@contember/schema-migrations 2.2.0-alpha.1 → 2.2.0-alpha.10
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/CLAUDE.md +16 -0
- 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/src/tags.d.ts.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/Migration.d.ts.map +1 -1
- package/dist/types/MigrationDescriber.d.ts.map +1 -1
- package/dist/types/SchemaDiffer.d.ts.map +1 -1
- package/dist/types/SchemaMigrator.d.ts.map +1 -1
- package/dist/types/modifications/ModificationHandler.d.ts.map +1 -1
- package/dist/types/modifications/ModificationHandlerFactory.d.ts.map +1 -1
- package/dist/types/modifications/NoopModification.d.ts.map +1 -1
- package/dist/types/modifications/acl/PatchAclSchemaModification.d.ts.map +1 -1
- package/dist/types/modifications/acl/UpdateAclSchemaModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/CreateTargetModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/CreateTriggerModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/PatchTriggerModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/RemoveTargetModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/RemoveTriggerModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/UpdateTargetModification.d.ts.map +1 -1
- package/dist/types/modifications/actions/UpdateTriggerModification.d.ts.map +1 -1
- package/dist/types/modifications/columns/CreateColumnModification.d.ts.map +1 -1
- package/dist/types/modifications/columns/UpdateColumnDefinitionModification.d.ts.map +1 -1
- package/dist/types/modifications/columns/UpdateColumnNameModification.d.ts.map +1 -1
- package/dist/types/modifications/columns/columnUtils.d.ts +1 -1
- package/dist/types/modifications/columns/columnUtils.d.ts.map +1 -1
- package/dist/types/modifications/constraints/CreateUniqueConstraintModification.d.ts.map +1 -1
- package/dist/types/modifications/constraints/RemoveUniqueConstraintModification.d.ts.map +1 -1
- package/dist/types/modifications/constraints/utils.d.ts.map +1 -1
- package/dist/types/modifications/differs/RemoveChangedFieldDiffer.d.ts.map +1 -1
- package/dist/types/modifications/differs/RemoveViewDiffer.d.ts.map +1 -1
- package/dist/types/modifications/differs/UpdateViewDiffer.d.ts.map +1 -1
- package/dist/types/modifications/entities/CreateEntityModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/CreateViewModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/RemoveEntityModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/ToggleEventLogModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/UpdateEntityNameModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/UpdateEntityOrderByModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/UpdateEntityTableNameModification.d.ts.map +1 -1
- package/dist/types/modifications/entities/UpdateViewModification.d.ts.map +1 -1
- package/dist/types/modifications/enums/CreateEnumModification.d.ts.map +1 -1
- package/dist/types/modifications/enums/RemoveEnumModification.d.ts.map +1 -1
- package/dist/types/modifications/enums/UpdateEnumModification.d.ts.map +1 -1
- package/dist/types/modifications/enums/enumUtils.d.ts.map +1 -1
- package/dist/types/modifications/fields/RemoveFieldModification.d.ts.map +1 -1
- package/dist/types/modifications/fields/UpdateFieldNameModification.d.ts.map +1 -1
- package/dist/types/modifications/indexes/CreateIndexModification.d.ts.map +1 -1
- package/dist/types/modifications/indexes/RemoveIndexModification.d.ts.map +1 -1
- package/dist/types/modifications/indexes/utils.d.ts.map +1 -1
- package/dist/types/modifications/relations/ConvertManyHasManyToJoiningEntityModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/ConvertOneHasManyToManyHasManyRelationModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/ConvertOneHasManyToOneHasOneRelationModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/ConvertOneToManyRelationModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/CreateRelationInverseSideModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/CreateRelationModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/DisableOrphanRemovalModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/EnableOrphanRemovalModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/MakeRelationNotNullModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/MakeRelationNullableModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/ToggleJunctionEventLogModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/UpdateRelationOnDeleteModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/UpdateRelationOrderByModification.d.ts.map +1 -1
- package/dist/types/modifications/relations/helpers.d.ts.map +1 -1
- package/dist/types/modifications/relations/normalization.d.ts.map +1 -1
- package/dist/types/modifications/settings/UpdateSettingsModification.d.ts.map +1 -1
- package/dist/types/modifications/upgrade/RemoveIndexNamesModification.d.ts.map +1 -1
- package/dist/types/modifications/utils/columnUtils.d.ts +1 -1
- package/dist/types/modifications/utils/columnUtils.d.ts.map +1 -1
- package/dist/types/modifications/utils/createJunctionTable.d.ts.map +1 -1
- package/dist/types/modifications/utils/diffUtils.d.ts.map +1 -1
- package/dist/types/modifications/utils/getPrimaryColumnType.d.ts.map +1 -1
- package/dist/types/modifications/utils/schemaUpdateUtils.d.ts.map +1 -1
- package/dist/types/modifications/utils/sqlUpdateUtils.d.ts.map +1 -1
- package/dist/types/modifications/utils/stringArrayEquals.d.ts.map +1 -1
- package/dist/types/modifications/utils/valueUtils.d.ts.map +1 -1
- package/dist/types/modifications/utils/viewDependencies.d.ts.map +1 -1
- package/dist/types/modifications/validation/PatchValidationSchemaModification.d.ts.map +1 -1
- package/dist/types/modifications/validation/UpdateValidationSchemaModification.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/dist/types/utils/dbHelpers.d.ts.map +1 -1
- package/dist/types/utils/isDefined.d.ts.map +1 -1
- package/dist/types/utils/isIt.d.ts.map +1 -1
- 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
package/CLAUDE.md
CHANGED
|
@@ -40,6 +40,22 @@ interface Migration {
|
|
|
40
40
|
- **Relation type visitors**: Different SQL for different relation types (ManyHasOne → FK column, ManyHasManyOwning → junction table, inverse → no SQL)
|
|
41
41
|
- **Version tracking**: Format versions control backward-compatible behavior changes
|
|
42
42
|
|
|
43
|
+
## PostgreSQL extensions
|
|
44
|
+
|
|
45
|
+
Contember deliberately does **not** run `CREATE EXTENSION` from schema or system migrations. A feature that needs one (the `similar` / `wordSimilar` trigram operators, the `gin_trgm_ops` index `opClass`) only documents the prerequisite; enabling it is a one-off operator task per database.
|
|
46
|
+
|
|
47
|
+
Extensions typically require superuser, behave differently on managed PostgreSQL, and a failed `CREATE EXTENSION` mid-migration is hard to roll back — auto-installing one could break the migration run itself. Document the requirement in the relevant docs page with a `:::caution[...]` admonition instead (see `docs/CLAUDE.md`).
|
|
48
|
+
|
|
49
|
+
## View updates
|
|
50
|
+
|
|
51
|
+
A view whose SQL changed used to drop and recreate its entire dependant cascade, re-emit full entity definitions and re-patch all ACL — a single view change could produce a 50–170 kB migration. Cause: `RemoveViewDiffer` + `CreateViewDiffer` always took the destructive path, and `removeEntity` stripped the entity's ACL for `UpdateAclSchemaDiffer` to add straight back.
|
|
52
|
+
|
|
53
|
+
`UpdateViewDiffer` (with `isReplaceableViewChange` in `modifications/utils/viewDependencies.ts`, wired into `SchemaDiffer` after `CreateViewDiffer`) now emits a single `updateView` (`CREATE OR REPLACE VIEW`) for SQL-only and view-metadata changes on non-materialized views — no dependant cascade, no ACL re-patch. Materialized views and structural changes still cascade.
|
|
54
|
+
|
|
55
|
+
**`CREATE OR REPLACE VIEW` is narrower than it looks** (verified on PG16): the new query must produce the same column names, in the same order, with the same types, and may only append at the end. Any deviation is a hard error (SQLSTATE 42P16) and transactional — column reorder, middle insert, and *any* type change including widening (`int`→`bigint`, `varchar(10)`→`varchar(20)`, `text`→`varchar`, `int`→`numeric`) all fail.
|
|
56
|
+
|
|
57
|
+
`isReplaceableViewChange` compares Contember `fields`, which is **necessary but not sufficient**, because a view's real column types and order come from the SQL body rather than the field metadata. The two residual cases — a SQL column reorder with an unchanged field set, and output-type drift without a matching field-type change — fail loudly at execute time, before any data is touched, never silently; both imply a schema/SQL inconsistency that the old drop-and-recreate masked.
|
|
58
|
+
|
|
43
59
|
## Key Files
|
|
44
60
|
|
|
45
61
|
- `SchemaDiffer.ts` — main differ orchestrator
|
|
@@ -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
|