@contember/schema-migrations 2.2.0-alpha.11 → 2.2.0-alpha.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/schema-migrations",
3
- "version": "2.2.0-alpha.11",
3
+ "version": "2.2.0-alpha.12",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/production/index.js",
6
6
  "typings": "./dist/types/index.d.ts",
@@ -23,16 +23,16 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@contember/database": "2.2.0-alpha.11",
27
- "@contember/database-migrations": "2.2.0-alpha.11",
28
- "@contember/engine-common": "2.2.0-alpha.11",
29
- "@contember/schema": "2.2.0-alpha.11",
30
- "@contember/schema-utils": "2.2.0-alpha.11",
26
+ "@contember/database": "2.2.0-alpha.12",
27
+ "@contember/database-migrations": "2.2.0-alpha.12",
28
+ "@contember/engine-common": "2.2.0-alpha.12",
29
+ "@contember/schema": "2.2.0-alpha.12",
30
+ "@contember/schema-utils": "2.2.0-alpha.12",
31
31
  "fast-deep-equal": "^3.1.3",
32
32
  "rfc6902": "^5.2.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@contember/schema-definition": "2.2.0-alpha.11"
35
+ "@contember/schema-definition": "2.2.0-alpha.12"
36
36
  },
37
37
  "peerDependencies": {
38
38
  "pg": "^8.20.0"
@@ -92,29 +92,35 @@ type EntityAclFieldPermissionsUpdater = (
92
92
  entityName: string,
93
93
  operation: Acl.Operation,
94
94
  ) => Acl.FieldPermissions
95
- type EntityOperationHandler = {
96
- [K in keyof Required<Acl.EntityOperations>]: (
97
- value: Exclude<Acl.EntityOperations[K], undefined>,
98
- ) => Acl.EntityOperations[K]
99
- }
100
-
101
95
  export const updateAclFieldPermissions =
102
96
  (updater: EntityAclFieldPermissionsUpdater): AclEntityPermissionsUpdater => ({ entityPermissions, entityName }) => {
103
- const operations: Writable<Acl.EntityOperations> = {}
104
- const handlers: EntityOperationHandler = {
105
- create: value => updater(value, entityName, Acl.Operation.create),
106
- update: value => updater(value, entityName, Acl.Operation.update),
107
- read: value => updater(value, entityName, Acl.Operation.read),
108
- delete: value => value,
109
- customPrimary: value => value,
110
- refreshMaterializedView: value => value,
111
- noRoot: value => value,
97
+ const source = entityPermissions.operations
98
+ const updateFields = (value: Acl.FieldPermissions, operation: Acl.Operation) => updater(value, entityName, operation)
99
+ // Carry every key over untouched by default, then rewrite the ones holding field names. An
100
+ // operation key that is not handled here must survive rather than disappear - the previous
101
+ // allow-list shape silently dropped `refreshMaterializedView` on every field rename.
102
+ const operations: Writable<Acl.EntityOperations> = { ...source }
103
+ if (source.create !== undefined) {
104
+ operations.create = updateFields(source.create, Acl.Operation.create)
105
+ }
106
+ if (source.update !== undefined) {
107
+ operations.update = updateFields(source.update, Acl.Operation.update)
112
108
  }
113
- const types: (keyof Acl.EntityOperations)[] = ['create', 'update', 'read', 'delete', 'customPrimary', 'noRoot']
114
- for (const key of types) {
115
- if (key in entityPermissions.operations) {
116
- operations[key] = handlers[key](entityPermissions.operations[key] as any) as any
109
+ if (source.read !== undefined) {
110
+ operations.read = updateFields(source.read, Acl.Operation.read)
111
+ }
112
+ if (source.through !== undefined) {
113
+ const through: Writable<Acl.ThroughOperations> = { ...source.through }
114
+ if (source.through.create !== undefined) {
115
+ through.create = updateFields(source.through.create, Acl.Operation.create)
116
+ }
117
+ if (source.through.update !== undefined) {
118
+ through.update = updateFields(source.through.update, Acl.Operation.update)
119
+ }
120
+ if (source.through.read !== undefined) {
121
+ through.read = updateFields(source.through.read, Acl.Operation.read)
117
122
  }
123
+ operations.through = through
118
124
  }
119
125
 
120
126
  return {
@@ -264,3 +264,71 @@ describe('rename a field carrying per-column index options', () =>
264
264
  sql: SQL``,
265
265
  noDiff: true,
266
266
  }))
267
+
268
+ // A field rename has to reach into the `through` bucket as well, and must not drop operation keys it
269
+ // does not rewrite - the previous allow-list shape silently discarded `refreshMaterializedView`.
270
+ describe('rename a field referenced by a through grant', () =>
271
+ testMigrations({
272
+ original: {
273
+ model: new SchemaBuilder()
274
+ .entity('Post', e => e.column('title'))
275
+ .buildSchema(),
276
+ acl: {
277
+ roles: {
278
+ editor: {
279
+ variables: {},
280
+ stages: '*',
281
+ entities: {
282
+ Post: {
283
+ predicates: {},
284
+ operations: {
285
+ read: { title: true },
286
+ refreshMaterializedView: true,
287
+ through: {
288
+ read: { title: true },
289
+ update: { title: true },
290
+ },
291
+ },
292
+ },
293
+ },
294
+ },
295
+ },
296
+ },
297
+ },
298
+ updated: {
299
+ model: new SchemaBuilder()
300
+ .entity('Post', e => e.column('heading', c => c.type(Model.ColumnType.String).columnName('title')))
301
+ .buildSchema(),
302
+ acl: {
303
+ roles: {
304
+ editor: {
305
+ variables: {},
306
+ stages: '*',
307
+ entities: {
308
+ Post: {
309
+ predicates: {},
310
+ operations: {
311
+ read: { heading: true },
312
+ refreshMaterializedView: true,
313
+ through: {
314
+ read: { heading: true },
315
+ update: { heading: true },
316
+ },
317
+ },
318
+ },
319
+ },
320
+ },
321
+ },
322
+ },
323
+ },
324
+ diff: [
325
+ {
326
+ modification: 'updateFieldName',
327
+ entityName: 'Post',
328
+ fieldName: 'title',
329
+ newFieldName: 'heading',
330
+ },
331
+ ],
332
+ sql: SQL``,
333
+ noDiff: true,
334
+ }))