@supabase/pg-delta 1.0.0-alpha.10 → 1.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/declarative-export.js +12 -17
- package/dist/cli/commands/plan.js +10 -13
- package/dist/cli/commands/sync.js +8 -12
- package/dist/cli/utils/integrations.d.ts +30 -6
- package/dist/cli/utils/integrations.js +98 -6
- package/dist/core/change-utils.d.ts +9 -0
- package/dist/core/change-utils.js +71 -0
- package/dist/core/change.types.d.ts +22 -0
- package/dist/core/change.types.js +37 -1
- package/dist/core/depend.js +25 -0
- package/dist/core/export/file-mapper.d.ts +2 -2
- package/dist/core/integrations/filter/dsl.d.ts +78 -74
- package/dist/core/integrations/filter/dsl.js +127 -79
- package/dist/core/integrations/filter/flatten.d.ts +51 -0
- package/dist/core/integrations/filter/flatten.js +116 -0
- package/dist/core/integrations/integration-dsl.d.ts +17 -1
- package/dist/core/integrations/merge.d.ts +20 -0
- package/dist/core/integrations/merge.js +60 -0
- package/dist/core/integrations/serialize/dsl.d.ts +7 -4
- package/dist/core/integrations/serialize/dsl.js +2 -2
- package/dist/core/integrations/supabase.js +23 -8
- package/dist/core/objects/aggregate/changes/aggregate.types.d.ts +1 -0
- package/dist/core/objects/base.change.d.ts +10 -0
- package/dist/core/objects/base.change.js +10 -0
- package/dist/core/objects/base.model.d.ts +4 -1
- package/dist/core/objects/base.model.js +5 -2
- package/dist/core/objects/collation/changes/collation.types.d.ts +1 -0
- package/dist/core/objects/domain/changes/domain.create.d.ts +1 -1
- package/dist/core/objects/domain/changes/domain.create.js +7 -1
- package/dist/core/objects/domain/changes/domain.types.d.ts +1 -0
- package/dist/core/objects/event-trigger/changes/event-trigger.types.d.ts +1 -0
- package/dist/core/objects/extension/changes/extension.types.d.ts +1 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.d.ts +1 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.d.ts +1 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.d.ts +1 -0
- package/dist/core/objects/foreign-data-wrapper/server/changes/server.types.d.ts +1 -0
- package/dist/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.d.ts +1 -0
- package/dist/core/objects/index/changes/index.types.d.ts +1 -0
- package/dist/core/objects/language/changes/language.types.d.ts +1 -0
- package/dist/core/objects/materialized-view/changes/materialized-view.types.d.ts +1 -0
- package/dist/core/objects/procedure/changes/procedure.types.d.ts +1 -0
- package/dist/core/objects/publication/changes/publication.types.d.ts +1 -0
- package/dist/core/objects/rls-policy/changes/rls-policy.types.d.ts +1 -0
- package/dist/core/objects/role/changes/role.types.d.ts +1 -0
- package/dist/core/objects/rule/changes/rule.types.d.ts +1 -0
- package/dist/core/objects/schema/changes/schema.types.d.ts +1 -0
- package/dist/core/objects/sequence/changes/sequence.types.d.ts +1 -0
- package/dist/core/objects/subscription/changes/subscription.types.d.ts +1 -0
- package/dist/core/objects/table/changes/table.types.d.ts +1 -0
- package/dist/core/objects/trigger/changes/trigger.types.d.ts +1 -0
- package/dist/core/objects/type/composite-type/changes/composite-type.types.d.ts +1 -0
- package/dist/core/objects/type/enum/changes/enum.types.d.ts +1 -0
- package/dist/core/objects/type/range/changes/range.types.d.ts +1 -0
- package/dist/core/objects/type/type.types.d.ts +1 -0
- package/dist/core/objects/view/changes/view.types.d.ts +1 -0
- package/dist/core/objects/view/view.diff.js +24 -13
- package/dist/core/postgres-config.d.ts +2 -2
- package/dist/core/sort/custom-constraints.js +1 -1
- package/dist/core/sort/logical-sort.js +3 -24
- package/package.json +5 -1
- package/src/cli/commands/declarative-export.ts +19 -27
- package/src/cli/commands/plan.ts +14 -20
- package/src/cli/commands/sync.ts +8 -15
- package/src/cli/utils/integrations.test.ts +210 -3
- package/src/cli/utils/integrations.ts +134 -6
- package/src/core/catalog.snapshot.test.ts +11 -2
- package/src/core/change-utils.test.ts +61 -0
- package/src/core/change-utils.ts +73 -0
- package/src/core/change.types.ts +50 -0
- package/src/core/depend.ts +25 -0
- package/src/core/export/file-mapper.ts +7 -2
- package/src/core/integrations/filter/dsl.test.ts +299 -60
- package/src/core/integrations/filter/dsl.ts +208 -169
- package/src/core/integrations/filter/flatten.test.ts +282 -0
- package/src/core/integrations/filter/flatten.ts +150 -0
- package/src/core/integrations/integration-dsl.ts +17 -1
- package/src/core/integrations/merge.test.ts +128 -0
- package/src/core/integrations/merge.ts +72 -0
- package/src/core/integrations/serialize/dsl.test.ts +6 -6
- package/src/core/integrations/serialize/dsl.ts +7 -4
- package/src/core/integrations/supabase.ts +23 -8
- package/src/core/objects/aggregate/changes/aggregate.types.ts +1 -0
- package/src/core/objects/base.change.ts +10 -0
- package/src/core/objects/base.model.test.ts +43 -0
- package/src/core/objects/base.model.ts +5 -2
- package/src/core/objects/collation/changes/collation.types.ts +1 -0
- package/src/core/objects/domain/changes/domain.create.ts +17 -1
- package/src/core/objects/domain/changes/domain.types.ts +1 -0
- package/src/core/objects/event-trigger/changes/event-trigger.types.ts +1 -0
- package/src/core/objects/extension/changes/extension.types.ts +1 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +1 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +1 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +1 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +1 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +1 -0
- package/src/core/objects/index/changes/index.types.ts +1 -0
- package/src/core/objects/language/changes/language.types.ts +1 -0
- package/src/core/objects/materialized-view/changes/materialized-view.types.ts +1 -0
- package/src/core/objects/procedure/changes/procedure.types.ts +1 -0
- package/src/core/objects/publication/changes/publication.types.ts +1 -0
- package/src/core/objects/rls-policy/changes/rls-policy.types.ts +1 -0
- package/src/core/objects/role/changes/role.types.ts +1 -0
- package/src/core/objects/rule/changes/rule.types.ts +1 -0
- package/src/core/objects/schema/changes/schema.types.ts +1 -0
- package/src/core/objects/sequence/changes/sequence.types.ts +1 -0
- package/src/core/objects/subscription/changes/subscription.types.ts +1 -0
- package/src/core/objects/table/changes/table.types.ts +1 -0
- package/src/core/objects/trigger/changes/trigger.types.ts +1 -0
- package/src/core/objects/type/composite-type/changes/composite-type.types.ts +1 -0
- package/src/core/objects/type/enum/changes/enum.types.ts +1 -0
- package/src/core/objects/type/range/changes/range.types.ts +1 -0
- package/src/core/objects/type/type.types.ts +1 -0
- package/src/core/objects/view/changes/view.types.ts +1 -0
- package/src/core/objects/view/view.diff.test.ts +96 -0
- package/src/core/objects/view/view.diff.ts +30 -15
- package/src/core/postgres-config.ts +2 -2
- package/src/core/sort/custom-constraints.ts +1 -1
- package/src/core/sort/logical-sort.ts +3 -27
- package/src/typedoc.ts +248 -0
- package/dist/core/integrations/filter/extractors.d.ts +0 -12
- package/dist/core/integrations/filter/extractors.js +0 -178
- package/src/core/integrations/filter/extractors.test.ts +0 -244
- package/src/core/integrations/filter/extractors.ts +0 -187
|
@@ -6,15 +6,21 @@ const tableCreate = {
|
|
|
6
6
|
objectType: "table",
|
|
7
7
|
operation: "create",
|
|
8
8
|
scope: "object",
|
|
9
|
-
table: {
|
|
9
|
+
table: {
|
|
10
|
+
schema: "public",
|
|
11
|
+
name: "t",
|
|
12
|
+
owner: "postgres",
|
|
13
|
+
is_partition: false,
|
|
14
|
+
},
|
|
10
15
|
requires: ["schema:public"],
|
|
16
|
+
creates: ["table:public.t"],
|
|
11
17
|
} as unknown as Change;
|
|
12
18
|
|
|
13
19
|
const viewAlter = {
|
|
14
20
|
objectType: "view",
|
|
15
21
|
operation: "alter",
|
|
16
22
|
scope: "comment",
|
|
17
|
-
view: { schema: "private", name: "v" },
|
|
23
|
+
view: { schema: "private", name: "v", owner: "admin" },
|
|
18
24
|
requires: ["schema:private", "type:auth.users"],
|
|
19
25
|
} as unknown as Change;
|
|
20
26
|
|
|
@@ -26,14 +32,23 @@ const roleDrop = {
|
|
|
26
32
|
requires: [],
|
|
27
33
|
} as unknown as Change;
|
|
28
34
|
|
|
35
|
+
const membershipChange = {
|
|
36
|
+
objectType: "role",
|
|
37
|
+
operation: "create",
|
|
38
|
+
scope: "membership",
|
|
39
|
+
member: "app_user",
|
|
40
|
+
role: { name: "admin_group" },
|
|
41
|
+
requires: [],
|
|
42
|
+
} as unknown as Change;
|
|
43
|
+
|
|
29
44
|
describe("evaluatePattern", () => {
|
|
30
|
-
describe("
|
|
31
|
-
test("
|
|
32
|
-
expect(evaluatePattern({
|
|
45
|
+
describe("bare key matching (top-level properties)", () => {
|
|
46
|
+
test("objectType match", () => {
|
|
47
|
+
expect(evaluatePattern({ objectType: "table" }, tableCreate)).toBe(true);
|
|
33
48
|
});
|
|
34
49
|
|
|
35
|
-
test("
|
|
36
|
-
expect(evaluatePattern({
|
|
50
|
+
test("objectType mismatch", () => {
|
|
51
|
+
expect(evaluatePattern({ objectType: "view" }, tableCreate)).toBe(false);
|
|
37
52
|
});
|
|
38
53
|
|
|
39
54
|
test("operation match", () => {
|
|
@@ -52,12 +67,18 @@ describe("evaluatePattern", () => {
|
|
|
52
67
|
expect(evaluatePattern({ scope: "comment" }, tableCreate)).toBe(false);
|
|
53
68
|
});
|
|
54
69
|
|
|
55
|
-
test("multiple
|
|
70
|
+
test("multiple bare keys AND together", () => {
|
|
56
71
|
expect(
|
|
57
|
-
evaluatePattern(
|
|
72
|
+
evaluatePattern(
|
|
73
|
+
{ objectType: "table", operation: "create" },
|
|
74
|
+
tableCreate,
|
|
75
|
+
),
|
|
58
76
|
).toBe(true);
|
|
59
77
|
expect(
|
|
60
|
-
evaluatePattern(
|
|
78
|
+
evaluatePattern(
|
|
79
|
+
{ objectType: "table", operation: "drop" },
|
|
80
|
+
tableCreate,
|
|
81
|
+
),
|
|
61
82
|
).toBe(false);
|
|
62
83
|
});
|
|
63
84
|
|
|
@@ -67,124 +88,257 @@ describe("evaluatePattern", () => {
|
|
|
67
88
|
});
|
|
68
89
|
});
|
|
69
90
|
|
|
70
|
-
describe("
|
|
71
|
-
test("
|
|
72
|
-
expect(evaluatePattern({
|
|
91
|
+
describe("path key matching (model sub-object properties)", () => {
|
|
92
|
+
test("exact path match", () => {
|
|
93
|
+
expect(evaluatePattern({ "table/schema": "public" }, tableCreate)).toBe(
|
|
94
|
+
true,
|
|
95
|
+
);
|
|
96
|
+
expect(evaluatePattern({ "table/schema": "private" }, tableCreate)).toBe(
|
|
73
97
|
false,
|
|
74
98
|
);
|
|
75
|
-
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("path with array value checks inclusion", () => {
|
|
102
|
+
expect(
|
|
103
|
+
evaluatePattern({ "table/schema": ["public", "private"] }, tableCreate),
|
|
104
|
+
).toBe(true);
|
|
105
|
+
expect(
|
|
106
|
+
evaluatePattern({ "table/schema": ["private", "auth"] }, tableCreate),
|
|
107
|
+
).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("path not found returns false", () => {
|
|
111
|
+
expect(evaluatePattern({ "table/schema": "public" }, roleDrop)).toBe(
|
|
112
|
+
false,
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
describe("wildcard pattern matching", () => {
|
|
118
|
+
test("*/schema matches any objectType's schema", () => {
|
|
119
|
+
expect(evaluatePattern({ "*/schema": "public" }, tableCreate)).toBe(true);
|
|
120
|
+
expect(evaluatePattern({ "*/schema": "private" }, viewAlter)).toBe(true);
|
|
121
|
+
expect(evaluatePattern({ "*/schema": "public" }, viewAlter)).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("*/owner matches across object types", () => {
|
|
125
|
+
expect(evaluatePattern({ "*/owner": "postgres" }, tableCreate)).toBe(
|
|
76
126
|
true,
|
|
77
127
|
);
|
|
128
|
+
expect(evaluatePattern({ "*/owner": "admin" }, viewAlter)).toBe(true);
|
|
78
129
|
});
|
|
79
130
|
|
|
80
|
-
test("
|
|
131
|
+
test("*/schema does not match objectTypes without schema", () => {
|
|
132
|
+
expect(evaluatePattern({ "*/schema": "anything" }, roleDrop)).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("*/name matches role/name", () => {
|
|
136
|
+
expect(evaluatePattern({ "*/name": "admin" }, roleDrop)).toBe(true);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("wildcard with array value", () => {
|
|
81
140
|
expect(
|
|
82
|
-
evaluatePattern(
|
|
83
|
-
{ and: [{ type: "table" }, { operation: "create" }] },
|
|
84
|
-
tableCreate,
|
|
85
|
-
),
|
|
141
|
+
evaluatePattern({ "*/schema": ["public", "private"] }, tableCreate),
|
|
86
142
|
).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe("boolean matching", () => {
|
|
147
|
+
test("matches boolean value", () => {
|
|
87
148
|
expect(
|
|
88
|
-
evaluatePattern(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
)
|
|
149
|
+
evaluatePattern({ "table/is_partition": false }, tableCreate),
|
|
150
|
+
).toBe(true);
|
|
151
|
+
expect(evaluatePattern({ "table/is_partition": true }, tableCreate)).toBe(
|
|
152
|
+
false,
|
|
153
|
+
);
|
|
93
154
|
});
|
|
155
|
+
});
|
|
94
156
|
|
|
95
|
-
|
|
157
|
+
describe("regex matching", () => {
|
|
158
|
+
test("regex on string value", () => {
|
|
96
159
|
expect(
|
|
97
160
|
evaluatePattern(
|
|
98
|
-
{
|
|
161
|
+
{ "table/name": { op: "regex", value: "^t" } },
|
|
99
162
|
tableCreate,
|
|
100
163
|
),
|
|
101
164
|
).toBe(true);
|
|
102
165
|
expect(
|
|
103
166
|
evaluatePattern(
|
|
104
|
-
{
|
|
167
|
+
{ "table/name": { op: "regex", value: "^z" } },
|
|
105
168
|
tableCreate,
|
|
106
169
|
),
|
|
107
170
|
).toBe(false);
|
|
108
171
|
});
|
|
109
172
|
|
|
110
|
-
test("
|
|
173
|
+
test("regex with array of patterns", () => {
|
|
111
174
|
expect(
|
|
112
175
|
evaluatePattern(
|
|
113
|
-
{
|
|
176
|
+
{ "table/name": { op: "regex", value: ["^z", "^t"] } },
|
|
114
177
|
tableCreate,
|
|
115
178
|
),
|
|
116
179
|
).toBe(true);
|
|
117
180
|
});
|
|
118
|
-
});
|
|
119
181
|
|
|
120
|
-
|
|
121
|
-
test("prefix match on requires array", () => {
|
|
182
|
+
test("regex on array value (requires)", () => {
|
|
122
183
|
expect(
|
|
123
|
-
evaluatePattern(
|
|
184
|
+
evaluatePattern(
|
|
185
|
+
{ requires: { op: "regex", value: "^schema:" } },
|
|
186
|
+
tableCreate,
|
|
187
|
+
),
|
|
124
188
|
).toBe(true);
|
|
125
189
|
expect(
|
|
126
|
-
evaluatePattern(
|
|
190
|
+
evaluatePattern(
|
|
191
|
+
{ requires: { op: "regex", value: "^type:auth\\." } },
|
|
192
|
+
viewAlter,
|
|
193
|
+
),
|
|
127
194
|
).toBe(true);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("no match when prefix absent", () => {
|
|
131
195
|
expect(
|
|
132
|
-
evaluatePattern(
|
|
196
|
+
evaluatePattern(
|
|
197
|
+
{ requires: { op: "regex", value: "^type:auth\\." } },
|
|
198
|
+
tableCreate,
|
|
199
|
+
),
|
|
133
200
|
).toBe(false);
|
|
134
201
|
});
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
describe("array value matching (requires/creates)", () => {
|
|
205
|
+
test("string match against array checks any element", () => {
|
|
206
|
+
expect(evaluatePattern({ requires: "schema:public" }, tableCreate)).toBe(
|
|
207
|
+
true,
|
|
208
|
+
);
|
|
209
|
+
expect(evaluatePattern({ requires: "schema:private" }, tableCreate)).toBe(
|
|
210
|
+
false,
|
|
211
|
+
);
|
|
212
|
+
});
|
|
135
213
|
|
|
136
|
-
test("
|
|
214
|
+
test("array match against array checks intersection", () => {
|
|
137
215
|
expect(
|
|
138
|
-
evaluatePattern(
|
|
216
|
+
evaluatePattern(
|
|
217
|
+
{ requires: ["schema:public", "schema:other"] },
|
|
218
|
+
tableCreate,
|
|
219
|
+
),
|
|
139
220
|
).toBe(true);
|
|
140
221
|
});
|
|
141
222
|
|
|
142
|
-
test("no match
|
|
143
|
-
expect(evaluatePattern({
|
|
223
|
+
test("no match on empty requires", () => {
|
|
224
|
+
expect(evaluatePattern({ requires: "schema:public" }, roleDrop)).toBe(
|
|
225
|
+
false,
|
|
226
|
+
);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("member/grantee matching", () => {
|
|
231
|
+
test("member match", () => {
|
|
232
|
+
expect(evaluatePattern({ member: "app_user" }, membershipChange)).toBe(
|
|
233
|
+
true,
|
|
234
|
+
);
|
|
235
|
+
expect(evaluatePattern({ member: "other_user" }, membershipChange)).toBe(
|
|
144
236
|
false,
|
|
145
237
|
);
|
|
146
238
|
});
|
|
239
|
+
|
|
240
|
+
test("member not present returns false", () => {
|
|
241
|
+
expect(evaluatePattern({ member: "app_user" }, tableCreate)).toBe(false);
|
|
242
|
+
});
|
|
147
243
|
});
|
|
148
244
|
|
|
149
|
-
describe("
|
|
150
|
-
test("
|
|
151
|
-
expect(
|
|
152
|
-
|
|
245
|
+
describe("composition patterns", () => {
|
|
246
|
+
test("not negates a pattern", () => {
|
|
247
|
+
expect(
|
|
248
|
+
evaluatePattern({ not: { objectType: "table" } }, tableCreate),
|
|
249
|
+
).toBe(false);
|
|
250
|
+
expect(
|
|
251
|
+
evaluatePattern({ not: { objectType: "view" } }, tableCreate),
|
|
252
|
+
).toBe(true);
|
|
153
253
|
});
|
|
154
254
|
|
|
155
|
-
test("
|
|
255
|
+
test("and requires all to match", () => {
|
|
156
256
|
expect(
|
|
157
|
-
evaluatePattern(
|
|
257
|
+
evaluatePattern(
|
|
258
|
+
{ and: [{ objectType: "table" }, { operation: "create" }] },
|
|
259
|
+
tableCreate,
|
|
260
|
+
),
|
|
158
261
|
).toBe(true);
|
|
159
262
|
expect(
|
|
160
|
-
evaluatePattern(
|
|
263
|
+
evaluatePattern(
|
|
264
|
+
{ and: [{ objectType: "table" }, { operation: "drop" }] },
|
|
265
|
+
tableCreate,
|
|
266
|
+
),
|
|
161
267
|
).toBe(false);
|
|
162
268
|
});
|
|
163
269
|
|
|
164
|
-
test("
|
|
165
|
-
expect(
|
|
270
|
+
test("or requires any to match", () => {
|
|
271
|
+
expect(
|
|
272
|
+
evaluatePattern(
|
|
273
|
+
{ or: [{ objectType: "table" }, { objectType: "view" }] },
|
|
274
|
+
tableCreate,
|
|
275
|
+
),
|
|
276
|
+
).toBe(true);
|
|
277
|
+
expect(
|
|
278
|
+
evaluatePattern(
|
|
279
|
+
{ or: [{ objectType: "role" }, { objectType: "view" }] },
|
|
280
|
+
tableCreate,
|
|
281
|
+
),
|
|
282
|
+
).toBe(false);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("nested composition", () => {
|
|
286
|
+
expect(
|
|
287
|
+
evaluatePattern(
|
|
288
|
+
{ not: { or: [{ objectType: "role" }, { objectType: "view" }] } },
|
|
289
|
+
tableCreate,
|
|
290
|
+
),
|
|
291
|
+
).toBe(true);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("composition with wildcard patterns", () => {
|
|
295
|
+
expect(
|
|
296
|
+
evaluatePattern(
|
|
297
|
+
{ not: { "*/schema": ["auth", "extensions"] } },
|
|
298
|
+
tableCreate,
|
|
299
|
+
),
|
|
300
|
+
).toBe(true);
|
|
166
301
|
});
|
|
302
|
+
});
|
|
167
303
|
|
|
168
|
-
|
|
169
|
-
|
|
304
|
+
describe("combined path + bare keys", () => {
|
|
305
|
+
test("objectType and path key AND together", () => {
|
|
170
306
|
expect(
|
|
171
307
|
evaluatePattern(
|
|
172
|
-
|
|
308
|
+
{ objectType: "table", "table/is_partition": false },
|
|
173
309
|
tableCreate,
|
|
174
310
|
),
|
|
175
311
|
).toBe(true);
|
|
312
|
+
expect(
|
|
313
|
+
evaluatePattern(
|
|
314
|
+
{ objectType: "table", "table/is_partition": true },
|
|
315
|
+
tableCreate,
|
|
316
|
+
),
|
|
317
|
+
).toBe(false);
|
|
176
318
|
});
|
|
319
|
+
});
|
|
177
320
|
|
|
178
|
-
|
|
321
|
+
describe("cascade property", () => {
|
|
322
|
+
test("cascade is ignored and does not affect match", () => {
|
|
179
323
|
expect(
|
|
180
|
-
evaluatePattern(
|
|
324
|
+
evaluatePattern(
|
|
325
|
+
{ objectType: "table", cascade: true } as Parameters<
|
|
326
|
+
typeof evaluatePattern
|
|
327
|
+
>[0],
|
|
328
|
+
tableCreate,
|
|
329
|
+
),
|
|
181
330
|
).toBe(true);
|
|
182
331
|
expect(
|
|
183
|
-
evaluatePattern(
|
|
332
|
+
evaluatePattern(
|
|
333
|
+
{ objectType: "table", cascade: false } as Parameters<
|
|
334
|
+
typeof evaluatePattern
|
|
335
|
+
>[0],
|
|
336
|
+
tableCreate,
|
|
337
|
+
),
|
|
184
338
|
).toBe(true);
|
|
185
339
|
expect(
|
|
186
340
|
evaluatePattern(
|
|
187
|
-
{ not: { schema: "auth" }, cascade: true },
|
|
341
|
+
{ not: { "*/schema": "auth" }, cascade: true },
|
|
188
342
|
tableCreate,
|
|
189
343
|
),
|
|
190
344
|
).toBe(true);
|
|
@@ -194,7 +348,7 @@ describe("evaluatePattern", () => {
|
|
|
194
348
|
|
|
195
349
|
describe("compileFilterDSL", () => {
|
|
196
350
|
test("returns a function that evaluates the pattern", () => {
|
|
197
|
-
const filter = compileFilterDSL({
|
|
351
|
+
const filter = compileFilterDSL({ objectType: "table" });
|
|
198
352
|
expect(typeof filter).toBe("function");
|
|
199
353
|
expect(filter(tableCreate)).toBe(true);
|
|
200
354
|
expect(filter(roleDrop)).toBe(false);
|
|
@@ -202,10 +356,95 @@ describe("compileFilterDSL", () => {
|
|
|
202
356
|
|
|
203
357
|
test("works with composition patterns", () => {
|
|
204
358
|
const filter = compileFilterDSL({
|
|
205
|
-
or: [{
|
|
359
|
+
or: [{ objectType: "table" }, { objectType: "role" }],
|
|
206
360
|
});
|
|
207
361
|
expect(filter(tableCreate)).toBe(true);
|
|
208
362
|
expect(filter(roleDrop)).toBe(true);
|
|
209
363
|
expect(filter(viewAlter)).toBe(false);
|
|
210
364
|
});
|
|
365
|
+
|
|
366
|
+
test("works with wildcard-based patterns", () => {
|
|
367
|
+
const filter = compileFilterDSL({
|
|
368
|
+
"*/schema": "public",
|
|
369
|
+
});
|
|
370
|
+
expect(filter(tableCreate)).toBe(true);
|
|
371
|
+
expect(filter(viewAlter)).toBe(false);
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
test("throws on invalid regex pattern", () => {
|
|
375
|
+
expect(() =>
|
|
376
|
+
compileFilterDSL({
|
|
377
|
+
"table/name": { op: "regex", value: "[invalid" },
|
|
378
|
+
}),
|
|
379
|
+
).toThrow(/Invalid regex pattern "\[invalid" in filter DSL/);
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
test("throws on invalid regex in array of patterns", () => {
|
|
383
|
+
expect(() =>
|
|
384
|
+
compileFilterDSL({
|
|
385
|
+
"table/name": { op: "regex", value: ["^valid$", "(unclosed"] },
|
|
386
|
+
}),
|
|
387
|
+
).toThrow(/Invalid regex pattern "\(unclosed" in filter DSL/);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
test("throws on invalid regex nested in composition", () => {
|
|
391
|
+
expect(() =>
|
|
392
|
+
compileFilterDSL({
|
|
393
|
+
or: [
|
|
394
|
+
{ objectType: "table" },
|
|
395
|
+
{ "table/name": { op: "regex", value: "**bad" } },
|
|
396
|
+
],
|
|
397
|
+
}),
|
|
398
|
+
).toThrow(/Invalid regex pattern "\*\*bad" in filter DSL/);
|
|
399
|
+
});
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
describe("glob pattern features", () => {
|
|
403
|
+
const tableCreate = {
|
|
404
|
+
objectType: "table",
|
|
405
|
+
operation: "create",
|
|
406
|
+
scope: "object",
|
|
407
|
+
table: {
|
|
408
|
+
schema: "public",
|
|
409
|
+
name: "t",
|
|
410
|
+
owner: "postgres",
|
|
411
|
+
is_partition: false,
|
|
412
|
+
},
|
|
413
|
+
requires: ["schema:public"],
|
|
414
|
+
creates: ["table:public.t"],
|
|
415
|
+
} as unknown as Change;
|
|
416
|
+
|
|
417
|
+
const viewAlter = {
|
|
418
|
+
objectType: "view",
|
|
419
|
+
operation: "alter",
|
|
420
|
+
scope: "comment",
|
|
421
|
+
view: { schema: "private", name: "v", owner: "admin" },
|
|
422
|
+
requires: ["schema:private", "type:auth.users"],
|
|
423
|
+
} as unknown as Change;
|
|
424
|
+
|
|
425
|
+
const roleDrop = {
|
|
426
|
+
objectType: "role",
|
|
427
|
+
operation: "drop",
|
|
428
|
+
scope: "object",
|
|
429
|
+
role: { name: "admin" },
|
|
430
|
+
requires: [],
|
|
431
|
+
} as unknown as Change;
|
|
432
|
+
|
|
433
|
+
test("brace expansion in path pattern keys", () => {
|
|
434
|
+
const filter = compileFilterDSL({ "{table,view}/schema": "public" });
|
|
435
|
+
expect(filter(tableCreate)).toBe(true);
|
|
436
|
+
expect(filter(viewAlter)).toBe(false); // private, not public
|
|
437
|
+
expect(filter(roleDrop)).toBe(false); // no matching key
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
test("partial wildcard in field names", () => {
|
|
441
|
+
const filter = compileFilterDSL({ "table/is_*": false });
|
|
442
|
+
expect(filter(tableCreate)).toBe(true); // is_partition = false
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
test("extglob negation in pattern keys", () => {
|
|
446
|
+
const filter = compileFilterDSL({ "!(role)/schema": "public" });
|
|
447
|
+
expect(filter(tableCreate)).toBe(true); // table/schema = public
|
|
448
|
+
expect(filter(roleDrop)).toBe(false); // role excluded by negation
|
|
449
|
+
});
|
|
211
450
|
});
|