mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 21:52:54 +00:00
# Which Problems Are Solved `IS NULL` and `IS NOT NULL` conditions were incorrectly marked as restricting columns, and currently fails unit tests. The restricting columns are mostly used to ensure single row selection during DELETE and UPDATE . When a `IS NOT NULL` condition is passed, the filter may (unintentionally) apply to all rows, while still allowing the query to execute. Settings and other repositories (still to be done) have unified tables for instance-level settings and organization-level settings. In those cases the organization ID may be null or have a value. The unique condition is a compound of multiple columns, in which case `IS NULL` is valid as part of the other restricting columns. # How the Problems Are Solved In order to prevent unsafe usage of null related filters and not break settings: - null conditions are no longer considered restricting columns - A function to force the restricting column state on a condition is provided - The settings unique condition function forces restricting column state on the returned condition. # Additional Changes - add `backend/v3` to the NX build. # Additional Context - [pipeline failures](https://github.com/zitadel/zitadel/actions/runs/19852295780/job/56881654340?pr=11115#step:13:3197) --------- Co-authored-by: Elio Bischof <[email protected]>
257 lines
6.7 KiB
Go
257 lines
6.7 KiB
Go
package database
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestWrite(t *testing.T) {
|
|
type want struct {
|
|
stmt string
|
|
args []any
|
|
}
|
|
for _, test := range []struct {
|
|
name string
|
|
cond Condition
|
|
want want
|
|
}{
|
|
{
|
|
name: "no and condition",
|
|
cond: And(),
|
|
want: want{
|
|
stmt: "",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "one and condition",
|
|
cond: And(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
),
|
|
want: want{
|
|
stmt: "table.column1 = other_table.column2",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "multiple and condition",
|
|
cond: And(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column3"), NewColumn("other_table", "column4")),
|
|
),
|
|
want: want{
|
|
stmt: "(table.column1 = other_table.column2 AND table.column3 = other_table.column4)",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "no or condition",
|
|
cond: Or(),
|
|
want: want{
|
|
stmt: "",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "one or condition",
|
|
cond: Or(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
),
|
|
want: want{
|
|
stmt: "table.column1 = other_table.column2",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "multiple or condition",
|
|
cond: Or(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column3"), NewColumn("other_table", "column4")),
|
|
),
|
|
want: want{
|
|
stmt: "(table.column1 = other_table.column2 OR table.column3 = other_table.column4)",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "is null condition",
|
|
cond: IsNull(NewColumn("table", "column1")),
|
|
want: want{
|
|
stmt: "table.column1 IS NULL",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "is not null condition",
|
|
cond: IsNotNull(NewColumn("table", "column1")),
|
|
want: want{
|
|
stmt: "table.column1 IS NOT NULL",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "text condition",
|
|
cond: NewTextCondition(NewColumn("table", "column1"), TextOperationEqual, "some text"),
|
|
want: want{
|
|
stmt: "table.column1 = $1",
|
|
args: []any{"some text"},
|
|
},
|
|
},
|
|
{
|
|
name: "text condition with ignore case",
|
|
cond: NewTextCondition(NewColumn("table", "column1"), TextOperationEqualIgnoreCase, "some text"),
|
|
want: want{
|
|
stmt: "LOWER(table.column1) = LOWER($1)",
|
|
args: []any{"some text"},
|
|
},
|
|
},
|
|
{
|
|
name: "text ignore case condition",
|
|
cond: NewTextIgnoreCaseCondition(NewColumn("table", "column1"), TextOperationNotEqual, "some TEXT"),
|
|
want: want{
|
|
stmt: "LOWER(table.column1) <> LOWER($1)",
|
|
args: []any{"some TEXT"},
|
|
},
|
|
},
|
|
{
|
|
name: "number condition",
|
|
cond: NewNumberCondition(NewColumn("table", "column1"), NumberOperationEqual, 42),
|
|
want: want{
|
|
stmt: "table.column1 = $1",
|
|
args: []any{42},
|
|
},
|
|
},
|
|
{
|
|
name: "boolean condition",
|
|
cond: NewBooleanCondition(NewColumn("table", "column1"), true),
|
|
want: want{
|
|
stmt: "table.column1 = $1",
|
|
args: []any{true},
|
|
},
|
|
},
|
|
{
|
|
name: "bytes condition",
|
|
cond: NewBytesCondition[[]byte](NewColumn("table", "column1"), BytesOperationEqual, []byte{0x01, 0x02, 0x03}),
|
|
want: want{
|
|
stmt: "table.column1 = $1",
|
|
args: []any{[]byte{0x01, 0x02, 0x03}},
|
|
},
|
|
},
|
|
{
|
|
name: "column condition",
|
|
cond: NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
want: want{
|
|
stmt: "table.column1 = other_table.column2",
|
|
args: nil,
|
|
},
|
|
},
|
|
{
|
|
name: "exists condition",
|
|
cond: Exists("table", And(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column3"), NewColumn("other_table", "column4")),
|
|
)),
|
|
want: want{
|
|
stmt: " EXISTS (SELECT 1 FROM table WHERE (table.column1 = other_table.column2 AND table.column3 = other_table.column4))",
|
|
args: nil,
|
|
},
|
|
},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
var builder StatementBuilder
|
|
test.cond.Write(&builder)
|
|
assert.Equal(t, test.want.stmt, builder.String())
|
|
require.Len(t, builder.Args(), len(test.want.args))
|
|
for i, arg := range test.want.args {
|
|
assert.Equal(t, arg, builder.Args()[i])
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsRestrictingColumn(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
arg Column
|
|
cond Condition
|
|
want bool
|
|
}{
|
|
{
|
|
name: "and with restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: And(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column3")),
|
|
),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "and without restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: And(
|
|
NewColumnCondition(NewColumn("table", "column2"), NewColumn("other_table", "column3")),
|
|
IsNull(NewColumn("table", "column4")),
|
|
IsNotNull(NewColumn("table", "column5")),
|
|
),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "or with restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: Or(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column3")),
|
|
),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "or without restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: Or(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column3")),
|
|
IsNotNull(NewColumn("table", "column4")),
|
|
IsNull(NewColumn("table", "column5")),
|
|
),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "is null never restricts",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: IsNull(NewColumn("table", "column1")),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "is not null never restricts",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: IsNotNull(NewColumn("table", "column1")),
|
|
want: false,
|
|
},
|
|
{
|
|
name: "exists with restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: Exists("table", And(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column2")),
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column3")),
|
|
)),
|
|
want: true,
|
|
},
|
|
{
|
|
name: "exists without restricting column",
|
|
arg: NewColumn("table", "column1"),
|
|
cond: Exists("table", Or(
|
|
NewColumnCondition(NewColumn("table", "column1"), NewColumn("other_table", "column3")),
|
|
IsNotNull(NewColumn("table", "column4")),
|
|
IsNull(NewColumn("table", "column5")),
|
|
)),
|
|
want: false,
|
|
},
|
|
} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
isRestricting := test.cond.IsRestrictingColumn(test.arg)
|
|
assert.Equal(t, test.want, isRestricting)
|
|
})
|
|
}
|
|
}
|