@contember/schema-migrations 2.2.0-alpha.7 → 2.2.0-alpha.8
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/development/src/modifications/acl/PatchAclSchemaModification.cjs +4 -6
- package/dist/development/src/modifications/acl/PatchAclSchemaModification.cjs.map +1 -1
- package/dist/development/src/modifications/acl/PatchAclSchemaModification.js +4 -6
- package/dist/development/src/modifications/acl/PatchAclSchemaModification.js.map +1 -1
- package/dist/development/src/modifications/columns/CreateColumnModification.cjs +2 -1
- package/dist/development/src/modifications/columns/CreateColumnModification.cjs.map +1 -1
- package/dist/development/src/modifications/columns/CreateColumnModification.js +2 -1
- package/dist/development/src/modifications/columns/CreateColumnModification.js.map +1 -1
- package/dist/development/src/utils/applyPatchCopyOnWrite.cjs +51 -0
- package/dist/development/src/utils/applyPatchCopyOnWrite.cjs.map +1 -0
- package/dist/development/src/utils/applyPatchCopyOnWrite.js +51 -0
- package/dist/development/src/utils/applyPatchCopyOnWrite.js.map +1 -0
- package/dist/production/src/modifications/acl/PatchAclSchemaModification.cjs +4 -6
- package/dist/production/src/modifications/acl/PatchAclSchemaModification.cjs.map +1 -1
- package/dist/production/src/modifications/acl/PatchAclSchemaModification.js +4 -6
- package/dist/production/src/modifications/acl/PatchAclSchemaModification.js.map +1 -1
- package/dist/production/src/modifications/columns/CreateColumnModification.cjs +2 -1
- package/dist/production/src/modifications/columns/CreateColumnModification.cjs.map +1 -1
- package/dist/production/src/modifications/columns/CreateColumnModification.js +2 -1
- package/dist/production/src/modifications/columns/CreateColumnModification.js.map +1 -1
- package/dist/production/src/utils/applyPatchCopyOnWrite.cjs +51 -0
- package/dist/production/src/utils/applyPatchCopyOnWrite.cjs.map +1 -0
- package/dist/production/src/utils/applyPatchCopyOnWrite.js +51 -0
- package/dist/production/src/utils/applyPatchCopyOnWrite.js.map +1 -0
- package/dist/tests/cases/unit/patchAclSchemaModification.test.d.ts +2 -0
- package/dist/tests/cases/unit/patchAclSchemaModification.test.d.ts.map +1 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/modifications/acl/PatchAclSchemaModification.d.ts.map +1 -1
- package/dist/types/modifications/columns/CreateColumnModification.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/types/utils/applyPatchCopyOnWrite.d.ts +10 -0
- package/dist/types/utils/applyPatchCopyOnWrite.d.ts.map +1 -0
- package/package.json +7 -7
- package/src/modifications/acl/PatchAclSchemaModification.ts +5 -6
- package/src/modifications/columns/CreateColumnModification.ts +2 -1
- package/src/utils/applyPatchCopyOnWrite.ts +63 -0
- package/tests/cases/integration/createColumn.test.ts +28 -0
- package/tests/cases/unit/patchAclSchemaModification.test.ts +144 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const ModificationHandler = require("../ModificationHandler.cjs");
|
|
4
|
-
const
|
|
5
|
-
const deepCopy = require("../../utils/deepCopy.cjs");
|
|
4
|
+
const applyPatchCopyOnWrite = require("../../utils/applyPatchCopyOnWrite.cjs");
|
|
6
5
|
class PatchAclSchemaModificationHandler {
|
|
7
6
|
constructor(data) {
|
|
8
7
|
this.data = data;
|
|
@@ -11,10 +10,9 @@ class PatchAclSchemaModificationHandler {
|
|
|
11
10
|
}
|
|
12
11
|
getSchemaUpdater() {
|
|
13
12
|
return ({ schema }) => {
|
|
14
|
-
const acl =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
throw result[0];
|
|
13
|
+
const { result: acl, errors } = applyPatchCopyOnWrite.applyPatchCopyOnWrite(schema.acl, this.data.patch);
|
|
14
|
+
if (errors.length > 0) {
|
|
15
|
+
throw errors[0];
|
|
18
16
|
}
|
|
19
17
|
return {
|
|
20
18
|
...schema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PatchAclSchemaModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport {
|
|
1
|
+
{"version":3,"file":"PatchAclSchemaModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport { Operation } from 'rfc6902'\nimport { applyPatchCopyOnWrite } from '../../utils/applyPatchCopyOnWrite.js'\n\nexport class PatchAclSchemaModificationHandler implements ModificationHandler<PatchAclSchemaModificationData> {\n\tconstructor(private readonly data: PatchAclSchemaModificationData) {}\n\n\tpublic createSql(): void {}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn ({ schema }) => {\n\t\t\tconst { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch)\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow errors[0]\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...schema,\n\t\t\t\tacl,\n\t\t\t}\n\t\t}\n\t}\n\n\tdescribe() {\n\t\treturn { message: 'Update ACL schema' }\n\t}\n}\n\nexport const patchAclSchemaModification = createModificationType({\n\tid: 'patchAclSchema',\n\thandler: PatchAclSchemaModificationHandler,\n})\n\nexport interface PatchAclSchemaModificationData {\n\tpatch: Operation[]\n}\n"],"names":["applyPatchCopyOnWrite","createModificationType"],"mappings":";;;;AAKO,MAAM,kCAAiG;AAAA,EAC7G,YAA6B,MAAsC;AAAtC,SAAA,OAAA;AAAA,EAAuC;AAAA,EAE7D,YAAkB;AAAA,EAAC;AAAA,EAEnB,mBAAkC;AACxC,WAAO,CAAC,EAAE,aAAa;AACtB,YAAM,EAAE,QAAQ,KAAK,WAAWA,sBAAAA,sBAAsB,OAAO,KAAK,KAAK,KAAK,KAAK;AACjF,UAAI,OAAO,SAAS,GAAG;AACtB,cAAM,OAAO,CAAC;AAAA,MACf;AAEA,aAAO;AAAA,QACN,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AAAA,EAEA,WAAW;AACV,WAAO,EAAE,SAAS,oBAAA;AAAA,EACnB;AACD;AAEO,MAAM,6BAA6BC,oBAAAA,uBAAuB;AAAA,EAChE,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;;;"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createModificationType } from "../ModificationHandler.js";
|
|
2
|
-
import {
|
|
3
|
-
import deepCopy from "../../utils/deepCopy.js";
|
|
2
|
+
import { applyPatchCopyOnWrite } from "../../utils/applyPatchCopyOnWrite.js";
|
|
4
3
|
class PatchAclSchemaModificationHandler {
|
|
5
4
|
constructor(data) {
|
|
6
5
|
this.data = data;
|
|
@@ -9,10 +8,9 @@ class PatchAclSchemaModificationHandler {
|
|
|
9
8
|
}
|
|
10
9
|
getSchemaUpdater() {
|
|
11
10
|
return ({ schema }) => {
|
|
12
|
-
const acl =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
throw result[0];
|
|
11
|
+
const { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch);
|
|
12
|
+
if (errors.length > 0) {
|
|
13
|
+
throw errors[0];
|
|
16
14
|
}
|
|
17
15
|
return {
|
|
18
16
|
...schema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PatchAclSchemaModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport {
|
|
1
|
+
{"version":3,"file":"PatchAclSchemaModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport { Operation } from 'rfc6902'\nimport { applyPatchCopyOnWrite } from '../../utils/applyPatchCopyOnWrite.js'\n\nexport class PatchAclSchemaModificationHandler implements ModificationHandler<PatchAclSchemaModificationData> {\n\tconstructor(private readonly data: PatchAclSchemaModificationData) {}\n\n\tpublic createSql(): void {}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn ({ schema }) => {\n\t\t\tconst { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch)\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow errors[0]\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...schema,\n\t\t\t\tacl,\n\t\t\t}\n\t\t}\n\t}\n\n\tdescribe() {\n\t\treturn { message: 'Update ACL schema' }\n\t}\n}\n\nexport const patchAclSchemaModification = createModificationType({\n\tid: 'patchAclSchema',\n\thandler: PatchAclSchemaModificationHandler,\n})\n\nexport interface PatchAclSchemaModificationData {\n\tpatch: Operation[]\n}\n"],"names":[],"mappings":";;AAKO,MAAM,kCAAiG;AAAA,EAC7G,YAA6B,MAAsC;AAAtC,SAAA,OAAA;AAAA,EAAuC;AAAA,EAE7D,YAAkB;AAAA,EAAC;AAAA,EAEnB,mBAAkC;AACxC,WAAO,CAAC,EAAE,aAAa;AACtB,YAAM,EAAE,QAAQ,KAAK,WAAW,sBAAsB,OAAO,KAAK,KAAK,KAAK,KAAK;AACjF,UAAI,OAAO,SAAS,GAAG;AACtB,cAAM,OAAO,CAAC;AAAA,MACf;AAEA,aAAO;AAAA,QACN,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AAAA,EAEA,WAAW;AACV,WAAO,EAAE,SAAS,oBAAA;AAAA,EACnB;AACD;AAEO,MAAM,6BAA6B,uBAAuB;AAAA,EAChE,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;"}
|
|
@@ -6,6 +6,7 @@ const schemaUtils = require("@contember/schema-utils");
|
|
|
6
6
|
const diffUtils = require("../utils/diffUtils.cjs");
|
|
7
7
|
const columnUtils = require("../utils/columnUtils.cjs");
|
|
8
8
|
const columnUtils$1 = require("./columnUtils.cjs");
|
|
9
|
+
const dbHelpers = require("../../utils/dbHelpers.cjs");
|
|
9
10
|
class CreateColumnModificationHandler {
|
|
10
11
|
constructor(data, schema) {
|
|
11
12
|
this.data = data;
|
|
@@ -30,7 +31,7 @@ class CreateColumnModificationHandler {
|
|
|
30
31
|
type: columnType,
|
|
31
32
|
notNull: !column.nullable && seedExpression === null,
|
|
32
33
|
sequenceGenerated: column.sequence,
|
|
33
|
-
collation: column.collation
|
|
34
|
+
collation: column.collation !== void 0 ? dbHelpers.wrapIdentifier(column.collation) : void 0
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
if (seedExpression !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateColumnModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":["getColumnSqlType","formatSeedExpression","fillSeed","updateModel","updateEntity","addField","createModificationType","createFields","isColumn"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateColumnModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\nimport { wrapIdentifier } from '../../utils/dbHelpers.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation !== undefined ? wrapIdentifier(column.collation) : undefined,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":["getColumnSqlType","formatSeedExpression","wrapIdentifier","fillSeed","updateModel","updateEntity","addField","createModificationType","createFields","isColumn"],"mappings":";;;;;;;;;AAUO,MAAM,gCAA6F;AAAA,EACzG,YAA6B,MAAqD,QAAgB;AAArE,SAAA,OAAA;AAAqD,SAAA,SAAA;AAAA,EAAiB;AAAA,EAE5F,UAAU,SAAiC;AACjD,UAAM,SAAS,KAAK,OAAO,MAAM,SAAS,KAAK,KAAK,UAAU;AAC9D,QAAI,OAAO,MAAM;AAChB;AAAA,IACD;AACA,UAAM,SAAS,KAAK,KAAK;AAEzB,UAAM,aAAaA,YAAAA,iBAAiB,MAAM;AAE1C,UAAM,iBAAiBC,cAAAA,qBAAqB;AAAA,MAC3C,OAAO,KAAK,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,KAAK;AAAA,MACrB,WAAW,KAAK,KAAK;AAAA,IAAA,CACrB;AAED,YAAQ,UAAU,OAAO,WAAW;AAAA,MACnC,CAAC,OAAO,UAAU,GAAG;AAAA,QACpB,MAAM;AAAA,QACN,SAAS,CAAC,OAAO,YAAY,mBAAmB;AAAA,QAChD,mBAAmB,OAAO;AAAA,QAC1B,WAAW,OAAO,cAAc,SAAYC,UAAAA,eAAe,OAAO,SAAS,IAAI;AAAA,MAAA;AAAA,IAChF,CACA;AAED,QAAI,mBAAmB,MAAM;AAC5B,UAAI,KAAK,KAAK,2BAA2B,SAAS;AACjD,gBAAQ,YAAY,OAAO,WAAW,OAAO,YAAY;AAAA,UACxD,SAAS,CAAC,OAAO,WAAW,OAAO;AAAA,UACnC,MAAM;AAAA,UACN,OAAO;AAAA,QAAA,CACP;AAAA,MACF,OAAO;AACNC,+BAAS;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB;AAAA,QAAA,CACA;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEO,mBAAkC;AACxC,WAAOC,8BAAYC,kBAAAA,aAAa,KAAK,KAAK,YAAYC,kBAAAA,SAAS,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,EACjF;AAAA,EAEA,SAAS,EAAE,mBAAkD;AAC5D,UAAM,UAAU,CAAC,KAAK,KAAK,MAAM;AACjC,UAAM,WAAW,KAAK,KAAK,cAAc,UAAa,KAAK,KAAK,cAAc;AAC9E,UAAM,iBAAiB,WAAW,CAAC,YAAY,CAAC,gBAAgB,SAAS,KAAK,KAAK,UAAU,IAC1F,6FACA;AACH,WAAO,EAAE,SAAS,aAAa,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,eAAA;AAAA,EAChF;AACD;AAUO,MAAM,2BAA2BC,oBAAAA,uBAAuB;AAAA,EAC9D,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;AAEM,MAAM,mBAAqC;AAAA,EACjD,WAAW,gBAAwB,eAAuB;AACzD,WAAOC,UAAAA,aAAa,gBAAgB,eAAe,CAAC,EAAE,UAAU,oBAAoB;AACnF,UAAI,CAACC,YAAAA,SAAS,QAAQ,GAAG;AACxB,eAAO;AAAA,MACR;AACA,aAAO,yBAAyB,mBAAmB;AAAA,QAClD,YAAY,cAAc;AAAA,QAC1B,OAAO;AAAA,QACP,GAAI,SAAS,YAAY,SAAY,EAAE,WAAW,SAAS,SAAS,wBAAwB,YAAY,CAAA;AAAA,MAAC,CACzG;AAAA,IACF,CAAC;AAAA,EACF;AACD;;;;"}
|
|
@@ -4,6 +4,7 @@ import { isColumn } from "@contember/schema-utils";
|
|
|
4
4
|
import { createFields } from "../utils/diffUtils.js";
|
|
5
5
|
import { getColumnSqlType } from "../utils/columnUtils.js";
|
|
6
6
|
import { formatSeedExpression, fillSeed } from "./columnUtils.js";
|
|
7
|
+
import { wrapIdentifier } from "../../utils/dbHelpers.js";
|
|
7
8
|
class CreateColumnModificationHandler {
|
|
8
9
|
constructor(data, schema) {
|
|
9
10
|
this.data = data;
|
|
@@ -28,7 +29,7 @@ class CreateColumnModificationHandler {
|
|
|
28
29
|
type: columnType,
|
|
29
30
|
notNull: !column.nullable && seedExpression === null,
|
|
30
31
|
sequenceGenerated: column.sequence,
|
|
31
|
-
collation: column.collation
|
|
32
|
+
collation: column.collation !== void 0 ? wrapIdentifier(column.collation) : void 0
|
|
32
33
|
}
|
|
33
34
|
});
|
|
34
35
|
if (seedExpression !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateColumnModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateColumnModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\nimport { wrapIdentifier } from '../../utils/dbHelpers.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation !== undefined ? wrapIdentifier(column.collation) : undefined,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":[],"mappings":";;;;;;;AAUO,MAAM,gCAA6F;AAAA,EACzG,YAA6B,MAAqD,QAAgB;AAArE,SAAA,OAAA;AAAqD,SAAA,SAAA;AAAA,EAAiB;AAAA,EAE5F,UAAU,SAAiC;AACjD,UAAM,SAAS,KAAK,OAAO,MAAM,SAAS,KAAK,KAAK,UAAU;AAC9D,QAAI,OAAO,MAAM;AAChB;AAAA,IACD;AACA,UAAM,SAAS,KAAK,KAAK;AAEzB,UAAM,aAAa,iBAAiB,MAAM;AAE1C,UAAM,iBAAiB,qBAAqB;AAAA,MAC3C,OAAO,KAAK,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,KAAK;AAAA,MACrB,WAAW,KAAK,KAAK;AAAA,IAAA,CACrB;AAED,YAAQ,UAAU,OAAO,WAAW;AAAA,MACnC,CAAC,OAAO,UAAU,GAAG;AAAA,QACpB,MAAM;AAAA,QACN,SAAS,CAAC,OAAO,YAAY,mBAAmB;AAAA,QAChD,mBAAmB,OAAO;AAAA,QAC1B,WAAW,OAAO,cAAc,SAAY,eAAe,OAAO,SAAS,IAAI;AAAA,MAAA;AAAA,IAChF,CACA;AAED,QAAI,mBAAmB,MAAM;AAC5B,UAAI,KAAK,KAAK,2BAA2B,SAAS;AACjD,gBAAQ,YAAY,OAAO,WAAW,OAAO,YAAY;AAAA,UACxD,SAAS,CAAC,OAAO,WAAW,OAAO;AAAA,UACnC,MAAM;AAAA,UACN,OAAO;AAAA,QAAA,CACP;AAAA,MACF,OAAO;AACN,iBAAS;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB;AAAA,QAAA,CACA;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEO,mBAAkC;AACxC,WAAO,YAAY,aAAa,KAAK,KAAK,YAAY,SAAS,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,EACjF;AAAA,EAEA,SAAS,EAAE,mBAAkD;AAC5D,UAAM,UAAU,CAAC,KAAK,KAAK,MAAM;AACjC,UAAM,WAAW,KAAK,KAAK,cAAc,UAAa,KAAK,KAAK,cAAc;AAC9E,UAAM,iBAAiB,WAAW,CAAC,YAAY,CAAC,gBAAgB,SAAS,KAAK,KAAK,UAAU,IAC1F,6FACA;AACH,WAAO,EAAE,SAAS,aAAa,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,eAAA;AAAA,EAChF;AACD;AAUO,MAAM,2BAA2B,uBAAuB;AAAA,EAC9D,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;AAEM,MAAM,mBAAqC;AAAA,EACjD,WAAW,gBAAwB,eAAuB;AACzD,WAAO,aAAa,gBAAgB,eAAe,CAAC,EAAE,UAAU,oBAAoB;AACnF,UAAI,CAAC,SAAS,QAAQ,GAAG;AACxB,eAAO;AAAA,MACR;AACA,aAAO,yBAAyB,mBAAmB;AAAA,QAClD,YAAY,cAAc;AAAA,QAC1B,OAAO;AAAA,QACP,GAAI,SAAS,YAAY,SAAY,EAAE,WAAW,SAAS,SAAS,wBAAwB,YAAY,CAAA;AAAA,MAAC,CACzG;AAAA,IACF,CAAC;AAAA,EACF;AACD;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const rfc6902 = require("rfc6902");
|
|
4
|
+
const skippedTokens = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
5
|
+
const isContainer = (value) => typeof value === "object" && value !== null;
|
|
6
|
+
const shallowCopy = (value) => Array.isArray(value) ? [...value] : { ...value };
|
|
7
|
+
const getMutatedPointers = (operation) => {
|
|
8
|
+
switch (operation.op) {
|
|
9
|
+
case "test":
|
|
10
|
+
return [];
|
|
11
|
+
case "move":
|
|
12
|
+
return [operation.from, operation.path];
|
|
13
|
+
default:
|
|
14
|
+
return [operation.path];
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const applyPatchCopyOnWrite = (root, patch) => {
|
|
18
|
+
const result = { ...root };
|
|
19
|
+
const copies = /* @__PURE__ */ new Set([result]);
|
|
20
|
+
const errors = [];
|
|
21
|
+
for (const operation of patch) {
|
|
22
|
+
for (const pointer of getMutatedPointers(operation)) {
|
|
23
|
+
copyParents(result, pointer, copies);
|
|
24
|
+
}
|
|
25
|
+
for (const error of rfc6902.applyPatch(result, [operation])) {
|
|
26
|
+
if (error !== null) {
|
|
27
|
+
errors.push(error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { result, errors };
|
|
32
|
+
};
|
|
33
|
+
const copyParents = (root, pointer, copies) => {
|
|
34
|
+
const tokens = rfc6902.Pointer.fromJSON(pointer).tokens.slice(1);
|
|
35
|
+
const lastToken = tokens.at(-1);
|
|
36
|
+
const writtenTokens = lastToken !== void 0 && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1);
|
|
37
|
+
const parentTokens = writtenTokens.filter((token) => !skippedTokens.has(token));
|
|
38
|
+
let node = root;
|
|
39
|
+
for (const token of parentTokens) {
|
|
40
|
+
const child = Reflect.get(node, token);
|
|
41
|
+
if (!isContainer(child)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const childCopy = copies.has(child) ? child : shallowCopy(child);
|
|
45
|
+
copies.add(childCopy);
|
|
46
|
+
Reflect.set(node, token, childCopy);
|
|
47
|
+
node = childCopy;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.applyPatchCopyOnWrite = applyPatchCopyOnWrite;
|
|
51
|
+
//# sourceMappingURL=applyPatchCopyOnWrite.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyPatchCopyOnWrite.cjs","sources":["../../../../../packages/schema-migrations/src/utils/applyPatchCopyOnWrite.ts"],"sourcesContent":["import { applyPatch, Operation, Pointer } from 'rfc6902'\n\ntype JsonContainer = { [key: string]: unknown } | unknown[]\n\n// Pointer.evaluate in rfc6902 skips these tokens, so the copy walk must skip them too.\nconst skippedTokens = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isContainer = (value: unknown): value is JsonContainer => typeof value === 'object' && value !== null\n\nconst shallowCopy = (value: JsonContainer): JsonContainer => Array.isArray(value) ? [...value] : { ...value }\n\nconst getMutatedPointers = (operation: Operation): string[] => {\n\tswitch (operation.op) {\n\t\tcase 'test':\n\t\t\treturn []\n\t\tcase 'move':\n\t\t\treturn [operation.from, operation.path]\n\t\tdefault:\n\t\t\treturn [operation.path]\n\t}\n}\n\n/**\n * Applies the patch to a copy of `root`, leaving `root` untouched. Only the containers on the paths\n * the patch writes to are copied; everything else stays shared with `root`.\n */\nexport const applyPatchCopyOnWrite = <T extends object>(root: T, patch: Operation[]): { result: T; errors: Error[] } => {\n\tconst result = { ...root }\n\tconst copies = new Set<unknown>([result])\n\tconst errors: Error[] = []\n\tfor (const operation of patch) {\n\t\t// Each path is copied against the tree as the previous operations left it: array indices shift\n\t\t// and `move` relocates an uncopied original, so a path resolved up front can miss the target.\n\t\tfor (const pointer of getMutatedPointers(operation)) {\n\t\t\tcopyParents(result, pointer, copies)\n\t\t}\n\t\tfor (const error of applyPatch(result, [operation])) {\n\t\t\tif (error !== null) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\t}\n\treturn { result, errors }\n}\n\nconst copyParents = (root: object, pointer: string, copies: Set<unknown>): void => {\n\tconst tokens = Pointer.fromJSON(pointer).tokens.slice(1)\n\t// rfc6902 writes into the node reached before the last token, unless that token is skipped.\n\tconst lastToken = tokens.at(-1)\n\tconst writtenTokens = lastToken !== undefined && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1)\n\tconst parentTokens = writtenTokens.filter(token => !skippedTokens.has(token))\n\tlet node: object = root\n\tfor (const token of parentTokens) {\n\t\tconst child: unknown = Reflect.get(node, token)\n\t\tif (!isContainer(child)) {\n\t\t\treturn\n\t\t}\n\t\tconst childCopy = copies.has(child) ? child : shallowCopy(child)\n\t\tcopies.add(childCopy)\n\t\tReflect.set(node, token, childCopy)\n\t\tnode = childCopy\n\t}\n}\n"],"names":["applyPatch","Pointer"],"mappings":";;;AAKA,MAAM,gBAAgB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AAEvE,MAAM,cAAc,CAAC,UAA2C,OAAO,UAAU,YAAY,UAAU;AAEvG,MAAM,cAAc,CAAC,UAAwC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,MAAA;AAEtG,MAAM,qBAAqB,CAAC,cAAmC;AAC9D,UAAQ,UAAU,IAAA;AAAA,IACjB,KAAK;AACJ,aAAO,CAAA;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,UAAU,MAAM,UAAU,IAAI;AAAA,IACvC;AACC,aAAO,CAAC,UAAU,IAAI;AAAA,EAAA;AAEzB;AAMO,MAAM,wBAAwB,CAAmB,MAAS,UAAuD;AACvH,QAAM,SAAS,EAAE,GAAG,KAAA;AACpB,QAAM,SAAS,oBAAI,IAAa,CAAC,MAAM,CAAC;AACxC,QAAM,SAAkB,CAAA;AACxB,aAAW,aAAa,OAAO;AAG9B,eAAW,WAAW,mBAAmB,SAAS,GAAG;AACpD,kBAAY,QAAQ,SAAS,MAAM;AAAA,IACpC;AACA,eAAW,SAASA,QAAAA,WAAW,QAAQ,CAAC,SAAS,CAAC,GAAG;AACpD,UAAI,UAAU,MAAM;AACnB,eAAO,KAAK,KAAK;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AACA,SAAO,EAAE,QAAQ,OAAA;AAClB;AAEA,MAAM,cAAc,CAAC,MAAc,SAAiB,WAA+B;AAClF,QAAM,SAASC,QAAAA,QAAQ,SAAS,OAAO,EAAE,OAAO,MAAM,CAAC;AAEvD,QAAM,YAAY,OAAO,GAAG,EAAE;AAC9B,QAAM,gBAAgB,cAAc,UAAa,cAAc,IAAI,SAAS,IAAI,SAAS,OAAO,MAAM,GAAG,EAAE;AAC3G,QAAM,eAAe,cAAc,OAAO,CAAA,UAAS,CAAC,cAAc,IAAI,KAAK,CAAC;AAC5E,MAAI,OAAe;AACnB,aAAW,SAAS,cAAc;AACjC,UAAM,QAAiB,QAAQ,IAAI,MAAM,KAAK;AAC9C,QAAI,CAAC,YAAY,KAAK,GAAG;AACxB;AAAA,IACD;AACA,UAAM,YAAY,OAAO,IAAI,KAAK,IAAI,QAAQ,YAAY,KAAK;AAC/D,WAAO,IAAI,SAAS;AACpB,YAAQ,IAAI,MAAM,OAAO,SAAS;AAClC,WAAO;AAAA,EACR;AACD;;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { applyPatch, Pointer } from "rfc6902";
|
|
2
|
+
const skippedTokens = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3
|
+
const isContainer = (value) => typeof value === "object" && value !== null;
|
|
4
|
+
const shallowCopy = (value) => Array.isArray(value) ? [...value] : { ...value };
|
|
5
|
+
const getMutatedPointers = (operation) => {
|
|
6
|
+
switch (operation.op) {
|
|
7
|
+
case "test":
|
|
8
|
+
return [];
|
|
9
|
+
case "move":
|
|
10
|
+
return [operation.from, operation.path];
|
|
11
|
+
default:
|
|
12
|
+
return [operation.path];
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const applyPatchCopyOnWrite = (root, patch) => {
|
|
16
|
+
const result = { ...root };
|
|
17
|
+
const copies = /* @__PURE__ */ new Set([result]);
|
|
18
|
+
const errors = [];
|
|
19
|
+
for (const operation of patch) {
|
|
20
|
+
for (const pointer of getMutatedPointers(operation)) {
|
|
21
|
+
copyParents(result, pointer, copies);
|
|
22
|
+
}
|
|
23
|
+
for (const error of applyPatch(result, [operation])) {
|
|
24
|
+
if (error !== null) {
|
|
25
|
+
errors.push(error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { result, errors };
|
|
30
|
+
};
|
|
31
|
+
const copyParents = (root, pointer, copies) => {
|
|
32
|
+
const tokens = Pointer.fromJSON(pointer).tokens.slice(1);
|
|
33
|
+
const lastToken = tokens.at(-1);
|
|
34
|
+
const writtenTokens = lastToken !== void 0 && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1);
|
|
35
|
+
const parentTokens = writtenTokens.filter((token) => !skippedTokens.has(token));
|
|
36
|
+
let node = root;
|
|
37
|
+
for (const token of parentTokens) {
|
|
38
|
+
const child = Reflect.get(node, token);
|
|
39
|
+
if (!isContainer(child)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const childCopy = copies.has(child) ? child : shallowCopy(child);
|
|
43
|
+
copies.add(childCopy);
|
|
44
|
+
Reflect.set(node, token, childCopy);
|
|
45
|
+
node = childCopy;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
applyPatchCopyOnWrite
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=applyPatchCopyOnWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyPatchCopyOnWrite.js","sources":["../../../../../packages/schema-migrations/src/utils/applyPatchCopyOnWrite.ts"],"sourcesContent":["import { applyPatch, Operation, Pointer } from 'rfc6902'\n\ntype JsonContainer = { [key: string]: unknown } | unknown[]\n\n// Pointer.evaluate in rfc6902 skips these tokens, so the copy walk must skip them too.\nconst skippedTokens = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isContainer = (value: unknown): value is JsonContainer => typeof value === 'object' && value !== null\n\nconst shallowCopy = (value: JsonContainer): JsonContainer => Array.isArray(value) ? [...value] : { ...value }\n\nconst getMutatedPointers = (operation: Operation): string[] => {\n\tswitch (operation.op) {\n\t\tcase 'test':\n\t\t\treturn []\n\t\tcase 'move':\n\t\t\treturn [operation.from, operation.path]\n\t\tdefault:\n\t\t\treturn [operation.path]\n\t}\n}\n\n/**\n * Applies the patch to a copy of `root`, leaving `root` untouched. Only the containers on the paths\n * the patch writes to are copied; everything else stays shared with `root`.\n */\nexport const applyPatchCopyOnWrite = <T extends object>(root: T, patch: Operation[]): { result: T; errors: Error[] } => {\n\tconst result = { ...root }\n\tconst copies = new Set<unknown>([result])\n\tconst errors: Error[] = []\n\tfor (const operation of patch) {\n\t\t// Each path is copied against the tree as the previous operations left it: array indices shift\n\t\t// and `move` relocates an uncopied original, so a path resolved up front can miss the target.\n\t\tfor (const pointer of getMutatedPointers(operation)) {\n\t\t\tcopyParents(result, pointer, copies)\n\t\t}\n\t\tfor (const error of applyPatch(result, [operation])) {\n\t\t\tif (error !== null) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\t}\n\treturn { result, errors }\n}\n\nconst copyParents = (root: object, pointer: string, copies: Set<unknown>): void => {\n\tconst tokens = Pointer.fromJSON(pointer).tokens.slice(1)\n\t// rfc6902 writes into the node reached before the last token, unless that token is skipped.\n\tconst lastToken = tokens.at(-1)\n\tconst writtenTokens = lastToken !== undefined && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1)\n\tconst parentTokens = writtenTokens.filter(token => !skippedTokens.has(token))\n\tlet node: object = root\n\tfor (const token of parentTokens) {\n\t\tconst child: unknown = Reflect.get(node, token)\n\t\tif (!isContainer(child)) {\n\t\t\treturn\n\t\t}\n\t\tconst childCopy = copies.has(child) ? child : shallowCopy(child)\n\t\tcopies.add(childCopy)\n\t\tReflect.set(node, token, childCopy)\n\t\tnode = childCopy\n\t}\n}\n"],"names":[],"mappings":";AAKA,MAAM,gBAAgB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AAEvE,MAAM,cAAc,CAAC,UAA2C,OAAO,UAAU,YAAY,UAAU;AAEvG,MAAM,cAAc,CAAC,UAAwC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,MAAA;AAEtG,MAAM,qBAAqB,CAAC,cAAmC;AAC9D,UAAQ,UAAU,IAAA;AAAA,IACjB,KAAK;AACJ,aAAO,CAAA;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,UAAU,MAAM,UAAU,IAAI;AAAA,IACvC;AACC,aAAO,CAAC,UAAU,IAAI;AAAA,EAAA;AAEzB;AAMO,MAAM,wBAAwB,CAAmB,MAAS,UAAuD;AACvH,QAAM,SAAS,EAAE,GAAG,KAAA;AACpB,QAAM,SAAS,oBAAI,IAAa,CAAC,MAAM,CAAC;AACxC,QAAM,SAAkB,CAAA;AACxB,aAAW,aAAa,OAAO;AAG9B,eAAW,WAAW,mBAAmB,SAAS,GAAG;AACpD,kBAAY,QAAQ,SAAS,MAAM;AAAA,IACpC;AACA,eAAW,SAAS,WAAW,QAAQ,CAAC,SAAS,CAAC,GAAG;AACpD,UAAI,UAAU,MAAM;AACnB,eAAO,KAAK,KAAK;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AACA,SAAO,EAAE,QAAQ,OAAA;AAClB;AAEA,MAAM,cAAc,CAAC,MAAc,SAAiB,WAA+B;AAClF,QAAM,SAAS,QAAQ,SAAS,OAAO,EAAE,OAAO,MAAM,CAAC;AAEvD,QAAM,YAAY,OAAO,GAAG,EAAE;AAC9B,QAAM,gBAAgB,cAAc,UAAa,cAAc,IAAI,SAAS,IAAI,SAAS,OAAO,MAAM,GAAG,EAAE;AAC3G,QAAM,eAAe,cAAc,OAAO,CAAA,UAAS,CAAC,cAAc,IAAI,KAAK,CAAC;AAC5E,MAAI,OAAe;AACnB,aAAW,SAAS,cAAc;AACjC,UAAM,QAAiB,QAAQ,IAAI,MAAM,KAAK;AAC9C,QAAI,CAAC,YAAY,KAAK,GAAG;AACxB;AAAA,IACD;AACA,UAAM,YAAY,OAAO,IAAI,KAAK,IAAI,QAAQ,YAAY,KAAK;AAC/D,WAAO,IAAI,SAAS;AACpB,YAAQ,IAAI,MAAM,OAAO,SAAS;AAClC,WAAO;AAAA,EACR;AACD;"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const ModificationHandler = require("../ModificationHandler.cjs");
|
|
4
|
-
const
|
|
5
|
-
const deepCopy = require("../../utils/deepCopy.cjs");
|
|
4
|
+
const applyPatchCopyOnWrite = require("../../utils/applyPatchCopyOnWrite.cjs");
|
|
6
5
|
class PatchAclSchemaModificationHandler {
|
|
7
6
|
constructor(data) {
|
|
8
7
|
this.data = data;
|
|
@@ -11,10 +10,9 @@ class PatchAclSchemaModificationHandler {
|
|
|
11
10
|
}
|
|
12
11
|
getSchemaUpdater() {
|
|
13
12
|
return ({ schema }) => {
|
|
14
|
-
const acl =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
throw result[0];
|
|
13
|
+
const { result: acl, errors } = applyPatchCopyOnWrite.applyPatchCopyOnWrite(schema.acl, this.data.patch);
|
|
14
|
+
if (errors.length > 0) {
|
|
15
|
+
throw errors[0];
|
|
18
16
|
}
|
|
19
17
|
return {
|
|
20
18
|
...schema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PatchAclSchemaModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport {
|
|
1
|
+
{"version":3,"file":"PatchAclSchemaModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport { Operation } from 'rfc6902'\nimport { applyPatchCopyOnWrite } from '../../utils/applyPatchCopyOnWrite.js'\n\nexport class PatchAclSchemaModificationHandler implements ModificationHandler<PatchAclSchemaModificationData> {\n\tconstructor(private readonly data: PatchAclSchemaModificationData) {}\n\n\tpublic createSql(): void {}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn ({ schema }) => {\n\t\t\tconst { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch)\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow errors[0]\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...schema,\n\t\t\t\tacl,\n\t\t\t}\n\t\t}\n\t}\n\n\tdescribe() {\n\t\treturn { message: 'Update ACL schema' }\n\t}\n}\n\nexport const patchAclSchemaModification = createModificationType({\n\tid: 'patchAclSchema',\n\thandler: PatchAclSchemaModificationHandler,\n})\n\nexport interface PatchAclSchemaModificationData {\n\tpatch: Operation[]\n}\n"],"names":["applyPatchCopyOnWrite","createModificationType"],"mappings":";;;;AAKO,MAAM,kCAAiG;AAAA,EAC7G,YAA6B,MAAsC;AAAtC,SAAA,OAAA;AAAA,EAAuC;AAAA,EAE7D,YAAkB;AAAA,EAAC;AAAA,EAEnB,mBAAkC;AACxC,WAAO,CAAC,EAAE,aAAa;AACtB,YAAM,EAAE,QAAQ,KAAK,WAAWA,sBAAAA,sBAAsB,OAAO,KAAK,KAAK,KAAK,KAAK;AACjF,UAAI,OAAO,SAAS,GAAG;AACtB,cAAM,OAAO,CAAC;AAAA,MACf;AAEA,aAAO;AAAA,QACN,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AAAA,EAEA,WAAW;AACV,WAAO,EAAE,SAAS,oBAAA;AAAA,EACnB;AACD;AAEO,MAAM,6BAA6BC,oBAAAA,uBAAuB;AAAA,EAChE,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;;;"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createModificationType } from "../ModificationHandler.js";
|
|
2
|
-
import {
|
|
3
|
-
import deepCopy from "../../utils/deepCopy.js";
|
|
2
|
+
import { applyPatchCopyOnWrite } from "../../utils/applyPatchCopyOnWrite.js";
|
|
4
3
|
class PatchAclSchemaModificationHandler {
|
|
5
4
|
constructor(data) {
|
|
6
5
|
this.data = data;
|
|
@@ -9,10 +8,9 @@ class PatchAclSchemaModificationHandler {
|
|
|
9
8
|
}
|
|
10
9
|
getSchemaUpdater() {
|
|
11
10
|
return ({ schema }) => {
|
|
12
|
-
const acl =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
throw result[0];
|
|
11
|
+
const { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch);
|
|
12
|
+
if (errors.length > 0) {
|
|
13
|
+
throw errors[0];
|
|
16
14
|
}
|
|
17
15
|
return {
|
|
18
16
|
...schema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PatchAclSchemaModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport {
|
|
1
|
+
{"version":3,"file":"PatchAclSchemaModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/acl/PatchAclSchemaModification.ts"],"sourcesContent":["import { SchemaUpdater } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, ModificationHandler } from '../ModificationHandler.js'\nimport { Operation } from 'rfc6902'\nimport { applyPatchCopyOnWrite } from '../../utils/applyPatchCopyOnWrite.js'\n\nexport class PatchAclSchemaModificationHandler implements ModificationHandler<PatchAclSchemaModificationData> {\n\tconstructor(private readonly data: PatchAclSchemaModificationData) {}\n\n\tpublic createSql(): void {}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn ({ schema }) => {\n\t\t\tconst { result: acl, errors } = applyPatchCopyOnWrite(schema.acl, this.data.patch)\n\t\t\tif (errors.length > 0) {\n\t\t\t\tthrow errors[0]\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...schema,\n\t\t\t\tacl,\n\t\t\t}\n\t\t}\n\t}\n\n\tdescribe() {\n\t\treturn { message: 'Update ACL schema' }\n\t}\n}\n\nexport const patchAclSchemaModification = createModificationType({\n\tid: 'patchAclSchema',\n\thandler: PatchAclSchemaModificationHandler,\n})\n\nexport interface PatchAclSchemaModificationData {\n\tpatch: Operation[]\n}\n"],"names":[],"mappings":";;AAKO,MAAM,kCAAiG;AAAA,EAC7G,YAA6B,MAAsC;AAAtC,SAAA,OAAA;AAAA,EAAuC;AAAA,EAE7D,YAAkB;AAAA,EAAC;AAAA,EAEnB,mBAAkC;AACxC,WAAO,CAAC,EAAE,aAAa;AACtB,YAAM,EAAE,QAAQ,KAAK,WAAW,sBAAsB,OAAO,KAAK,KAAK,KAAK,KAAK;AACjF,UAAI,OAAO,SAAS,GAAG;AACtB,cAAM,OAAO,CAAC;AAAA,MACf;AAEA,aAAO;AAAA,QACN,GAAG;AAAA,QACH;AAAA,MAAA;AAAA,IAEF;AAAA,EACD;AAAA,EAEA,WAAW;AACV,WAAO,EAAE,SAAS,oBAAA;AAAA,EACnB;AACD;AAEO,MAAM,6BAA6B,uBAAuB;AAAA,EAChE,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;"}
|
|
@@ -6,6 +6,7 @@ const schemaUtils = require("@contember/schema-utils");
|
|
|
6
6
|
const diffUtils = require("../utils/diffUtils.cjs");
|
|
7
7
|
const columnUtils = require("../utils/columnUtils.cjs");
|
|
8
8
|
const columnUtils$1 = require("./columnUtils.cjs");
|
|
9
|
+
const dbHelpers = require("../../utils/dbHelpers.cjs");
|
|
9
10
|
class CreateColumnModificationHandler {
|
|
10
11
|
constructor(data, schema) {
|
|
11
12
|
this.data = data;
|
|
@@ -30,7 +31,7 @@ class CreateColumnModificationHandler {
|
|
|
30
31
|
type: columnType,
|
|
31
32
|
notNull: !column.nullable && seedExpression === null,
|
|
32
33
|
sequenceGenerated: column.sequence,
|
|
33
|
-
collation: column.collation
|
|
34
|
+
collation: column.collation !== void 0 ? dbHelpers.wrapIdentifier(column.collation) : void 0
|
|
34
35
|
}
|
|
35
36
|
});
|
|
36
37
|
if (seedExpression !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateColumnModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":["getColumnSqlType","formatSeedExpression","fillSeed","updateModel","updateEntity","addField","createModificationType","createFields","isColumn"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateColumnModification.cjs","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\nimport { wrapIdentifier } from '../../utils/dbHelpers.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation !== undefined ? wrapIdentifier(column.collation) : undefined,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":["getColumnSqlType","formatSeedExpression","wrapIdentifier","fillSeed","updateModel","updateEntity","addField","createModificationType","createFields","isColumn"],"mappings":";;;;;;;;;AAUO,MAAM,gCAA6F;AAAA,EACzG,YAA6B,MAAqD,QAAgB;AAArE,SAAA,OAAA;AAAqD,SAAA,SAAA;AAAA,EAAiB;AAAA,EAE5F,UAAU,SAAiC;AACjD,UAAM,SAAS,KAAK,OAAO,MAAM,SAAS,KAAK,KAAK,UAAU;AAC9D,QAAI,OAAO,MAAM;AAChB;AAAA,IACD;AACA,UAAM,SAAS,KAAK,KAAK;AAEzB,UAAM,aAAaA,YAAAA,iBAAiB,MAAM;AAE1C,UAAM,iBAAiBC,cAAAA,qBAAqB;AAAA,MAC3C,OAAO,KAAK,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,KAAK;AAAA,MACrB,WAAW,KAAK,KAAK;AAAA,IAAA,CACrB;AAED,YAAQ,UAAU,OAAO,WAAW;AAAA,MACnC,CAAC,OAAO,UAAU,GAAG;AAAA,QACpB,MAAM;AAAA,QACN,SAAS,CAAC,OAAO,YAAY,mBAAmB;AAAA,QAChD,mBAAmB,OAAO;AAAA,QAC1B,WAAW,OAAO,cAAc,SAAYC,UAAAA,eAAe,OAAO,SAAS,IAAI;AAAA,MAAA;AAAA,IAChF,CACA;AAED,QAAI,mBAAmB,MAAM;AAC5B,UAAI,KAAK,KAAK,2BAA2B,SAAS;AACjD,gBAAQ,YAAY,OAAO,WAAW,OAAO,YAAY;AAAA,UACxD,SAAS,CAAC,OAAO,WAAW,OAAO;AAAA,UACnC,MAAM;AAAA,UACN,OAAO;AAAA,QAAA,CACP;AAAA,MACF,OAAO;AACNC,+BAAS;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB;AAAA,QAAA,CACA;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEO,mBAAkC;AACxC,WAAOC,8BAAYC,kBAAAA,aAAa,KAAK,KAAK,YAAYC,kBAAAA,SAAS,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,EACjF;AAAA,EAEA,SAAS,EAAE,mBAAkD;AAC5D,UAAM,UAAU,CAAC,KAAK,KAAK,MAAM;AACjC,UAAM,WAAW,KAAK,KAAK,cAAc,UAAa,KAAK,KAAK,cAAc;AAC9E,UAAM,iBAAiB,WAAW,CAAC,YAAY,CAAC,gBAAgB,SAAS,KAAK,KAAK,UAAU,IAC1F,6FACA;AACH,WAAO,EAAE,SAAS,aAAa,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,eAAA;AAAA,EAChF;AACD;AAUO,MAAM,2BAA2BC,oBAAAA,uBAAuB;AAAA,EAC9D,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;AAEM,MAAM,mBAAqC;AAAA,EACjD,WAAW,gBAAwB,eAAuB;AACzD,WAAOC,UAAAA,aAAa,gBAAgB,eAAe,CAAC,EAAE,UAAU,oBAAoB;AACnF,UAAI,CAACC,YAAAA,SAAS,QAAQ,GAAG;AACxB,eAAO;AAAA,MACR;AACA,aAAO,yBAAyB,mBAAmB;AAAA,QAClD,YAAY,cAAc;AAAA,QAC1B,OAAO;AAAA,QACP,GAAI,SAAS,YAAY,SAAY,EAAE,WAAW,SAAS,SAAS,wBAAwB,YAAY,CAAA;AAAA,MAAC,CACzG;AAAA,IACF,CAAC;AAAA,EACF;AACD;;;;"}
|
|
@@ -4,6 +4,7 @@ import { isColumn } from "@contember/schema-utils";
|
|
|
4
4
|
import { createFields } from "../utils/diffUtils.js";
|
|
5
5
|
import { getColumnSqlType } from "../utils/columnUtils.js";
|
|
6
6
|
import { formatSeedExpression, fillSeed } from "./columnUtils.js";
|
|
7
|
+
import { wrapIdentifier } from "../../utils/dbHelpers.js";
|
|
7
8
|
class CreateColumnModificationHandler {
|
|
8
9
|
constructor(data, schema) {
|
|
9
10
|
this.data = data;
|
|
@@ -28,7 +29,7 @@ class CreateColumnModificationHandler {
|
|
|
28
29
|
type: columnType,
|
|
29
30
|
notNull: !column.nullable && seedExpression === null,
|
|
30
31
|
sequenceGenerated: column.sequence,
|
|
31
|
-
collation: column.collation
|
|
32
|
+
collation: column.collation !== void 0 ? wrapIdentifier(column.collation) : void 0
|
|
32
33
|
}
|
|
33
34
|
});
|
|
34
35
|
if (seedExpression !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateColumnModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateColumnModification.js","sources":["../../../../../../packages/schema-migrations/src/modifications/columns/CreateColumnModification.ts"],"sourcesContent":["import { MigrationBuilder } from '@contember/database-migrations'\nimport { JSONValue, Model, Schema } from '@contember/schema'\nimport { addField, SchemaUpdater, updateEntity, updateModel } from '../utils/schemaUpdateUtils.js'\nimport { createModificationType, Differ, ModificationHandler } from '../ModificationHandler.js'\nimport { isColumn } from '@contember/schema-utils'\nimport { createFields } from '../utils/diffUtils.js'\nimport { getColumnSqlType } from '../utils/columnUtils.js'\nimport { fillSeed, formatSeedExpression } from './columnUtils.js'\nimport { wrapIdentifier } from '../../utils/dbHelpers.js'\n\nexport class CreateColumnModificationHandler implements ModificationHandler<CreateColumnModificationData> {\n\tconstructor(private readonly data: CreateColumnModificationData, private readonly schema: Schema) {}\n\n\tpublic createSql(builder: MigrationBuilder): void {\n\t\tconst entity = this.schema.model.entities[this.data.entityName]\n\t\tif (entity.view) {\n\t\t\treturn\n\t\t}\n\t\tconst column = this.data.field\n\n\t\tconst columnType = getColumnSqlType(column)\n\n\t\tconst seedExpression = formatSeedExpression({\n\t\t\tmodel: this.schema.model,\n\t\t\tentity,\n\t\t\tcolumnType,\n\t\t\tfillValue: this.data.fillValue,\n\t\t\tcopyValue: this.data.copyValue,\n\t\t})\n\n\t\tbuilder.addColumn(entity.tableName, {\n\t\t\t[column.columnName]: {\n\t\t\t\ttype: columnType,\n\t\t\t\tnotNull: !column.nullable && seedExpression === null,\n\t\t\t\tsequenceGenerated: column.sequence,\n\t\t\t\tcollation: column.collation !== undefined ? wrapIdentifier(column.collation) : undefined,\n\t\t\t},\n\t\t})\n\n\t\tif (seedExpression !== null) {\n\t\t\tif (this.data.valueMigrationStrategy === 'using') {\n\t\t\t\tbuilder.alterColumn(entity.tableName, column.columnName, {\n\t\t\t\t\tnotNull: !column.nullable ? true : undefined,\n\t\t\t\t\ttype: columnType,\n\t\t\t\t\tusing: seedExpression,\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tfillSeed({\n\t\t\t\t\tbuilder,\n\t\t\t\t\ttype: 'creating',\n\t\t\t\t\tentity,\n\t\t\t\t\tcolumnName: column.columnName,\n\t\t\t\t\tnullable: column.nullable,\n\t\t\t\t\tseedExpression,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSchemaUpdater(): SchemaUpdater {\n\t\treturn updateModel(updateEntity(this.data.entityName, addField(this.data.field)))\n\t}\n\n\tdescribe({ createdEntities }: { createdEntities: string[] }) {\n\t\tconst notNull = !this.data.field.nullable\n\t\tconst hasValue = this.data.fillValue !== undefined || this.data.copyValue !== undefined\n\t\tconst failureWarning = notNull && !hasValue && !createdEntities.includes(this.data.entityName)\n\t\t\t? 'May fail in runtime, because column is not-null. Consider setting fillValue or copyValue'\n\t\t\t: undefined\n\t\treturn { message: `Add field ${this.data.entityName}.${this.data.field.name}`, failureWarning }\n\t}\n}\n\nexport interface CreateColumnModificationData {\n\tentityName: string\n\tfield: Model.AnyColumn\n\tfillValue?: JSONValue\n\tcopyValue?: string\n\tvalueMigrationStrategy?: 'using' | 'update'\n}\n\nexport const createColumnModification = createModificationType({\n\tid: 'createColumn',\n\thandler: CreateColumnModificationHandler,\n})\n\nexport class CreateColumnDiffer implements Differ {\n\tcreateDiff(originalSchema: Schema, updatedSchema: Schema) {\n\t\treturn createFields(originalSchema, updatedSchema, ({ newField, updatedEntity }) => {\n\t\t\tif (!isColumn(newField)) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\treturn createColumnModification.createModification({\n\t\t\t\tentityName: updatedEntity.name,\n\t\t\t\tfield: newField,\n\t\t\t\t...(newField.default !== undefined ? { fillValue: newField.default, valueMigrationStrategy: 'using' } : {}),\n\t\t\t})\n\t\t})\n\t}\n}\n"],"names":[],"mappings":";;;;;;;AAUO,MAAM,gCAA6F;AAAA,EACzG,YAA6B,MAAqD,QAAgB;AAArE,SAAA,OAAA;AAAqD,SAAA,SAAA;AAAA,EAAiB;AAAA,EAE5F,UAAU,SAAiC;AACjD,UAAM,SAAS,KAAK,OAAO,MAAM,SAAS,KAAK,KAAK,UAAU;AAC9D,QAAI,OAAO,MAAM;AAChB;AAAA,IACD;AACA,UAAM,SAAS,KAAK,KAAK;AAEzB,UAAM,aAAa,iBAAiB,MAAM;AAE1C,UAAM,iBAAiB,qBAAqB;AAAA,MAC3C,OAAO,KAAK,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,KAAK;AAAA,MACrB,WAAW,KAAK,KAAK;AAAA,IAAA,CACrB;AAED,YAAQ,UAAU,OAAO,WAAW;AAAA,MACnC,CAAC,OAAO,UAAU,GAAG;AAAA,QACpB,MAAM;AAAA,QACN,SAAS,CAAC,OAAO,YAAY,mBAAmB;AAAA,QAChD,mBAAmB,OAAO;AAAA,QAC1B,WAAW,OAAO,cAAc,SAAY,eAAe,OAAO,SAAS,IAAI;AAAA,MAAA;AAAA,IAChF,CACA;AAED,QAAI,mBAAmB,MAAM;AAC5B,UAAI,KAAK,KAAK,2BAA2B,SAAS;AACjD,gBAAQ,YAAY,OAAO,WAAW,OAAO,YAAY;AAAA,UACxD,SAAS,CAAC,OAAO,WAAW,OAAO;AAAA,UACnC,MAAM;AAAA,UACN,OAAO;AAAA,QAAA,CACP;AAAA,MACF,OAAO;AACN,iBAAS;AAAA,UACR;AAAA,UACA,MAAM;AAAA,UACN;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,UAAU,OAAO;AAAA,UACjB;AAAA,QAAA,CACA;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAEO,mBAAkC;AACxC,WAAO,YAAY,aAAa,KAAK,KAAK,YAAY,SAAS,KAAK,KAAK,KAAK,CAAC,CAAC;AAAA,EACjF;AAAA,EAEA,SAAS,EAAE,mBAAkD;AAC5D,UAAM,UAAU,CAAC,KAAK,KAAK,MAAM;AACjC,UAAM,WAAW,KAAK,KAAK,cAAc,UAAa,KAAK,KAAK,cAAc;AAC9E,UAAM,iBAAiB,WAAW,CAAC,YAAY,CAAC,gBAAgB,SAAS,KAAK,KAAK,UAAU,IAC1F,6FACA;AACH,WAAO,EAAE,SAAS,aAAa,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,MAAM,IAAI,IAAI,eAAA;AAAA,EAChF;AACD;AAUO,MAAM,2BAA2B,uBAAuB;AAAA,EAC9D,IAAI;AAAA,EACJ,SAAS;AACV,CAAC;AAEM,MAAM,mBAAqC;AAAA,EACjD,WAAW,gBAAwB,eAAuB;AACzD,WAAO,aAAa,gBAAgB,eAAe,CAAC,EAAE,UAAU,oBAAoB;AACnF,UAAI,CAAC,SAAS,QAAQ,GAAG;AACxB,eAAO;AAAA,MACR;AACA,aAAO,yBAAyB,mBAAmB;AAAA,QAClD,YAAY,cAAc;AAAA,QAC1B,OAAO;AAAA,QACP,GAAI,SAAS,YAAY,SAAY,EAAE,WAAW,SAAS,SAAS,wBAAwB,YAAY,CAAA;AAAA,MAAC,CACzG;AAAA,IACF,CAAC;AAAA,EACF;AACD;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const rfc6902 = require("rfc6902");
|
|
4
|
+
const skippedTokens = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
5
|
+
const isContainer = (value) => typeof value === "object" && value !== null;
|
|
6
|
+
const shallowCopy = (value) => Array.isArray(value) ? [...value] : { ...value };
|
|
7
|
+
const getMutatedPointers = (operation) => {
|
|
8
|
+
switch (operation.op) {
|
|
9
|
+
case "test":
|
|
10
|
+
return [];
|
|
11
|
+
case "move":
|
|
12
|
+
return [operation.from, operation.path];
|
|
13
|
+
default:
|
|
14
|
+
return [operation.path];
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
const applyPatchCopyOnWrite = (root, patch) => {
|
|
18
|
+
const result = { ...root };
|
|
19
|
+
const copies = /* @__PURE__ */ new Set([result]);
|
|
20
|
+
const errors = [];
|
|
21
|
+
for (const operation of patch) {
|
|
22
|
+
for (const pointer of getMutatedPointers(operation)) {
|
|
23
|
+
copyParents(result, pointer, copies);
|
|
24
|
+
}
|
|
25
|
+
for (const error of rfc6902.applyPatch(result, [operation])) {
|
|
26
|
+
if (error !== null) {
|
|
27
|
+
errors.push(error);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { result, errors };
|
|
32
|
+
};
|
|
33
|
+
const copyParents = (root, pointer, copies) => {
|
|
34
|
+
const tokens = rfc6902.Pointer.fromJSON(pointer).tokens.slice(1);
|
|
35
|
+
const lastToken = tokens.at(-1);
|
|
36
|
+
const writtenTokens = lastToken !== void 0 && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1);
|
|
37
|
+
const parentTokens = writtenTokens.filter((token) => !skippedTokens.has(token));
|
|
38
|
+
let node = root;
|
|
39
|
+
for (const token of parentTokens) {
|
|
40
|
+
const child = Reflect.get(node, token);
|
|
41
|
+
if (!isContainer(child)) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const childCopy = copies.has(child) ? child : shallowCopy(child);
|
|
45
|
+
copies.add(childCopy);
|
|
46
|
+
Reflect.set(node, token, childCopy);
|
|
47
|
+
node = childCopy;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
exports.applyPatchCopyOnWrite = applyPatchCopyOnWrite;
|
|
51
|
+
//# sourceMappingURL=applyPatchCopyOnWrite.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyPatchCopyOnWrite.cjs","sources":["../../../../../packages/schema-migrations/src/utils/applyPatchCopyOnWrite.ts"],"sourcesContent":["import { applyPatch, Operation, Pointer } from 'rfc6902'\n\ntype JsonContainer = { [key: string]: unknown } | unknown[]\n\n// Pointer.evaluate in rfc6902 skips these tokens, so the copy walk must skip them too.\nconst skippedTokens = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isContainer = (value: unknown): value is JsonContainer => typeof value === 'object' && value !== null\n\nconst shallowCopy = (value: JsonContainer): JsonContainer => Array.isArray(value) ? [...value] : { ...value }\n\nconst getMutatedPointers = (operation: Operation): string[] => {\n\tswitch (operation.op) {\n\t\tcase 'test':\n\t\t\treturn []\n\t\tcase 'move':\n\t\t\treturn [operation.from, operation.path]\n\t\tdefault:\n\t\t\treturn [operation.path]\n\t}\n}\n\n/**\n * Applies the patch to a copy of `root`, leaving `root` untouched. Only the containers on the paths\n * the patch writes to are copied; everything else stays shared with `root`.\n */\nexport const applyPatchCopyOnWrite = <T extends object>(root: T, patch: Operation[]): { result: T; errors: Error[] } => {\n\tconst result = { ...root }\n\tconst copies = new Set<unknown>([result])\n\tconst errors: Error[] = []\n\tfor (const operation of patch) {\n\t\t// Each path is copied against the tree as the previous operations left it: array indices shift\n\t\t// and `move` relocates an uncopied original, so a path resolved up front can miss the target.\n\t\tfor (const pointer of getMutatedPointers(operation)) {\n\t\t\tcopyParents(result, pointer, copies)\n\t\t}\n\t\tfor (const error of applyPatch(result, [operation])) {\n\t\t\tif (error !== null) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\t}\n\treturn { result, errors }\n}\n\nconst copyParents = (root: object, pointer: string, copies: Set<unknown>): void => {\n\tconst tokens = Pointer.fromJSON(pointer).tokens.slice(1)\n\t// rfc6902 writes into the node reached before the last token, unless that token is skipped.\n\tconst lastToken = tokens.at(-1)\n\tconst writtenTokens = lastToken !== undefined && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1)\n\tconst parentTokens = writtenTokens.filter(token => !skippedTokens.has(token))\n\tlet node: object = root\n\tfor (const token of parentTokens) {\n\t\tconst child: unknown = Reflect.get(node, token)\n\t\tif (!isContainer(child)) {\n\t\t\treturn\n\t\t}\n\t\tconst childCopy = copies.has(child) ? child : shallowCopy(child)\n\t\tcopies.add(childCopy)\n\t\tReflect.set(node, token, childCopy)\n\t\tnode = childCopy\n\t}\n}\n"],"names":["applyPatch","Pointer"],"mappings":";;;AAKA,MAAM,gBAAgB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AAEvE,MAAM,cAAc,CAAC,UAA2C,OAAO,UAAU,YAAY,UAAU;AAEvG,MAAM,cAAc,CAAC,UAAwC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,MAAA;AAEtG,MAAM,qBAAqB,CAAC,cAAmC;AAC9D,UAAQ,UAAU,IAAA;AAAA,IACjB,KAAK;AACJ,aAAO,CAAA;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,UAAU,MAAM,UAAU,IAAI;AAAA,IACvC;AACC,aAAO,CAAC,UAAU,IAAI;AAAA,EAAA;AAEzB;AAMO,MAAM,wBAAwB,CAAmB,MAAS,UAAuD;AACvH,QAAM,SAAS,EAAE,GAAG,KAAA;AACpB,QAAM,SAAS,oBAAI,IAAa,CAAC,MAAM,CAAC;AACxC,QAAM,SAAkB,CAAA;AACxB,aAAW,aAAa,OAAO;AAG9B,eAAW,WAAW,mBAAmB,SAAS,GAAG;AACpD,kBAAY,QAAQ,SAAS,MAAM;AAAA,IACpC;AACA,eAAW,SAASA,QAAAA,WAAW,QAAQ,CAAC,SAAS,CAAC,GAAG;AACpD,UAAI,UAAU,MAAM;AACnB,eAAO,KAAK,KAAK;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AACA,SAAO,EAAE,QAAQ,OAAA;AAClB;AAEA,MAAM,cAAc,CAAC,MAAc,SAAiB,WAA+B;AAClF,QAAM,SAASC,QAAAA,QAAQ,SAAS,OAAO,EAAE,OAAO,MAAM,CAAC;AAEvD,QAAM,YAAY,OAAO,GAAG,EAAE;AAC9B,QAAM,gBAAgB,cAAc,UAAa,cAAc,IAAI,SAAS,IAAI,SAAS,OAAO,MAAM,GAAG,EAAE;AAC3G,QAAM,eAAe,cAAc,OAAO,CAAA,UAAS,CAAC,cAAc,IAAI,KAAK,CAAC;AAC5E,MAAI,OAAe;AACnB,aAAW,SAAS,cAAc;AACjC,UAAM,QAAiB,QAAQ,IAAI,MAAM,KAAK;AAC9C,QAAI,CAAC,YAAY,KAAK,GAAG;AACxB;AAAA,IACD;AACA,UAAM,YAAY,OAAO,IAAI,KAAK,IAAI,QAAQ,YAAY,KAAK;AAC/D,WAAO,IAAI,SAAS;AACpB,YAAQ,IAAI,MAAM,OAAO,SAAS;AAClC,WAAO;AAAA,EACR;AACD;;"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { applyPatch, Pointer } from "rfc6902";
|
|
2
|
+
const skippedTokens = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
3
|
+
const isContainer = (value) => typeof value === "object" && value !== null;
|
|
4
|
+
const shallowCopy = (value) => Array.isArray(value) ? [...value] : { ...value };
|
|
5
|
+
const getMutatedPointers = (operation) => {
|
|
6
|
+
switch (operation.op) {
|
|
7
|
+
case "test":
|
|
8
|
+
return [];
|
|
9
|
+
case "move":
|
|
10
|
+
return [operation.from, operation.path];
|
|
11
|
+
default:
|
|
12
|
+
return [operation.path];
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const applyPatchCopyOnWrite = (root, patch) => {
|
|
16
|
+
const result = { ...root };
|
|
17
|
+
const copies = /* @__PURE__ */ new Set([result]);
|
|
18
|
+
const errors = [];
|
|
19
|
+
for (const operation of patch) {
|
|
20
|
+
for (const pointer of getMutatedPointers(operation)) {
|
|
21
|
+
copyParents(result, pointer, copies);
|
|
22
|
+
}
|
|
23
|
+
for (const error of applyPatch(result, [operation])) {
|
|
24
|
+
if (error !== null) {
|
|
25
|
+
errors.push(error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { result, errors };
|
|
30
|
+
};
|
|
31
|
+
const copyParents = (root, pointer, copies) => {
|
|
32
|
+
const tokens = Pointer.fromJSON(pointer).tokens.slice(1);
|
|
33
|
+
const lastToken = tokens.at(-1);
|
|
34
|
+
const writtenTokens = lastToken !== void 0 && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1);
|
|
35
|
+
const parentTokens = writtenTokens.filter((token) => !skippedTokens.has(token));
|
|
36
|
+
let node = root;
|
|
37
|
+
for (const token of parentTokens) {
|
|
38
|
+
const child = Reflect.get(node, token);
|
|
39
|
+
if (!isContainer(child)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const childCopy = copies.has(child) ? child : shallowCopy(child);
|
|
43
|
+
copies.add(childCopy);
|
|
44
|
+
Reflect.set(node, token, childCopy);
|
|
45
|
+
node = childCopy;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
export {
|
|
49
|
+
applyPatchCopyOnWrite
|
|
50
|
+
};
|
|
51
|
+
//# sourceMappingURL=applyPatchCopyOnWrite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"applyPatchCopyOnWrite.js","sources":["../../../../../packages/schema-migrations/src/utils/applyPatchCopyOnWrite.ts"],"sourcesContent":["import { applyPatch, Operation, Pointer } from 'rfc6902'\n\ntype JsonContainer = { [key: string]: unknown } | unknown[]\n\n// Pointer.evaluate in rfc6902 skips these tokens, so the copy walk must skip them too.\nconst skippedTokens = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isContainer = (value: unknown): value is JsonContainer => typeof value === 'object' && value !== null\n\nconst shallowCopy = (value: JsonContainer): JsonContainer => Array.isArray(value) ? [...value] : { ...value }\n\nconst getMutatedPointers = (operation: Operation): string[] => {\n\tswitch (operation.op) {\n\t\tcase 'test':\n\t\t\treturn []\n\t\tcase 'move':\n\t\t\treturn [operation.from, operation.path]\n\t\tdefault:\n\t\t\treturn [operation.path]\n\t}\n}\n\n/**\n * Applies the patch to a copy of `root`, leaving `root` untouched. Only the containers on the paths\n * the patch writes to are copied; everything else stays shared with `root`.\n */\nexport const applyPatchCopyOnWrite = <T extends object>(root: T, patch: Operation[]): { result: T; errors: Error[] } => {\n\tconst result = { ...root }\n\tconst copies = new Set<unknown>([result])\n\tconst errors: Error[] = []\n\tfor (const operation of patch) {\n\t\t// Each path is copied against the tree as the previous operations left it: array indices shift\n\t\t// and `move` relocates an uncopied original, so a path resolved up front can miss the target.\n\t\tfor (const pointer of getMutatedPointers(operation)) {\n\t\t\tcopyParents(result, pointer, copies)\n\t\t}\n\t\tfor (const error of applyPatch(result, [operation])) {\n\t\t\tif (error !== null) {\n\t\t\t\terrors.push(error)\n\t\t\t}\n\t\t}\n\t}\n\treturn { result, errors }\n}\n\nconst copyParents = (root: object, pointer: string, copies: Set<unknown>): void => {\n\tconst tokens = Pointer.fromJSON(pointer).tokens.slice(1)\n\t// rfc6902 writes into the node reached before the last token, unless that token is skipped.\n\tconst lastToken = tokens.at(-1)\n\tconst writtenTokens = lastToken !== undefined && skippedTokens.has(lastToken) ? tokens : tokens.slice(0, -1)\n\tconst parentTokens = writtenTokens.filter(token => !skippedTokens.has(token))\n\tlet node: object = root\n\tfor (const token of parentTokens) {\n\t\tconst child: unknown = Reflect.get(node, token)\n\t\tif (!isContainer(child)) {\n\t\t\treturn\n\t\t}\n\t\tconst childCopy = copies.has(child) ? child : shallowCopy(child)\n\t\tcopies.add(childCopy)\n\t\tReflect.set(node, token, childCopy)\n\t\tnode = childCopy\n\t}\n}\n"],"names":[],"mappings":";AAKA,MAAM,gBAAgB,oBAAI,IAAI,CAAC,aAAa,eAAe,WAAW,CAAC;AAEvE,MAAM,cAAc,CAAC,UAA2C,OAAO,UAAU,YAAY,UAAU;AAEvG,MAAM,cAAc,CAAC,UAAwC,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE,GAAG,MAAA;AAEtG,MAAM,qBAAqB,CAAC,cAAmC;AAC9D,UAAQ,UAAU,IAAA;AAAA,IACjB,KAAK;AACJ,aAAO,CAAA;AAAA,IACR,KAAK;AACJ,aAAO,CAAC,UAAU,MAAM,UAAU,IAAI;AAAA,IACvC;AACC,aAAO,CAAC,UAAU,IAAI;AAAA,EAAA;AAEzB;AAMO,MAAM,wBAAwB,CAAmB,MAAS,UAAuD;AACvH,QAAM,SAAS,EAAE,GAAG,KAAA;AACpB,QAAM,SAAS,oBAAI,IAAa,CAAC,MAAM,CAAC;AACxC,QAAM,SAAkB,CAAA;AACxB,aAAW,aAAa,OAAO;AAG9B,eAAW,WAAW,mBAAmB,SAAS,GAAG;AACpD,kBAAY,QAAQ,SAAS,MAAM;AAAA,IACpC;AACA,eAAW,SAAS,WAAW,QAAQ,CAAC,SAAS,CAAC,GAAG;AACpD,UAAI,UAAU,MAAM;AACnB,eAAO,KAAK,KAAK;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AACA,SAAO,EAAE,QAAQ,OAAA;AAClB;AAEA,MAAM,cAAc,CAAC,MAAc,SAAiB,WAA+B;AAClF,QAAM,SAAS,QAAQ,SAAS,OAAO,EAAE,OAAO,MAAM,CAAC;AAEvD,QAAM,YAAY,OAAO,GAAG,EAAE;AAC9B,QAAM,gBAAgB,cAAc,UAAa,cAAc,IAAI,SAAS,IAAI,SAAS,OAAO,MAAM,GAAG,EAAE;AAC3G,QAAM,eAAe,cAAc,OAAO,CAAA,UAAS,CAAC,cAAc,IAAI,KAAK,CAAC;AAC5E,MAAI,OAAe;AACnB,aAAW,SAAS,cAAc;AACjC,UAAM,QAAiB,QAAQ,IAAI,MAAM,KAAK;AAC9C,QAAI,CAAC,YAAY,KAAK,GAAG;AACxB;AAAA,IACD;AACA,UAAM,YAAY,OAAO,IAAI,KAAK,IAAI,QAAQ,YAAY,KAAK;AAC/D,WAAO,IAAI,SAAS;AACpB,YAAQ,IAAI,MAAM,OAAO,SAAS;AAClC,WAAO;AAAA,EACR;AACD;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patchAclSchemaModification.test.d.ts","sourceRoot":"","sources":["../../../../tests/cases/unit/patchAclSchemaModification.test.ts"],"names":[],"mappings":""}
|