@strapi/core 0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8 → 0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c

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.
Files changed (23) hide show
  1. package/dist/domain/content-type/index.d.ts.map +1 -1
  2. package/dist/domain/content-type/index.js +0 -15
  3. package/dist/domain/content-type/index.js.map +1 -1
  4. package/dist/domain/content-type/index.mjs +0 -15
  5. package/dist/domain/content-type/index.mjs.map +1 -1
  6. package/dist/migrations/database/5.0.0-discard-drafts.d.ts +12 -9
  7. package/dist/migrations/database/5.0.0-discard-drafts.d.ts.map +1 -1
  8. package/dist/migrations/database/5.0.0-discard-drafts.js +50 -11
  9. package/dist/migrations/database/5.0.0-discard-drafts.js.map +1 -1
  10. package/dist/migrations/database/5.0.0-discard-drafts.mjs +51 -12
  11. package/dist/migrations/database/5.0.0-discard-drafts.mjs.map +1 -1
  12. package/dist/services/document-service/repository.d.ts.map +1 -1
  13. package/dist/services/document-service/repository.js +11 -6
  14. package/dist/services/document-service/repository.js.map +1 -1
  15. package/dist/services/document-service/repository.mjs +11 -6
  16. package/dist/services/document-service/repository.mjs.map +1 -1
  17. package/dist/services/document-service/utils/unidirectional-relations.d.ts +33 -0
  18. package/dist/services/document-service/utils/unidirectional-relations.d.ts.map +1 -0
  19. package/dist/services/document-service/utils/unidirectional-relations.js +58 -0
  20. package/dist/services/document-service/utils/unidirectional-relations.js.map +1 -0
  21. package/dist/services/document-service/utils/unidirectional-relations.mjs +58 -0
  22. package/dist/services/document-service/utils/unidirectional-relations.mjs.map +1 -0
  23. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/content-type/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAO,MAAM,eAAe,CAAC;AAGjD,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAUF,QAAA,MAAM,iBAAiB,QAAS,MAAM,cAAc,qBAAqB,0DAiDxE,CAAC;AAyDF,QAAA,MAAM,WAAW,WAAY,OAAO,WAAW,WAAW,MAAM,WAK/D,CAAC;AAmBF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/domain/content-type/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAG5C,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACrC,CAAC;AAUF,QAAA,MAAM,iBAAiB,QAAS,MAAM,cAAc,qBAAqB,0DAiCxE,CAAC;AAyDF,QAAA,MAAM,WAAW,WAAY,OAAO,WAAW,WAAW,MAAM,WAK/D,CAAC;AAmBF,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC"}
@@ -33,21 +33,6 @@ ${e.errors}`);
33
33
  actions,
34
34
  lifecycles
35
35
  });
36
- schema.attributes.localizations = {
37
- type: "relation",
38
- relation: "oneToMany",
39
- target: uid,
40
- writable: false,
41
- private: false,
42
- configurable: false,
43
- visible: false,
44
- // @ts-expect-error blabla
45
- joinColumn: {
46
- name: "document_id",
47
- referencedColumn: "document_id",
48
- referencedTable: strapi.db.metadata.identifiers.getTableName(schema.collectionName)
49
- }
50
- };
51
36
  addTimestamps(schema);
52
37
  addDraftAndPublish(schema);
53
38
  addCreatorFields(schema);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../../src/domain/content-type/index.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport _ from 'lodash';\nimport { yup, contentTypes as contentTypesUtils } from '@strapi/utils';\nimport type { Schema, UID } from '@strapi/types';\nimport { validateContentTypeDefinition } from './validator';\n\nexport type ContentTypeDefinition = {\n schema: Schema.ContentType;\n actions: Record<string, unknown>;\n lifecycles: Record<string, unknown>;\n};\n\nconst {\n CREATED_AT_ATTRIBUTE,\n UPDATED_AT_ATTRIBUTE,\n PUBLISHED_AT_ATTRIBUTE,\n CREATED_BY_ATTRIBUTE,\n UPDATED_BY_ATTRIBUTE,\n} = contentTypesUtils.constants;\n\nconst createContentType = (uid: string, definition: ContentTypeDefinition) => {\n try {\n validateContentTypeDefinition(definition);\n } catch (e) {\n if (e instanceof yup.ValidationError) {\n throw new Error(`Content Type Definition is invalid for ${uid}'.\\n${e.errors}`);\n }\n\n throw e;\n }\n\n const { schema, actions, lifecycles } = cloneDeep(definition);\n\n // general info\n Object.assign(schema, {\n uid,\n modelType: 'contentType',\n kind: schema.kind || 'collectionType',\n __schema__: pickSchema(definition.schema),\n modelName: definition.schema.info.singularName,\n actions,\n lifecycles,\n });\n\n schema.attributes.localizations = {\n type: 'relation',\n relation: 'oneToMany',\n target: uid as UID.ContentType,\n writable: false,\n private: false,\n configurable: false,\n visible: false,\n // @ts-expect-error blabla\n joinColumn: {\n name: 'document_id',\n referencedColumn: 'document_id',\n referencedTable: strapi.db.metadata.identifiers.getTableName(schema.collectionName!),\n },\n };\n\n addTimestamps(schema);\n\n // Published at is added regardless of draft and publish being enabled\n // In case it is not enabled, value will be always published, and it will not contain a draft\n addDraftAndPublish(schema);\n\n addCreatorFields(schema);\n\n return schema;\n};\n\nconst addTimestamps = (schema: Schema.ContentType) => {\n // attributes\n Object.assign(schema.attributes, {\n [CREATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n // TODO: handle on edit set to new date\n [UPDATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n });\n};\n\nconst addDraftAndPublish = (schema: Schema.ContentType) => {\n if (!_.has(schema, 'options.draftAndPublish')) {\n _.set(schema, 'options.draftAndPublish', false); // Disabled by default\n }\n\n schema.attributes[PUBLISHED_AT_ATTRIBUTE] = {\n type: 'datetime',\n configurable: false,\n writable: true,\n visible: false,\n default() {\n return new Date();\n },\n };\n};\n\nconst addCreatorFields = (schema: Schema.ContentType) => {\n const isPrivate = !_.get(schema, 'options.populateCreatorFields', false);\n\n schema.attributes[CREATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n\n schema.attributes[UPDATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n};\n\nconst getGlobalId = (schema: Schema.ContentType, prefix?: string) => {\n const modelName = schema.info.singularName;\n const globalId = prefix ? `${prefix}-${modelName}` : modelName;\n\n return schema.globalId || _.upperFirst(_.camelCase(globalId));\n};\n\nconst pickSchema = (model: Schema.ContentType) => {\n const schema = _.cloneDeep(\n _.pick(model, [\n 'connection',\n 'collectionName',\n 'info',\n 'options',\n 'pluginOptions',\n 'attributes',\n 'kind',\n ])\n );\n\n schema.kind = model.kind || 'collectionType';\n return schema;\n};\n\nexport { createContentType, getGlobalId };\n"],"names":["contentTypesUtils","validateContentTypeDefinition","yup","cloneDeep","_"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../../src/domain/content-type/index.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport _ from 'lodash';\nimport { yup, contentTypes as contentTypesUtils } from '@strapi/utils';\nimport type { Schema } from '@strapi/types';\nimport { validateContentTypeDefinition } from './validator';\n\nexport type ContentTypeDefinition = {\n schema: Schema.ContentType;\n actions: Record<string, unknown>;\n lifecycles: Record<string, unknown>;\n};\n\nconst {\n CREATED_AT_ATTRIBUTE,\n UPDATED_AT_ATTRIBUTE,\n PUBLISHED_AT_ATTRIBUTE,\n CREATED_BY_ATTRIBUTE,\n UPDATED_BY_ATTRIBUTE,\n} = contentTypesUtils.constants;\n\nconst createContentType = (uid: string, definition: ContentTypeDefinition) => {\n try {\n validateContentTypeDefinition(definition);\n } catch (e) {\n if (e instanceof yup.ValidationError) {\n throw new Error(`Content Type Definition is invalid for ${uid}'.\\n${e.errors}`);\n }\n\n throw e;\n }\n\n const { schema, actions, lifecycles } = cloneDeep(definition);\n\n // general info\n Object.assign(schema, {\n uid,\n modelType: 'contentType',\n kind: schema.kind || 'collectionType',\n __schema__: pickSchema(definition.schema),\n modelName: definition.schema.info.singularName,\n actions,\n lifecycles,\n });\n\n addTimestamps(schema);\n\n // Published at is added regardless of draft and publish being enabled\n // In case it is not enabled, value will be always published, and it will not contain a draft\n addDraftAndPublish(schema);\n\n addCreatorFields(schema);\n\n return schema;\n};\n\nconst addTimestamps = (schema: Schema.ContentType) => {\n // attributes\n Object.assign(schema.attributes, {\n [CREATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n // TODO: handle on edit set to new date\n [UPDATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n });\n};\n\nconst addDraftAndPublish = (schema: Schema.ContentType) => {\n if (!_.has(schema, 'options.draftAndPublish')) {\n _.set(schema, 'options.draftAndPublish', false); // Disabled by default\n }\n\n schema.attributes[PUBLISHED_AT_ATTRIBUTE] = {\n type: 'datetime',\n configurable: false,\n writable: true,\n visible: false,\n default() {\n return new Date();\n },\n };\n};\n\nconst addCreatorFields = (schema: Schema.ContentType) => {\n const isPrivate = !_.get(schema, 'options.populateCreatorFields', false);\n\n schema.attributes[CREATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n\n schema.attributes[UPDATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n};\n\nconst getGlobalId = (schema: Schema.ContentType, prefix?: string) => {\n const modelName = schema.info.singularName;\n const globalId = prefix ? `${prefix}-${modelName}` : modelName;\n\n return schema.globalId || _.upperFirst(_.camelCase(globalId));\n};\n\nconst pickSchema = (model: Schema.ContentType) => {\n const schema = _.cloneDeep(\n _.pick(model, [\n 'connection',\n 'collectionName',\n 'info',\n 'options',\n 'pluginOptions',\n 'attributes',\n 'kind',\n ])\n );\n\n schema.kind = model.kind || 'collectionType';\n return schema;\n};\n\nexport { createContentType, getGlobalId };\n"],"names":["contentTypesUtils","validateContentTypeDefinition","yup","cloneDeep","_"],"mappings":";;;;;;;;AAYA,MAAM;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,IAAIA,YAAAA,aAAkB;AAEhB,MAAA,oBAAoB,CAAC,KAAa,eAAsC;AACxE,MAAA;AACFC,cAAA,8BAA8B,UAAU;AAAA,WACjC,GAAG;AACN,QAAA,aAAaC,gBAAI,iBAAiB;AAC9B,YAAA,IAAI,MAAM,0CAA0C,GAAG;AAAA,EAAO,EAAE,MAAM,EAAE;AAAA,IAChF;AAEM,UAAA;AAAA,EACR;AAEA,QAAM,EAAE,QAAQ,SAAS,WAAW,IAAIC,GAAAA,UAAU,UAAU;AAG5D,SAAO,OAAO,QAAQ;AAAA,IACpB;AAAA,IACA,WAAW;AAAA,IACX,MAAM,OAAO,QAAQ;AAAA,IACrB,YAAY,WAAW,WAAW,MAAM;AAAA,IACxC,WAAW,WAAW,OAAO,KAAK;AAAA,IAClC;AAAA,IACA;AAAA,EAAA,CACD;AAED,gBAAc,MAAM;AAIpB,qBAAmB,MAAM;AAEzB,mBAAiB,MAAM;AAEhB,SAAA;AACT;AAEA,MAAM,gBAAgB,CAAC,WAA+B;AAE7C,SAAA,OAAO,OAAO,YAAY;AAAA,IAC/B,CAAC,oBAAoB,GAAG;AAAA,MACtB,MAAM;AAAA,IACR;AAAA;AAAA,IAEA,CAAC,oBAAoB,GAAG;AAAA,MACtB,MAAM;AAAA,IACR;AAAA,EAAA,CACD;AACH;AAEA,MAAM,qBAAqB,CAAC,WAA+B;AACzD,MAAI,CAACC,WAAAA,QAAE,IAAI,QAAQ,yBAAyB,GAAG;AAC3CA,eAAAA,QAAA,IAAI,QAAQ,2BAA2B,KAAK;AAAA,EAChD;AAEO,SAAA,WAAW,sBAAsB,IAAI;AAAA,IAC1C,MAAM;AAAA,IACN,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,UAAU;AACR,iCAAW,KAAK;AAAA,IAClB;AAAA,EAAA;AAEJ;AAEA,MAAM,mBAAmB,CAAC,WAA+B;AACvD,QAAM,YAAY,CAACA,mBAAE,IAAI,QAAQ,iCAAiC,KAAK;AAEhE,SAAA,WAAW,oBAAoB,IAAI;AAAA,IACxC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,EAAA;AAGJ,SAAA,WAAW,oBAAoB,IAAI;AAAA,IACxC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,EAAA;AAEb;AAEM,MAAA,cAAc,CAAC,QAA4B,WAAoB;AAC7D,QAAA,YAAY,OAAO,KAAK;AAC9B,QAAM,WAAW,SAAS,GAAG,MAAM,IAAI,SAAS,KAAK;AAErD,SAAO,OAAO,YAAYA,mBAAE,WAAWA,WAAAA,QAAE,UAAU,QAAQ,CAAC;AAC9D;AAEA,MAAM,aAAa,CAAC,UAA8B;AAChD,QAAM,SAASA,WAAAA,QAAE;AAAA,IACfA,WAAA,QAAE,KAAK,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;AAAA,EAAA;AAGI,SAAA,OAAO,MAAM,QAAQ;AACrB,SAAA;AACT;;;"}
@@ -29,21 +29,6 @@ ${e.errors}`);
29
29
  actions,
30
30
  lifecycles
31
31
  });
32
- schema.attributes.localizations = {
33
- type: "relation",
34
- relation: "oneToMany",
35
- target: uid,
36
- writable: false,
37
- private: false,
38
- configurable: false,
39
- visible: false,
40
- // @ts-expect-error blabla
41
- joinColumn: {
42
- name: "document_id",
43
- referencedColumn: "document_id",
44
- referencedTable: strapi.db.metadata.identifiers.getTableName(schema.collectionName)
45
- }
46
- };
47
32
  addTimestamps(schema);
48
33
  addDraftAndPublish(schema);
49
34
  addCreatorFields(schema);
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../../src/domain/content-type/index.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport _ from 'lodash';\nimport { yup, contentTypes as contentTypesUtils } from '@strapi/utils';\nimport type { Schema, UID } from '@strapi/types';\nimport { validateContentTypeDefinition } from './validator';\n\nexport type ContentTypeDefinition = {\n schema: Schema.ContentType;\n actions: Record<string, unknown>;\n lifecycles: Record<string, unknown>;\n};\n\nconst {\n CREATED_AT_ATTRIBUTE,\n UPDATED_AT_ATTRIBUTE,\n PUBLISHED_AT_ATTRIBUTE,\n CREATED_BY_ATTRIBUTE,\n UPDATED_BY_ATTRIBUTE,\n} = contentTypesUtils.constants;\n\nconst createContentType = (uid: string, definition: ContentTypeDefinition) => {\n try {\n validateContentTypeDefinition(definition);\n } catch (e) {\n if (e instanceof yup.ValidationError) {\n throw new Error(`Content Type Definition is invalid for ${uid}'.\\n${e.errors}`);\n }\n\n throw e;\n }\n\n const { schema, actions, lifecycles } = cloneDeep(definition);\n\n // general info\n Object.assign(schema, {\n uid,\n modelType: 'contentType',\n kind: schema.kind || 'collectionType',\n __schema__: pickSchema(definition.schema),\n modelName: definition.schema.info.singularName,\n actions,\n lifecycles,\n });\n\n schema.attributes.localizations = {\n type: 'relation',\n relation: 'oneToMany',\n target: uid as UID.ContentType,\n writable: false,\n private: false,\n configurable: false,\n visible: false,\n // @ts-expect-error blabla\n joinColumn: {\n name: 'document_id',\n referencedColumn: 'document_id',\n referencedTable: strapi.db.metadata.identifiers.getTableName(schema.collectionName!),\n },\n };\n\n addTimestamps(schema);\n\n // Published at is added regardless of draft and publish being enabled\n // In case it is not enabled, value will be always published, and it will not contain a draft\n addDraftAndPublish(schema);\n\n addCreatorFields(schema);\n\n return schema;\n};\n\nconst addTimestamps = (schema: Schema.ContentType) => {\n // attributes\n Object.assign(schema.attributes, {\n [CREATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n // TODO: handle on edit set to new date\n [UPDATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n });\n};\n\nconst addDraftAndPublish = (schema: Schema.ContentType) => {\n if (!_.has(schema, 'options.draftAndPublish')) {\n _.set(schema, 'options.draftAndPublish', false); // Disabled by default\n }\n\n schema.attributes[PUBLISHED_AT_ATTRIBUTE] = {\n type: 'datetime',\n configurable: false,\n writable: true,\n visible: false,\n default() {\n return new Date();\n },\n };\n};\n\nconst addCreatorFields = (schema: Schema.ContentType) => {\n const isPrivate = !_.get(schema, 'options.populateCreatorFields', false);\n\n schema.attributes[CREATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n\n schema.attributes[UPDATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n};\n\nconst getGlobalId = (schema: Schema.ContentType, prefix?: string) => {\n const modelName = schema.info.singularName;\n const globalId = prefix ? `${prefix}-${modelName}` : modelName;\n\n return schema.globalId || _.upperFirst(_.camelCase(globalId));\n};\n\nconst pickSchema = (model: Schema.ContentType) => {\n const schema = _.cloneDeep(\n _.pick(model, [\n 'connection',\n 'collectionName',\n 'info',\n 'options',\n 'pluginOptions',\n 'attributes',\n 'kind',\n ])\n );\n\n schema.kind = model.kind || 'collectionType';\n return schema;\n};\n\nexport { createContentType, getGlobalId };\n"],"names":["contentTypesUtils"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../../src/domain/content-type/index.ts"],"sourcesContent":["import { cloneDeep } from 'lodash/fp';\nimport _ from 'lodash';\nimport { yup, contentTypes as contentTypesUtils } from '@strapi/utils';\nimport type { Schema } from '@strapi/types';\nimport { validateContentTypeDefinition } from './validator';\n\nexport type ContentTypeDefinition = {\n schema: Schema.ContentType;\n actions: Record<string, unknown>;\n lifecycles: Record<string, unknown>;\n};\n\nconst {\n CREATED_AT_ATTRIBUTE,\n UPDATED_AT_ATTRIBUTE,\n PUBLISHED_AT_ATTRIBUTE,\n CREATED_BY_ATTRIBUTE,\n UPDATED_BY_ATTRIBUTE,\n} = contentTypesUtils.constants;\n\nconst createContentType = (uid: string, definition: ContentTypeDefinition) => {\n try {\n validateContentTypeDefinition(definition);\n } catch (e) {\n if (e instanceof yup.ValidationError) {\n throw new Error(`Content Type Definition is invalid for ${uid}'.\\n${e.errors}`);\n }\n\n throw e;\n }\n\n const { schema, actions, lifecycles } = cloneDeep(definition);\n\n // general info\n Object.assign(schema, {\n uid,\n modelType: 'contentType',\n kind: schema.kind || 'collectionType',\n __schema__: pickSchema(definition.schema),\n modelName: definition.schema.info.singularName,\n actions,\n lifecycles,\n });\n\n addTimestamps(schema);\n\n // Published at is added regardless of draft and publish being enabled\n // In case it is not enabled, value will be always published, and it will not contain a draft\n addDraftAndPublish(schema);\n\n addCreatorFields(schema);\n\n return schema;\n};\n\nconst addTimestamps = (schema: Schema.ContentType) => {\n // attributes\n Object.assign(schema.attributes, {\n [CREATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n // TODO: handle on edit set to new date\n [UPDATED_AT_ATTRIBUTE]: {\n type: 'datetime',\n },\n });\n};\n\nconst addDraftAndPublish = (schema: Schema.ContentType) => {\n if (!_.has(schema, 'options.draftAndPublish')) {\n _.set(schema, 'options.draftAndPublish', false); // Disabled by default\n }\n\n schema.attributes[PUBLISHED_AT_ATTRIBUTE] = {\n type: 'datetime',\n configurable: false,\n writable: true,\n visible: false,\n default() {\n return new Date();\n },\n };\n};\n\nconst addCreatorFields = (schema: Schema.ContentType) => {\n const isPrivate = !_.get(schema, 'options.populateCreatorFields', false);\n\n schema.attributes[CREATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n\n schema.attributes[UPDATED_BY_ATTRIBUTE] = {\n type: 'relation',\n relation: 'oneToOne',\n target: 'admin::user',\n configurable: false,\n writable: false,\n visible: false,\n useJoinTable: false,\n private: isPrivate,\n };\n};\n\nconst getGlobalId = (schema: Schema.ContentType, prefix?: string) => {\n const modelName = schema.info.singularName;\n const globalId = prefix ? `${prefix}-${modelName}` : modelName;\n\n return schema.globalId || _.upperFirst(_.camelCase(globalId));\n};\n\nconst pickSchema = (model: Schema.ContentType) => {\n const schema = _.cloneDeep(\n _.pick(model, [\n 'connection',\n 'collectionName',\n 'info',\n 'options',\n 'pluginOptions',\n 'attributes',\n 'kind',\n ])\n );\n\n schema.kind = model.kind || 'collectionType';\n return schema;\n};\n\nexport { createContentType, getGlobalId };\n"],"names":["contentTypesUtils"],"mappings":";;;;AAYA,MAAM;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,IAAIA,aAAkB;AAEhB,MAAA,oBAAoB,CAAC,KAAa,eAAsC;AACxE,MAAA;AACF,kCAA8B,UAAU;AAAA,WACjC,GAAG;AACN,QAAA,aAAa,IAAI,iBAAiB;AAC9B,YAAA,IAAI,MAAM,0CAA0C,GAAG;AAAA,EAAO,EAAE,MAAM,EAAE;AAAA,IAChF;AAEM,UAAA;AAAA,EACR;AAEA,QAAM,EAAE,QAAQ,SAAS,WAAW,IAAI,UAAU,UAAU;AAG5D,SAAO,OAAO,QAAQ;AAAA,IACpB;AAAA,IACA,WAAW;AAAA,IACX,MAAM,OAAO,QAAQ;AAAA,IACrB,YAAY,WAAW,WAAW,MAAM;AAAA,IACxC,WAAW,WAAW,OAAO,KAAK;AAAA,IAClC;AAAA,IACA;AAAA,EAAA,CACD;AAED,gBAAc,MAAM;AAIpB,qBAAmB,MAAM;AAEzB,mBAAiB,MAAM;AAEhB,SAAA;AACT;AAEA,MAAM,gBAAgB,CAAC,WAA+B;AAE7C,SAAA,OAAO,OAAO,YAAY;AAAA,IAC/B,CAAC,oBAAoB,GAAG;AAAA,MACtB,MAAM;AAAA,IACR;AAAA;AAAA,IAEA,CAAC,oBAAoB,GAAG;AAAA,MACtB,MAAM;AAAA,IACR;AAAA,EAAA,CACD;AACH;AAEA,MAAM,qBAAqB,CAAC,WAA+B;AACzD,MAAI,CAAC,EAAE,IAAI,QAAQ,yBAAyB,GAAG;AAC3C,MAAA,IAAI,QAAQ,2BAA2B,KAAK;AAAA,EAChD;AAEO,SAAA,WAAW,sBAAsB,IAAI;AAAA,IAC1C,MAAM;AAAA,IACN,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,UAAU;AACR,iCAAW,KAAK;AAAA,IAClB;AAAA,EAAA;AAEJ;AAEA,MAAM,mBAAmB,CAAC,WAA+B;AACvD,QAAM,YAAY,CAAC,EAAE,IAAI,QAAQ,iCAAiC,KAAK;AAEhE,SAAA,WAAW,oBAAoB,IAAI;AAAA,IACxC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,EAAA;AAGJ,SAAA,WAAW,oBAAoB,IAAI;AAAA,IACxC,MAAM;AAAA,IACN,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,UAAU;AAAA,IACV,SAAS;AAAA,IACT,cAAc;AAAA,IACd,SAAS;AAAA,EAAA;AAEb;AAEM,MAAA,cAAc,CAAC,QAA4B,WAAoB;AAC7D,QAAA,YAAY,OAAO,KAAK;AAC9B,QAAM,WAAW,SAAS,GAAG,MAAM,IAAI,SAAS,KAAK;AAErD,SAAO,OAAO,YAAY,EAAE,WAAW,EAAE,UAAU,QAAQ,CAAC;AAC9D;AAEA,MAAM,aAAa,CAAC,UAA8B;AAChD,QAAM,SAAS,EAAE;AAAA,IACf,EAAE,KAAK,OAAO;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;AAAA,EAAA;AAGI,SAAA,OAAO,MAAM,QAAQ;AACrB,SAAA;AACT;"}
@@ -1,3 +1,15 @@
1
+ /**
2
+ * This migration is responsible for creating the draft counterpart for all the entries that were in a published state.
3
+ *
4
+ * In v4, entries could either be in a draft or published state, but not both at the same time.
5
+ * In v5, we introduced the concept of document, and an entry can be in a draft or published state.
6
+ *
7
+ * This means the migration needs to create the draft counterpart if an entry was published.
8
+ *
9
+ * This migration performs the following steps:
10
+ * 1. Creates draft entries for all published entries, without it's components, dynamic zones or relations.
11
+ * 2. Using the document service, discard those same drafts to copy its relations.
12
+ */
1
13
  import type { Database, Migration } from '@strapi/database';
2
14
  type DocumentVersion = {
3
15
  documentId: string;
@@ -16,15 +28,6 @@ export declare function getBatchToDiscard({ db, trx, uid, batchSize, }: {
16
28
  uid: string;
17
29
  batchSize?: number;
18
30
  }): AsyncGenerator<DocumentVersion[], void, unknown>;
19
- /**
20
- * On V4 there was no concept of document, and an entry could be in a draft or published state.
21
- * But not both at the same time.
22
- *
23
- * On V5 we introduced the concept of document, and an entry can be in a draft or published state,
24
- * with the requirement that a document must always have a draft.
25
- *
26
- * This migration creates the document draft counterpart for all the entries that were in a published state.
27
- */
28
31
  export declare const discardDocumentDrafts: Migration;
29
32
  export {};
30
33
  //# sourceMappingURL=5.0.0-discard-drafts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"5.0.0-discard-drafts.d.ts","sourceRoot":"","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG5D,KAAK,eAAe,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9D,KAAK,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE3C;;;;;GAKG;AACH,wBAAuB,iBAAiB,CAAC,EACvC,EAAE,EACF,GAAG,EACH,GAAG,EACH,SAAgB,GACjB,EAAE;IACD,EAAE,EAAE,QAAQ,CAAC;IACb,GAAG,EAAE,IAAI,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,oDAuBA;AAiCD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,SASnC,CAAC"}
1
+ {"version":3,"file":"5.0.0-discard-drafts.d.ts","sourceRoot":"","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG5D,KAAK,eAAe,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9D,KAAK,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAgF3C;;;;;GAKG;AACH,wBAAuB,iBAAiB,CAAC,EACvC,EAAE,EACF,GAAG,EACH,GAAG,EACH,SAAgB,GACjB,EAAE;IACD,EAAE,EAAE,QAAQ,CAAC;IACb,GAAG,EAAE,IAAI,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,oDAuBA;AAwCD,eAAO,MAAM,qBAAqB,EAAE,SAQnC,CAAC"}
@@ -1,6 +1,45 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const strapiUtils = require("@strapi/utils");
4
+ const hasDraftAndPublish = async (trx, meta) => {
5
+ const hasTable = await trx.schema.hasTable(meta.tableName);
6
+ if (!hasTable) {
7
+ return false;
8
+ }
9
+ const uid = meta.uid;
10
+ const model = strapi.getModel(uid);
11
+ const hasDP = strapiUtils.contentTypes.hasDraftAndPublish(model);
12
+ if (!hasDP) {
13
+ return false;
14
+ }
15
+ return true;
16
+ };
17
+ async function copyPublishedEntriesToDraft({
18
+ db,
19
+ trx,
20
+ uid
21
+ }) {
22
+ const meta = db.metadata.get(uid);
23
+ const scalarAttributes = Object.values(meta.attributes).reduce((acc, attribute) => {
24
+ if (["id"].includes(attribute.columnName)) {
25
+ return acc;
26
+ }
27
+ if (strapiUtils.contentTypes.isScalarAttribute(attribute)) {
28
+ acc.push(attribute.columnName);
29
+ }
30
+ return acc;
31
+ }, []);
32
+ await trx.into(trx.raw(`${meta.tableName} (${scalarAttributes.join(", ")})`)).insert((subQb) => {
33
+ subQb.select(
34
+ ...scalarAttributes.map((att) => {
35
+ if (att === "published_at") {
36
+ return trx.raw("NULL as published_at");
37
+ }
38
+ return att;
39
+ })
40
+ ).from(meta.tableName).whereNotNull("published_at");
41
+ });
42
+ }
4
43
  async function* getBatchToDiscard({
5
44
  db,
6
45
  trx,
@@ -19,19 +58,19 @@ async function* getBatchToDiscard({
19
58
  }
20
59
  }
21
60
  const migrateUp = async (trx, db) => {
61
+ const dpModels = [];
22
62
  for (const meta of db.metadata.values()) {
23
- const hasTable = await trx.schema.hasTable(meta.tableName);
24
- if (!hasTable) {
25
- continue;
63
+ const hasDP = await hasDraftAndPublish(trx, meta);
64
+ if (hasDP) {
65
+ dpModels.push(meta);
26
66
  }
27
- const uid = meta.uid;
28
- const model = strapi.getModel(uid);
29
- const hasDP = strapiUtils.contentTypes.hasDraftAndPublish(model);
30
- if (!hasDP) {
31
- continue;
32
- }
33
- const discardDraft = async (entry) => strapi.documents(uid).discardDraft({ documentId: entry.documentId, locale: entry.locale });
34
- for await (const batch of getBatchToDiscard({ db, trx, uid: meta.uid })) {
67
+ }
68
+ for (const model of dpModels) {
69
+ await copyPublishedEntriesToDraft({ db, trx, uid: model.uid });
70
+ }
71
+ for (const model of dpModels) {
72
+ const discardDraft = async (entry) => strapi.documents(model.uid).discardDraft({ documentId: entry.documentId, locale: entry.locale });
73
+ for await (const batch of getBatchToDiscard({ db, trx, uid: model.uid })) {
35
74
  await strapiUtils.async.map(batch, discardDraft, { concurrency: 10 });
36
75
  }
37
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"5.0.0-discard-drafts.js","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport type { UID } from '@strapi/types';\nimport type { Database, Migration } from '@strapi/database';\nimport { async, contentTypes } from '@strapi/utils';\n\ntype DocumentVersion = { documentId: string; locale: string };\ntype Knex = Parameters<Migration['up']>[0];\n\n/**\n * Load a batch of versions to discard.\n *\n * Versions with only a draft version will be ignored.\n * Only versions with a published version (which always have a draft version) will be discarded.\n */\nexport async function* getBatchToDiscard({\n db,\n trx,\n uid,\n batchSize = 1000,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n batchSize?: number;\n}) {\n let offset = 0;\n let hasMore = true;\n\n while (hasMore) {\n // Look for the published entries to discard\n const batch: DocumentVersion[] = await db\n .queryBuilder(uid)\n .select(['id', 'documentId', 'locale'])\n .where({ publishedAt: { $ne: null } })\n .limit(batchSize)\n .offset(offset)\n .orderBy('id')\n .transacting(trx)\n .execute();\n\n if (batch.length < batchSize) {\n hasMore = false;\n }\n\n offset += batchSize;\n yield batch;\n }\n}\n\nconst migrateUp = async (trx: Knex, db: Database) => {\n for (const meta of db.metadata.values()) {\n const hasTable = await trx.schema.hasTable(meta.tableName);\n\n if (!hasTable) {\n continue;\n }\n\n const uid = meta.uid as UID.ContentType;\n const model = strapi.getModel(uid);\n const hasDP = contentTypes.hasDraftAndPublish(model);\n if (!hasDP) {\n continue;\n }\n\n const discardDraft = async (entry: DocumentVersion) =>\n strapi\n .documents(uid)\n // Discard draft by referencing the documentId and locale\n .discardDraft({ documentId: entry.documentId, locale: entry.locale });\n\n /**\n * Load a batch of entries (batched to prevent loading millions of rows at once ),\n * and discard them using the document service.\n */\n for await (const batch of getBatchToDiscard({ db, trx, uid: meta.uid })) {\n await async.map(batch, discardDraft, { concurrency: 10 });\n }\n }\n};\n\n/**\n * On V4 there was no concept of document, and an entry could be in a draft or published state.\n * But not both at the same time.\n *\n * On V5 we introduced the concept of document, and an entry can be in a draft or published state,\n * with the requirement that a document must always have a draft.\n *\n * This migration creates the document draft counterpart for all the entries that were in a published state.\n */\nexport const discardDocumentDrafts: Migration = {\n name: 'core::5.0.0-discard-drafts',\n async up(trx, db) {\n // TODO: Log to inform the user that the migration is running in the background\n await migrateUp(trx, db);\n },\n async down() {\n throw new Error('not implemented');\n },\n};\n"],"names":["contentTypes","async"],"mappings":";;;AAcA,gBAAuB,kBAAkB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAKG;AACD,MAAI,SAAS;AACb,MAAI,UAAU;AAEd,SAAO,SAAS;AAEd,UAAM,QAA2B,MAAM,GACpC,aAAa,GAAG,EAChB,OAAO,CAAC,MAAM,cAAc,QAAQ,CAAC,EACrC,MAAM,EAAE,aAAa,EAAE,KAAK,KAAO,EAAA,CAAC,EACpC,MAAM,SAAS,EACf,OAAO,MAAM,EACb,QAAQ,IAAI,EACZ,YAAY,GAAG,EACf,QAAQ;AAEP,QAAA,MAAM,SAAS,WAAW;AAClB,gBAAA;AAAA,IACZ;AAEU,cAAA;AACJ,UAAA;AAAA,EACR;AACF;AAEA,MAAM,YAAY,OAAO,KAAW,OAAiB;AACnD,aAAW,QAAQ,GAAG,SAAS,OAAA,GAAU;AACvC,UAAM,WAAW,MAAM,IAAI,OAAO,SAAS,KAAK,SAAS;AAEzD,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAEA,UAAM,MAAM,KAAK;AACX,UAAA,QAAQ,OAAO,SAAS,GAAG;AAC3B,UAAA,QAAQA,YAAAA,aAAa,mBAAmB,KAAK;AACnD,QAAI,CAAC,OAAO;AACV;AAAA,IACF;AAEA,UAAM,eAAe,OAAO,UAC1B,OACG,UAAU,GAAG,EAEb,aAAa,EAAE,YAAY,MAAM,YAAY,QAAQ,MAAM,QAAQ;AAMvD,qBAAA,SAAS,kBAAkB,EAAE,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG;AACvE,YAAMC,YAAAA,MAAM,IAAI,OAAO,cAAc,EAAE,aAAa,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;AAWO,MAAM,wBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,GAAG,KAAK,IAAI;AAEV,UAAA,UAAU,KAAK,EAAE;AAAA,EACzB;AAAA,EACA,MAAM,OAAO;AACL,UAAA,IAAI,MAAM,iBAAiB;AAAA,EACnC;AACF;;;"}
1
+ {"version":3,"file":"5.0.0-discard-drafts.js","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"sourcesContent":["/**\n * This migration is responsible for creating the draft counterpart for all the entries that were in a published state.\n *\n * In v4, entries could either be in a draft or published state, but not both at the same time.\n * In v5, we introduced the concept of document, and an entry can be in a draft or published state.\n *\n * This means the migration needs to create the draft counterpart if an entry was published.\n *\n * This migration performs the following steps:\n * 1. Creates draft entries for all published entries, without it's components, dynamic zones or relations.\n * 2. Using the document service, discard those same drafts to copy its relations.\n */\n\n/* eslint-disable no-continue */\nimport type { UID } from '@strapi/types';\nimport type { Database, Migration } from '@strapi/database';\nimport { async, contentTypes } from '@strapi/utils';\n\ntype DocumentVersion = { documentId: string; locale: string };\ntype Knex = Parameters<Migration['up']>[0];\n\n/**\n * Check if the model has draft and publish enabled.\n */\nconst hasDraftAndPublish = async (trx: Knex, meta: any) => {\n const hasTable = await trx.schema.hasTable(meta.tableName);\n\n if (!hasTable) {\n return false;\n }\n\n const uid = meta.uid as UID.ContentType;\n const model = strapi.getModel(uid);\n const hasDP = contentTypes.hasDraftAndPublish(model);\n if (!hasDP) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Copy all the published entries to draft entries, without it's components, dynamic zones or relations.\n * This ensures all necessary draft's exist before copying it's relations.\n */\nasync function copyPublishedEntriesToDraft({\n db,\n trx,\n uid,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n}) {\n // Extract all scalar attributes to use in the insert query\n const meta = db.metadata.get(uid);\n\n // Get scalar attributes that will be copied over the new draft\n const scalarAttributes = Object.values(meta.attributes).reduce((acc, attribute: any) => {\n if (['id'].includes(attribute.columnName)) {\n return acc;\n }\n\n if (contentTypes.isScalarAttribute(attribute)) {\n acc.push(attribute.columnName);\n }\n\n return acc;\n }, [] as string[]);\n\n /**\n * Query to copy the published entries into draft entries.\n *\n * INSERT INTO tableName (columnName1, columnName2, columnName3, ...)\n * SELECT columnName1, columnName2, columnName3, ...\n * FROM tableName\n */\n await trx\n // INSERT INTO tableName (columnName1, columnName2, columnName3, ...)\n .into(trx.raw(`${meta.tableName} (${scalarAttributes.join(', ')})`))\n .insert((subQb: typeof trx) => {\n // SELECT columnName1, columnName2, columnName3, ...\n subQb\n .select(\n ...scalarAttributes.map((att: string) => {\n // Override 'publishedAt' and 'updatedAt' attributes\n if (att === 'published_at') {\n return trx.raw('NULL as published_at');\n }\n\n return att;\n })\n )\n .from(meta.tableName)\n // Only select entries that were published\n .whereNotNull('published_at');\n });\n}\n\n/**\n * Load a batch of versions to discard.\n *\n * Versions with only a draft version will be ignored.\n * Only versions with a published version (which always have a draft version) will be discarded.\n */\nexport async function* getBatchToDiscard({\n db,\n trx,\n uid,\n batchSize = 1000,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n batchSize?: number;\n}) {\n let offset = 0;\n let hasMore = true;\n\n while (hasMore) {\n // Look for the published entries to discard\n const batch: DocumentVersion[] = await db\n .queryBuilder(uid)\n .select(['id', 'documentId', 'locale'])\n .where({ publishedAt: { $ne: null } })\n .limit(batchSize)\n .offset(offset)\n .orderBy('id')\n .transacting(trx)\n .execute();\n\n if (batch.length < batchSize) {\n hasMore = false;\n }\n\n offset += batchSize;\n yield batch;\n }\n}\n\n/**\n * 2 pass migration to create the draft entries for all the published entries.\n * And then discard the drafts to copy the relations.\n */\nconst migrateUp = async (trx: Knex, db: Database) => {\n const dpModels = [];\n for (const meta of db.metadata.values()) {\n const hasDP = await hasDraftAndPublish(trx, meta);\n if (hasDP) {\n dpModels.push(meta);\n }\n }\n\n /**\n * Create plain draft entries for all the entries that were published.\n */\n for (const model of dpModels) {\n await copyPublishedEntriesToDraft({ db, trx, uid: model.uid });\n }\n\n /**\n * Discard the drafts will copy the relations from the published entries to the newly created drafts.\n *\n * Load a batch of entries (batched to prevent loading millions of rows at once ),\n * and discard them using the document service.\n */\n for (const model of dpModels) {\n const discardDraft = async (entry: DocumentVersion) =>\n strapi\n .documents(model.uid as UID.ContentType)\n .discardDraft({ documentId: entry.documentId, locale: entry.locale });\n\n for await (const batch of getBatchToDiscard({ db, trx, uid: model.uid })) {\n await async.map(batch, discardDraft, { concurrency: 10 });\n }\n }\n};\n\nexport const discardDocumentDrafts: Migration = {\n name: 'core::5.0.0-discard-drafts',\n async up(trx, db) {\n await migrateUp(trx, db);\n },\n async down() {\n throw new Error('not implemented');\n },\n};\n"],"names":["contentTypes","async"],"mappings":";;;AAwBA,MAAM,qBAAqB,OAAO,KAAW,SAAc;AACzD,QAAM,WAAW,MAAM,IAAI,OAAO,SAAS,KAAK,SAAS;AAEzD,MAAI,CAAC,UAAU;AACN,WAAA;AAAA,EACT;AAEA,QAAM,MAAM,KAAK;AACX,QAAA,QAAQ,OAAO,SAAS,GAAG;AAC3B,QAAA,QAAQA,YAAAA,aAAa,mBAAmB,KAAK;AACnD,MAAI,CAAC,OAAO;AACH,WAAA;AAAA,EACT;AAEO,SAAA;AACT;AAMA,eAAe,4BAA4B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAED,QAAM,OAAO,GAAG,SAAS,IAAI,GAAG;AAG1B,QAAA,mBAAmB,OAAO,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC,KAAK,cAAmB;AACtF,QAAI,CAAC,IAAI,EAAE,SAAS,UAAU,UAAU,GAAG;AAClC,aAAA;AAAA,IACT;AAEI,QAAAA,YAAA,aAAa,kBAAkB,SAAS,GAAG;AACzC,UAAA,KAAK,UAAU,UAAU;AAAA,IAC/B;AAEO,WAAA;AAAA,EACT,GAAG,CAAc,CAAA;AASjB,QAAM,IAEH,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,KAAK,iBAAiB,KAAK,IAAI,CAAC,GAAG,CAAC,EAClE,OAAO,CAAC,UAAsB;AAG1B,UAAA;AAAA,MACC,GAAG,iBAAiB,IAAI,CAAC,QAAgB;AAEvC,YAAI,QAAQ,gBAAgB;AACnB,iBAAA,IAAI,IAAI,sBAAsB;AAAA,QACvC;AAEO,eAAA;AAAA,MAAA,CACR;AAAA,IAAA,EAEF,KAAK,KAAK,SAAS,EAEnB,aAAa,cAAc;AAAA,EAAA,CAC/B;AACL;AAQA,gBAAuB,kBAAkB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAKG;AACD,MAAI,SAAS;AACb,MAAI,UAAU;AAEd,SAAO,SAAS;AAEd,UAAM,QAA2B,MAAM,GACpC,aAAa,GAAG,EAChB,OAAO,CAAC,MAAM,cAAc,QAAQ,CAAC,EACrC,MAAM,EAAE,aAAa,EAAE,KAAK,KAAO,EAAA,CAAC,EACpC,MAAM,SAAS,EACf,OAAO,MAAM,EACb,QAAQ,IAAI,EACZ,YAAY,GAAG,EACf,QAAQ;AAEP,QAAA,MAAM,SAAS,WAAW;AAClB,gBAAA;AAAA,IACZ;AAEU,cAAA;AACJ,UAAA;AAAA,EACR;AACF;AAMA,MAAM,YAAY,OAAO,KAAW,OAAiB;AACnD,QAAM,WAAW,CAAA;AACjB,aAAW,QAAQ,GAAG,SAAS,OAAA,GAAU;AACvC,UAAM,QAAQ,MAAM,mBAAmB,KAAK,IAAI;AAChD,QAAI,OAAO;AACT,eAAS,KAAK,IAAI;AAAA,IACpB;AAAA,EACF;AAKA,aAAW,SAAS,UAAU;AAC5B,UAAM,4BAA4B,EAAE,IAAI,KAAK,KAAK,MAAM,KAAK;AAAA,EAC/D;AAQA,aAAW,SAAS,UAAU;AAC5B,UAAM,eAAe,OAAO,UAC1B,OACG,UAAU,MAAM,GAAsB,EACtC,aAAa,EAAE,YAAY,MAAM,YAAY,QAAQ,MAAM,QAAQ;AAEvD,qBAAA,SAAS,kBAAkB,EAAE,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,GAAG;AACxE,YAAMC,YAAAA,MAAM,IAAI,OAAO,cAAc,EAAE,aAAa,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,MAAM,wBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,GAAG,KAAK,IAAI;AACV,UAAA,UAAU,KAAK,EAAE;AAAA,EACzB;AAAA,EACA,MAAM,OAAO;AACL,UAAA,IAAI,MAAM,iBAAiB;AAAA,EACnC;AACF;;;"}
@@ -1,4 +1,43 @@
1
- import { contentTypes, async } from "@strapi/utils";
1
+ import { async, contentTypes } from "@strapi/utils";
2
+ const hasDraftAndPublish = async (trx, meta) => {
3
+ const hasTable = await trx.schema.hasTable(meta.tableName);
4
+ if (!hasTable) {
5
+ return false;
6
+ }
7
+ const uid = meta.uid;
8
+ const model = strapi.getModel(uid);
9
+ const hasDP = contentTypes.hasDraftAndPublish(model);
10
+ if (!hasDP) {
11
+ return false;
12
+ }
13
+ return true;
14
+ };
15
+ async function copyPublishedEntriesToDraft({
16
+ db,
17
+ trx,
18
+ uid
19
+ }) {
20
+ const meta = db.metadata.get(uid);
21
+ const scalarAttributes = Object.values(meta.attributes).reduce((acc, attribute) => {
22
+ if (["id"].includes(attribute.columnName)) {
23
+ return acc;
24
+ }
25
+ if (contentTypes.isScalarAttribute(attribute)) {
26
+ acc.push(attribute.columnName);
27
+ }
28
+ return acc;
29
+ }, []);
30
+ await trx.into(trx.raw(`${meta.tableName} (${scalarAttributes.join(", ")})`)).insert((subQb) => {
31
+ subQb.select(
32
+ ...scalarAttributes.map((att) => {
33
+ if (att === "published_at") {
34
+ return trx.raw("NULL as published_at");
35
+ }
36
+ return att;
37
+ })
38
+ ).from(meta.tableName).whereNotNull("published_at");
39
+ });
40
+ }
2
41
  async function* getBatchToDiscard({
3
42
  db,
4
43
  trx,
@@ -17,19 +56,19 @@ async function* getBatchToDiscard({
17
56
  }
18
57
  }
19
58
  const migrateUp = async (trx, db) => {
59
+ const dpModels = [];
20
60
  for (const meta of db.metadata.values()) {
21
- const hasTable = await trx.schema.hasTable(meta.tableName);
22
- if (!hasTable) {
23
- continue;
61
+ const hasDP = await hasDraftAndPublish(trx, meta);
62
+ if (hasDP) {
63
+ dpModels.push(meta);
24
64
  }
25
- const uid = meta.uid;
26
- const model = strapi.getModel(uid);
27
- const hasDP = contentTypes.hasDraftAndPublish(model);
28
- if (!hasDP) {
29
- continue;
30
- }
31
- const discardDraft = async (entry) => strapi.documents(uid).discardDraft({ documentId: entry.documentId, locale: entry.locale });
32
- for await (const batch of getBatchToDiscard({ db, trx, uid: meta.uid })) {
65
+ }
66
+ for (const model of dpModels) {
67
+ await copyPublishedEntriesToDraft({ db, trx, uid: model.uid });
68
+ }
69
+ for (const model of dpModels) {
70
+ const discardDraft = async (entry) => strapi.documents(model.uid).discardDraft({ documentId: entry.documentId, locale: entry.locale });
71
+ for await (const batch of getBatchToDiscard({ db, trx, uid: model.uid })) {
33
72
  await async.map(batch, discardDraft, { concurrency: 10 });
34
73
  }
35
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"5.0.0-discard-drafts.mjs","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport type { UID } from '@strapi/types';\nimport type { Database, Migration } from '@strapi/database';\nimport { async, contentTypes } from '@strapi/utils';\n\ntype DocumentVersion = { documentId: string; locale: string };\ntype Knex = Parameters<Migration['up']>[0];\n\n/**\n * Load a batch of versions to discard.\n *\n * Versions with only a draft version will be ignored.\n * Only versions with a published version (which always have a draft version) will be discarded.\n */\nexport async function* getBatchToDiscard({\n db,\n trx,\n uid,\n batchSize = 1000,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n batchSize?: number;\n}) {\n let offset = 0;\n let hasMore = true;\n\n while (hasMore) {\n // Look for the published entries to discard\n const batch: DocumentVersion[] = await db\n .queryBuilder(uid)\n .select(['id', 'documentId', 'locale'])\n .where({ publishedAt: { $ne: null } })\n .limit(batchSize)\n .offset(offset)\n .orderBy('id')\n .transacting(trx)\n .execute();\n\n if (batch.length < batchSize) {\n hasMore = false;\n }\n\n offset += batchSize;\n yield batch;\n }\n}\n\nconst migrateUp = async (trx: Knex, db: Database) => {\n for (const meta of db.metadata.values()) {\n const hasTable = await trx.schema.hasTable(meta.tableName);\n\n if (!hasTable) {\n continue;\n }\n\n const uid = meta.uid as UID.ContentType;\n const model = strapi.getModel(uid);\n const hasDP = contentTypes.hasDraftAndPublish(model);\n if (!hasDP) {\n continue;\n }\n\n const discardDraft = async (entry: DocumentVersion) =>\n strapi\n .documents(uid)\n // Discard draft by referencing the documentId and locale\n .discardDraft({ documentId: entry.documentId, locale: entry.locale });\n\n /**\n * Load a batch of entries (batched to prevent loading millions of rows at once ),\n * and discard them using the document service.\n */\n for await (const batch of getBatchToDiscard({ db, trx, uid: meta.uid })) {\n await async.map(batch, discardDraft, { concurrency: 10 });\n }\n }\n};\n\n/**\n * On V4 there was no concept of document, and an entry could be in a draft or published state.\n * But not both at the same time.\n *\n * On V5 we introduced the concept of document, and an entry can be in a draft or published state,\n * with the requirement that a document must always have a draft.\n *\n * This migration creates the document draft counterpart for all the entries that were in a published state.\n */\nexport const discardDocumentDrafts: Migration = {\n name: 'core::5.0.0-discard-drafts',\n async up(trx, db) {\n // TODO: Log to inform the user that the migration is running in the background\n await migrateUp(trx, db);\n },\n async down() {\n throw new Error('not implemented');\n },\n};\n"],"names":[],"mappings":";AAcA,gBAAuB,kBAAkB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAKG;AACD,MAAI,SAAS;AACb,MAAI,UAAU;AAEd,SAAO,SAAS;AAEd,UAAM,QAA2B,MAAM,GACpC,aAAa,GAAG,EAChB,OAAO,CAAC,MAAM,cAAc,QAAQ,CAAC,EACrC,MAAM,EAAE,aAAa,EAAE,KAAK,KAAO,EAAA,CAAC,EACpC,MAAM,SAAS,EACf,OAAO,MAAM,EACb,QAAQ,IAAI,EACZ,YAAY,GAAG,EACf,QAAQ;AAEP,QAAA,MAAM,SAAS,WAAW;AAClB,gBAAA;AAAA,IACZ;AAEU,cAAA;AACJ,UAAA;AAAA,EACR;AACF;AAEA,MAAM,YAAY,OAAO,KAAW,OAAiB;AACnD,aAAW,QAAQ,GAAG,SAAS,OAAA,GAAU;AACvC,UAAM,WAAW,MAAM,IAAI,OAAO,SAAS,KAAK,SAAS;AAEzD,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAEA,UAAM,MAAM,KAAK;AACX,UAAA,QAAQ,OAAO,SAAS,GAAG;AAC3B,UAAA,QAAQ,aAAa,mBAAmB,KAAK;AACnD,QAAI,CAAC,OAAO;AACV;AAAA,IACF;AAEA,UAAM,eAAe,OAAO,UAC1B,OACG,UAAU,GAAG,EAEb,aAAa,EAAE,YAAY,MAAM,YAAY,QAAQ,MAAM,QAAQ;AAMvD,qBAAA,SAAS,kBAAkB,EAAE,IAAI,KAAK,KAAK,KAAK,IAAI,CAAC,GAAG;AACvE,YAAM,MAAM,IAAI,OAAO,cAAc,EAAE,aAAa,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;AAWO,MAAM,wBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,GAAG,KAAK,IAAI;AAEV,UAAA,UAAU,KAAK,EAAE;AAAA,EACzB;AAAA,EACA,MAAM,OAAO;AACL,UAAA,IAAI,MAAM,iBAAiB;AAAA,EACnC;AACF;"}
1
+ {"version":3,"file":"5.0.0-discard-drafts.mjs","sources":["../../../src/migrations/database/5.0.0-discard-drafts.ts"],"sourcesContent":["/**\n * This migration is responsible for creating the draft counterpart for all the entries that were in a published state.\n *\n * In v4, entries could either be in a draft or published state, but not both at the same time.\n * In v5, we introduced the concept of document, and an entry can be in a draft or published state.\n *\n * This means the migration needs to create the draft counterpart if an entry was published.\n *\n * This migration performs the following steps:\n * 1. Creates draft entries for all published entries, without it's components, dynamic zones or relations.\n * 2. Using the document service, discard those same drafts to copy its relations.\n */\n\n/* eslint-disable no-continue */\nimport type { UID } from '@strapi/types';\nimport type { Database, Migration } from '@strapi/database';\nimport { async, contentTypes } from '@strapi/utils';\n\ntype DocumentVersion = { documentId: string; locale: string };\ntype Knex = Parameters<Migration['up']>[0];\n\n/**\n * Check if the model has draft and publish enabled.\n */\nconst hasDraftAndPublish = async (trx: Knex, meta: any) => {\n const hasTable = await trx.schema.hasTable(meta.tableName);\n\n if (!hasTable) {\n return false;\n }\n\n const uid = meta.uid as UID.ContentType;\n const model = strapi.getModel(uid);\n const hasDP = contentTypes.hasDraftAndPublish(model);\n if (!hasDP) {\n return false;\n }\n\n return true;\n};\n\n/**\n * Copy all the published entries to draft entries, without it's components, dynamic zones or relations.\n * This ensures all necessary draft's exist before copying it's relations.\n */\nasync function copyPublishedEntriesToDraft({\n db,\n trx,\n uid,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n}) {\n // Extract all scalar attributes to use in the insert query\n const meta = db.metadata.get(uid);\n\n // Get scalar attributes that will be copied over the new draft\n const scalarAttributes = Object.values(meta.attributes).reduce((acc, attribute: any) => {\n if (['id'].includes(attribute.columnName)) {\n return acc;\n }\n\n if (contentTypes.isScalarAttribute(attribute)) {\n acc.push(attribute.columnName);\n }\n\n return acc;\n }, [] as string[]);\n\n /**\n * Query to copy the published entries into draft entries.\n *\n * INSERT INTO tableName (columnName1, columnName2, columnName3, ...)\n * SELECT columnName1, columnName2, columnName3, ...\n * FROM tableName\n */\n await trx\n // INSERT INTO tableName (columnName1, columnName2, columnName3, ...)\n .into(trx.raw(`${meta.tableName} (${scalarAttributes.join(', ')})`))\n .insert((subQb: typeof trx) => {\n // SELECT columnName1, columnName2, columnName3, ...\n subQb\n .select(\n ...scalarAttributes.map((att: string) => {\n // Override 'publishedAt' and 'updatedAt' attributes\n if (att === 'published_at') {\n return trx.raw('NULL as published_at');\n }\n\n return att;\n })\n )\n .from(meta.tableName)\n // Only select entries that were published\n .whereNotNull('published_at');\n });\n}\n\n/**\n * Load a batch of versions to discard.\n *\n * Versions with only a draft version will be ignored.\n * Only versions with a published version (which always have a draft version) will be discarded.\n */\nexport async function* getBatchToDiscard({\n db,\n trx,\n uid,\n batchSize = 1000,\n}: {\n db: Database;\n trx: Knex;\n uid: string;\n batchSize?: number;\n}) {\n let offset = 0;\n let hasMore = true;\n\n while (hasMore) {\n // Look for the published entries to discard\n const batch: DocumentVersion[] = await db\n .queryBuilder(uid)\n .select(['id', 'documentId', 'locale'])\n .where({ publishedAt: { $ne: null } })\n .limit(batchSize)\n .offset(offset)\n .orderBy('id')\n .transacting(trx)\n .execute();\n\n if (batch.length < batchSize) {\n hasMore = false;\n }\n\n offset += batchSize;\n yield batch;\n }\n}\n\n/**\n * 2 pass migration to create the draft entries for all the published entries.\n * And then discard the drafts to copy the relations.\n */\nconst migrateUp = async (trx: Knex, db: Database) => {\n const dpModels = [];\n for (const meta of db.metadata.values()) {\n const hasDP = await hasDraftAndPublish(trx, meta);\n if (hasDP) {\n dpModels.push(meta);\n }\n }\n\n /**\n * Create plain draft entries for all the entries that were published.\n */\n for (const model of dpModels) {\n await copyPublishedEntriesToDraft({ db, trx, uid: model.uid });\n }\n\n /**\n * Discard the drafts will copy the relations from the published entries to the newly created drafts.\n *\n * Load a batch of entries (batched to prevent loading millions of rows at once ),\n * and discard them using the document service.\n */\n for (const model of dpModels) {\n const discardDraft = async (entry: DocumentVersion) =>\n strapi\n .documents(model.uid as UID.ContentType)\n .discardDraft({ documentId: entry.documentId, locale: entry.locale });\n\n for await (const batch of getBatchToDiscard({ db, trx, uid: model.uid })) {\n await async.map(batch, discardDraft, { concurrency: 10 });\n }\n }\n};\n\nexport const discardDocumentDrafts: Migration = {\n name: 'core::5.0.0-discard-drafts',\n async up(trx, db) {\n await migrateUp(trx, db);\n },\n async down() {\n throw new Error('not implemented');\n },\n};\n"],"names":[],"mappings":";AAwBA,MAAM,qBAAqB,OAAO,KAAW,SAAc;AACzD,QAAM,WAAW,MAAM,IAAI,OAAO,SAAS,KAAK,SAAS;AAEzD,MAAI,CAAC,UAAU;AACN,WAAA;AAAA,EACT;AAEA,QAAM,MAAM,KAAK;AACX,QAAA,QAAQ,OAAO,SAAS,GAAG;AAC3B,QAAA,QAAQ,aAAa,mBAAmB,KAAK;AACnD,MAAI,CAAC,OAAO;AACH,WAAA;AAAA,EACT;AAEO,SAAA;AACT;AAMA,eAAe,4BAA4B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AACF,GAIG;AAED,QAAM,OAAO,GAAG,SAAS,IAAI,GAAG;AAG1B,QAAA,mBAAmB,OAAO,OAAO,KAAK,UAAU,EAAE,OAAO,CAAC,KAAK,cAAmB;AACtF,QAAI,CAAC,IAAI,EAAE,SAAS,UAAU,UAAU,GAAG;AAClC,aAAA;AAAA,IACT;AAEI,QAAA,aAAa,kBAAkB,SAAS,GAAG;AACzC,UAAA,KAAK,UAAU,UAAU;AAAA,IAC/B;AAEO,WAAA;AAAA,EACT,GAAG,CAAc,CAAA;AASjB,QAAM,IAEH,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,KAAK,iBAAiB,KAAK,IAAI,CAAC,GAAG,CAAC,EAClE,OAAO,CAAC,UAAsB;AAG1B,UAAA;AAAA,MACC,GAAG,iBAAiB,IAAI,CAAC,QAAgB;AAEvC,YAAI,QAAQ,gBAAgB;AACnB,iBAAA,IAAI,IAAI,sBAAsB;AAAA,QACvC;AAEO,eAAA;AAAA,MAAA,CACR;AAAA,IAAA,EAEF,KAAK,KAAK,SAAS,EAEnB,aAAa,cAAc;AAAA,EAAA,CAC/B;AACL;AAQA,gBAAuB,kBAAkB;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AACd,GAKG;AACD,MAAI,SAAS;AACb,MAAI,UAAU;AAEd,SAAO,SAAS;AAEd,UAAM,QAA2B,MAAM,GACpC,aAAa,GAAG,EAChB,OAAO,CAAC,MAAM,cAAc,QAAQ,CAAC,EACrC,MAAM,EAAE,aAAa,EAAE,KAAK,KAAO,EAAA,CAAC,EACpC,MAAM,SAAS,EACf,OAAO,MAAM,EACb,QAAQ,IAAI,EACZ,YAAY,GAAG,EACf,QAAQ;AAEP,QAAA,MAAM,SAAS,WAAW;AAClB,gBAAA;AAAA,IACZ;AAEU,cAAA;AACJ,UAAA;AAAA,EACR;AACF;AAMA,MAAM,YAAY,OAAO,KAAW,OAAiB;AACnD,QAAM,WAAW,CAAA;AACjB,aAAW,QAAQ,GAAG,SAAS,OAAA,GAAU;AACvC,UAAM,QAAQ,MAAM,mBAAmB,KAAK,IAAI;AAChD,QAAI,OAAO;AACT,eAAS,KAAK,IAAI;AAAA,IACpB;AAAA,EACF;AAKA,aAAW,SAAS,UAAU;AAC5B,UAAM,4BAA4B,EAAE,IAAI,KAAK,KAAK,MAAM,KAAK;AAAA,EAC/D;AAQA,aAAW,SAAS,UAAU;AAC5B,UAAM,eAAe,OAAO,UAC1B,OACG,UAAU,MAAM,GAAsB,EACtC,aAAa,EAAE,YAAY,MAAM,YAAY,QAAQ,MAAM,QAAQ;AAEvD,qBAAA,SAAS,kBAAkB,EAAE,IAAI,KAAK,KAAK,MAAM,IAAI,CAAC,GAAG;AACxE,YAAM,MAAM,IAAI,OAAO,cAAc,EAAE,aAAa,IAAI;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,MAAM,wBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,MAAM,GAAG,KAAK,IAAI;AACV,UAAA,UAAU,KAAK,EAAE;AAAA,EACzB;AAAA,EACA,MAAM,OAAO;AACL,UAAA,IAAI,MAAM,iBAAiB;AAAA,EACnC;AACF;"}
@@ -1 +1 @@
1
- {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../src/services/document-service/repository.ts"],"names":[],"mappings":"AAKA,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAkB3E,eAAO,MAAM,2BAA2B,EAAE,uBA4WzC,CAAC"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../../src/services/document-service/repository.ts"],"names":[],"mappings":"AAKA,OAAO,EAAqB,KAAK,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAmB3E,eAAO,MAAM,2BAA2B,EAAE,uBAyXzC,CAAC"}
@@ -13,6 +13,7 @@ const populate = require("./utils/populate.js");
13
13
  const query = require("./transform/query.js");
14
14
  const idTransform = require("./transform/id-transform.js");
15
15
  const events = require("./events.js");
16
+ const unidirectionalRelations = require("./utils/unidirectional-relations.js");
16
17
  const { validators } = strapiUtils.validate;
17
18
  const getModel = (schema) => strapi.getModel(schema);
18
19
  const createContentTypeRepository = (uid) => {
@@ -207,7 +208,7 @@ const createContentTypeRepository = (uid) => {
207
208
  internationalization.defaultLocale(contentType),
208
209
  internationalization.multiLocaleToLookup(contentType)
209
210
  )(params2);
210
- const [draftsToPublish, publishedToDelete] = await Promise.all([
211
+ const [draftsToPublish, oldPublishedVersions] = await Promise.all([
211
212
  strapi.db.query(uid).findMany({
212
213
  where: {
213
214
  ...queryParams?.lookup,
@@ -224,14 +225,16 @@ const createContentTypeRepository = (uid) => {
224
225
  documentId,
225
226
  publishedAt: { $ne: null }
226
227
  },
227
- select: ["id"]
228
+ select: ["id", "locale"]
228
229
  })
229
230
  ]);
230
- await strapiUtils.async.map(publishedToDelete, (entry) => entries$1.delete(entry.id));
231
+ const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);
232
+ await strapiUtils.async.map(oldPublishedVersions, (entry) => entries$1.delete(entry.id));
231
233
  const publishedEntries = await strapiUtils.async.map(
232
234
  draftsToPublish,
233
235
  (draft) => entries$1.publish(draft, queryParams)
234
236
  );
237
+ await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);
235
238
  publishedEntries.forEach(emitEvent("entry.publish"));
236
239
  return { documentId, entries: publishedEntries };
237
240
  }
@@ -256,7 +259,7 @@ const createContentTypeRepository = (uid) => {
256
259
  internationalization.defaultLocale(contentType),
257
260
  internationalization.multiLocaleToLookup(contentType)
258
261
  )(params2);
259
- const [versionsToDraft, versionsToDelete] = await Promise.all([
262
+ const [versionsToDraft, oldDrafts] = await Promise.all([
260
263
  strapi.db.query(uid).findMany({
261
264
  where: {
262
265
  ...queryParams?.lookup,
@@ -272,14 +275,16 @@ const createContentTypeRepository = (uid) => {
272
275
  documentId,
273
276
  publishedAt: null
274
277
  },
275
- select: ["id"]
278
+ select: ["id", "locale"]
276
279
  })
277
280
  ]);
278
- await strapiUtils.async.map(versionsToDelete, (entry) => entries$1.delete(entry.id));
281
+ const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);
282
+ await strapiUtils.async.map(oldDrafts, (entry) => entries$1.delete(entry.id));
279
283
  const draftEntries = await strapiUtils.async.map(
280
284
  versionsToDraft,
281
285
  (entry) => entries$1.discardDraft(entry, queryParams)
282
286
  );
287
+ await unidirectionalRelations.sync(oldDrafts, draftEntries, relationsToSync);
283
288
  draftEntries.forEach(emitEvent("entry.draft-discard"));
284
289
  return { documentId, entries: draftEntries };
285
290
  }
@@ -1 +1 @@
1
- {"version":3,"file":"repository.js","sources":["../../../src/services/document-service/repository.ts"],"sourcesContent":["import { omit, assoc, merge, curry } from 'lodash/fp';\n\nimport { async, contentTypes as contentTypesUtils, validate } from '@strapi/utils';\n\nimport { UID } from '@strapi/types';\nimport { wrapInTransaction, type RepositoryFactoryMethod } from './common';\nimport * as DP from './draft-and-publish';\nimport * as i18n from './internationalization';\nimport * as components from './components';\n\nimport { createEntriesService } from './entries';\nimport { pickSelectionParams } from './params';\nimport { createDocumentId } from '../../utils/transform-content-types-to-models';\nimport { getDeepPopulate } from './utils/populate';\nimport { transformParamsToQuery } from './transform/query';\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { createEventManager } from './events';\n\nconst { validators } = validate;\n\n// we have to typecast to reconcile the differences between validator and database getModel\nconst getModel = ((schema: UID.Schema) => strapi.getModel(schema)) as (schema: string) => any;\n\nexport const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {\n const contentType = strapi.contentType(uid);\n const hasDraftAndPublish = contentTypesUtils.hasDraftAndPublish(contentType);\n\n // Define the validations that should be performed\n const sortValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const fieldValidations = ['scalarAttributes'];\n const filtersValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const populateValidations = {\n sort: sortValidations,\n field: fieldValidations,\n filters: filtersValidations,\n populate: ['nonAttributesOperators'],\n };\n\n const validateParams = async (params: any) => {\n const ctx = { schema: contentType, getModel };\n await validators.validateFilters(ctx, params.filters, filtersValidations);\n await validators.validateSort(ctx, params.sort, sortValidations);\n await validators.validateFields(ctx, params.fields, fieldValidations);\n await validators.validatePopulate(ctx, params.populate, populateValidations);\n\n // TODO: add validate status, locale, pagination\n\n return params;\n };\n\n const entries = createEntriesService(uid);\n\n const eventManager = createEventManager(strapi, uid);\n const emitEvent = curry(eventManager.emitEvent);\n\n async function findMany(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params || {});\n\n return strapi.db.query(uid).findMany(query);\n }\n\n async function findFirst(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n // TODO: do we really want to add filters on the findOne now that we have findFirst ?\n async function findOne(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n async function deleteDocument(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n omit('status'),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n if (params.status === 'draft') {\n throw new Error('Cannot delete a draft document');\n }\n\n const entriesToDelete = await strapi.db.query(uid).findMany(query);\n\n // Delete all matched entries and its components\n const deletedEntries = await async.map(entriesToDelete, (entryToDelete: any) =>\n entries.delete(entryToDelete.id)\n );\n\n entriesToDelete.forEach(emitEvent('entry.delete'));\n\n return { documentId, entries: deletedEntries };\n }\n\n async function create(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToData(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const doc = await entries.create(queryParams);\n\n emitEvent('entry.create', doc);\n\n if (hasDraftAndPublish && params.status === 'published') {\n return publish({\n ...params,\n documentId: doc.documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return doc;\n }\n\n async function clone(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n // Get deep populate\n const entriesToClone = await strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n // DP Enabled: Clone drafts\n // DP Disabled: Clone only the existing version (published)\n publishedAt: { $null: hasDraftAndPublish },\n },\n populate: getDeepPopulate(uid, { relationalFields: ['id'] }),\n });\n\n const clonedEntries = await async.map(\n entriesToClone,\n async.pipe(\n validateParams,\n omit('id'),\n // assign new documentId\n assoc('documentId', createDocumentId()),\n // Merge new data into it\n (data) => merge(data, queryParams.data),\n (data) => entries.create({ ...queryParams, data, status: 'draft' })\n )\n );\n\n clonedEntries.forEach(emitEvent('entry.create'));\n\n return { documentId: clonedEntries.at(0)?.documentId, entries: clonedEntries };\n }\n\n async function update(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToLookup(contentType),\n DP.statusToData(contentType),\n // Default locale will be set if not provided\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const { data, ...restParams } = await transformParamsDocumentId(uid, queryParams || {});\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);\n\n // Validation\n // Find if document exists\n const entryToUpdate = await strapi.db\n .query(uid)\n .findOne({ ...query, where: { ...queryParams?.lookup, ...query?.where, documentId } });\n\n let updatedDraft = null;\n if (entryToUpdate) {\n updatedDraft = await entries.update(entryToUpdate, queryParams);\n emitEvent('entry.update', updatedDraft);\n }\n\n if (!updatedDraft) {\n const documentExists = await strapi.db\n .query(contentType.uid)\n .findOne({ where: { documentId } });\n\n if (documentExists) {\n updatedDraft = await entries.create({\n ...queryParams,\n data: { ...queryParams.data, documentId },\n });\n emitEvent('entry.create', updatedDraft);\n }\n }\n\n if (hasDraftAndPublish && updatedDraft && params.status === 'published') {\n return publish({\n ...params,\n documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return updatedDraft;\n }\n\n async function count(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultStatus(contentType),\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).count(query);\n }\n\n async function publish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [draftsToPublish, publishedToDelete] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null, // Ignore lookup\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n select: ['id'],\n }),\n ]);\n\n // Delete all published versions\n await async.map(publishedToDelete, (entry: any) => entries.delete(entry.id));\n\n // Transform draft entry data and create published versions\n const publishedEntries = await async.map(draftsToPublish, (draft: unknown) =>\n entries.publish(draft, queryParams)\n );\n\n publishedEntries.forEach(emitEvent('entry.publish'));\n return { documentId, entries: publishedEntries };\n }\n\n async function unpublish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId, publishedAt: { $ne: null } }, query)\n )(params);\n\n // Delete all published versions\n const versionsToDelete = await strapi.db.query(uid).findMany(query);\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n versionsToDelete.forEach(emitEvent('entry.unpublish'));\n return { documentId, entries: versionsToDelete };\n }\n\n async function discardDraft(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [versionsToDraft, versionsToDelete] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null,\n },\n select: ['id'],\n }),\n ]);\n\n // Delete all drafts\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n // Transform published entry data and create draft versions\n const draftEntries = await async.map(versionsToDraft, (entry: any) =>\n entries.discardDraft(entry, queryParams)\n );\n\n draftEntries.forEach(emitEvent('entry.draft-discard'));\n return { documentId, entries: draftEntries };\n }\n\n async function updateComponents(entry: any, data: any) {\n return components.updateComponents(uid, entry, data);\n }\n\n function omitComponentData(data: any) {\n return components.omitComponentData(contentType, data);\n }\n\n return {\n findMany: wrapInTransaction(findMany),\n findFirst: wrapInTransaction(findFirst),\n findOne: wrapInTransaction(findOne),\n delete: wrapInTransaction(deleteDocument),\n create: wrapInTransaction(create),\n clone: wrapInTransaction(clone),\n update: wrapInTransaction(update),\n count: wrapInTransaction(count),\n publish: hasDraftAndPublish ? wrapInTransaction(publish) : (undefined as any),\n unpublish: hasDraftAndPublish ? wrapInTransaction(unpublish) : (undefined as any),\n discardDraft: hasDraftAndPublish ? wrapInTransaction(discardDraft) : (undefined as any),\n\n updateComponents,\n omitComponentData,\n };\n};\n"],"names":["validate","contentTypesUtils","params","entries","createEntriesService","createEventManager","curry","query","async","DP.defaultToDraft","DP.statusToLookup","i18n.defaultLocale","i18n.multiLocaleToLookup","transformParamsDocumentId","transformParamsToQuery","i18n.localeToLookup","assoc","omit","DP.filterDataPublishedAt","DP.setStatusToDraft","DP.statusToData","i18n.localeToData","doc","getDeepPopulate","createDocumentId","merge","pickSelectionParams","DP.defaultStatus","components.updateComponents","components.omitComponentData","wrapInTransaction"],"mappings":"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"}
1
+ {"version":3,"file":"repository.js","sources":["../../../src/services/document-service/repository.ts"],"sourcesContent":["import { omit, assoc, merge, curry } from 'lodash/fp';\n\nimport { async, contentTypes as contentTypesUtils, validate } from '@strapi/utils';\n\nimport { UID } from '@strapi/types';\nimport { wrapInTransaction, type RepositoryFactoryMethod } from './common';\nimport * as DP from './draft-and-publish';\nimport * as i18n from './internationalization';\nimport * as components from './components';\n\nimport { createEntriesService } from './entries';\nimport { pickSelectionParams } from './params';\nimport { createDocumentId } from '../../utils/transform-content-types-to-models';\nimport { getDeepPopulate } from './utils/populate';\nimport { transformParamsToQuery } from './transform/query';\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { createEventManager } from './events';\nimport * as unidirectionalRelations from './utils/unidirectional-relations';\n\nconst { validators } = validate;\n\n// we have to typecast to reconcile the differences between validator and database getModel\nconst getModel = ((schema: UID.Schema) => strapi.getModel(schema)) as (schema: string) => any;\n\nexport const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {\n const contentType = strapi.contentType(uid);\n const hasDraftAndPublish = contentTypesUtils.hasDraftAndPublish(contentType);\n\n // Define the validations that should be performed\n const sortValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const fieldValidations = ['scalarAttributes'];\n const filtersValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const populateValidations = {\n sort: sortValidations,\n field: fieldValidations,\n filters: filtersValidations,\n populate: ['nonAttributesOperators'],\n };\n\n const validateParams = async (params: any) => {\n const ctx = { schema: contentType, getModel };\n await validators.validateFilters(ctx, params.filters, filtersValidations);\n await validators.validateSort(ctx, params.sort, sortValidations);\n await validators.validateFields(ctx, params.fields, fieldValidations);\n await validators.validatePopulate(ctx, params.populate, populateValidations);\n\n // TODO: add validate status, locale, pagination\n\n return params;\n };\n\n const entries = createEntriesService(uid);\n\n const eventManager = createEventManager(strapi, uid);\n const emitEvent = curry(eventManager.emitEvent);\n\n async function findMany(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params || {});\n\n return strapi.db.query(uid).findMany(query);\n }\n\n async function findFirst(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n // TODO: do we really want to add filters on the findOne now that we have findFirst ?\n async function findOne(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n async function deleteDocument(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n omit('status'),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n if (params.status === 'draft') {\n throw new Error('Cannot delete a draft document');\n }\n\n const entriesToDelete = await strapi.db.query(uid).findMany(query);\n\n // Delete all matched entries and its components\n const deletedEntries = await async.map(entriesToDelete, (entryToDelete: any) =>\n entries.delete(entryToDelete.id)\n );\n\n entriesToDelete.forEach(emitEvent('entry.delete'));\n\n return { documentId, entries: deletedEntries };\n }\n\n async function create(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToData(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const doc = await entries.create(queryParams);\n\n emitEvent('entry.create', doc);\n\n if (hasDraftAndPublish && params.status === 'published') {\n return publish({\n ...params,\n documentId: doc.documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return doc;\n }\n\n async function clone(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n // Get deep populate\n const entriesToClone = await strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n // DP Enabled: Clone drafts\n // DP Disabled: Clone only the existing version (published)\n publishedAt: { $null: hasDraftAndPublish },\n },\n populate: getDeepPopulate(uid, { relationalFields: ['id'] }),\n });\n\n const clonedEntries = await async.map(\n entriesToClone,\n async.pipe(\n validateParams,\n omit('id'),\n // assign new documentId\n assoc('documentId', createDocumentId()),\n // Merge new data into it\n (data) => merge(data, queryParams.data),\n (data) => entries.create({ ...queryParams, data, status: 'draft' })\n )\n );\n\n clonedEntries.forEach(emitEvent('entry.create'));\n\n return { documentId: clonedEntries.at(0)?.documentId, entries: clonedEntries };\n }\n\n async function update(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToLookup(contentType),\n DP.statusToData(contentType),\n // Default locale will be set if not provided\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const { data, ...restParams } = await transformParamsDocumentId(uid, queryParams || {});\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);\n\n // Validation\n // Find if document exists\n const entryToUpdate = await strapi.db\n .query(uid)\n .findOne({ ...query, where: { ...queryParams?.lookup, ...query?.where, documentId } });\n\n let updatedDraft = null;\n if (entryToUpdate) {\n updatedDraft = await entries.update(entryToUpdate, queryParams);\n emitEvent('entry.update', updatedDraft);\n }\n\n if (!updatedDraft) {\n const documentExists = await strapi.db\n .query(contentType.uid)\n .findOne({ where: { documentId } });\n\n if (documentExists) {\n updatedDraft = await entries.create({\n ...queryParams,\n data: { ...queryParams.data, documentId },\n });\n emitEvent('entry.create', updatedDraft);\n }\n }\n\n if (hasDraftAndPublish && updatedDraft && params.status === 'published') {\n return publish({\n ...params,\n documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return updatedDraft;\n }\n\n async function count(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultStatus(contentType),\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).count(query);\n }\n\n async function publish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [draftsToPublish, oldPublishedVersions] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null, // Ignore lookup\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n select: ['id', 'locale'],\n }),\n ]);\n\n // Load any unidirectional relation targetting the old published entries\n const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);\n\n // Delete old published versions\n await async.map(oldPublishedVersions, (entry: any) => entries.delete(entry.id));\n\n // Transform draft entry data and create published versions\n const publishedEntries = await async.map(draftsToPublish, (draft: any) =>\n entries.publish(draft, queryParams)\n );\n\n // Sync unidirectional relations with the new published entries\n await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);\n\n publishedEntries.forEach(emitEvent('entry.publish'));\n\n return { documentId, entries: publishedEntries };\n }\n\n async function unpublish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId, publishedAt: { $ne: null } }, query)\n )(params);\n\n // Delete all published versions\n const versionsToDelete = await strapi.db.query(uid).findMany(query);\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n versionsToDelete.forEach(emitEvent('entry.unpublish'));\n return { documentId, entries: versionsToDelete };\n }\n\n async function discardDraft(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [versionsToDraft, oldDrafts] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null,\n },\n select: ['id', 'locale'],\n }),\n ]);\n\n // Load any unidirectional relation targeting the old drafts\n const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);\n\n // Delete old drafts\n await async.map(oldDrafts, (entry: any) => entries.delete(entry.id));\n\n // Transform published entry data and create draft versions\n const draftEntries = await async.map(versionsToDraft, (entry: any) =>\n entries.discardDraft(entry, queryParams)\n );\n\n // Sync unidirectional relations with the new draft entries\n await unidirectionalRelations.sync(oldDrafts, draftEntries, relationsToSync);\n\n draftEntries.forEach(emitEvent('entry.draft-discard'));\n return { documentId, entries: draftEntries };\n }\n\n async function updateComponents(entry: any, data: any) {\n return components.updateComponents(uid, entry, data);\n }\n\n function omitComponentData(data: any) {\n return components.omitComponentData(contentType, data);\n }\n\n return {\n findMany: wrapInTransaction(findMany),\n findFirst: wrapInTransaction(findFirst),\n findOne: wrapInTransaction(findOne),\n delete: wrapInTransaction(deleteDocument),\n create: wrapInTransaction(create),\n clone: wrapInTransaction(clone),\n update: wrapInTransaction(update),\n count: wrapInTransaction(count),\n publish: hasDraftAndPublish ? wrapInTransaction(publish) : (undefined as any),\n unpublish: hasDraftAndPublish ? wrapInTransaction(unpublish) : (undefined as any),\n discardDraft: hasDraftAndPublish ? wrapInTransaction(discardDraft) : (undefined as any),\n\n updateComponents,\n omitComponentData,\n };\n};\n"],"names":["validate","contentTypesUtils","params","entries","createEntriesService","createEventManager","curry","query","async","DP.defaultToDraft","DP.statusToLookup","i18n.defaultLocale","i18n.multiLocaleToLookup","transformParamsDocumentId","transformParamsToQuery","i18n.localeToLookup","assoc","omit","DP.filterDataPublishedAt","DP.setStatusToDraft","DP.statusToData","i18n.localeToData","doc","getDeepPopulate","createDocumentId","merge","pickSelectionParams","DP.defaultStatus","unidirectionalRelations.load","unidirectionalRelations.sync","components.updateComponents","components.omitComponentData","wrapInTransaction"],"mappings":"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"}
@@ -11,6 +11,7 @@ import { getDeepPopulate } from "./utils/populate.mjs";
11
11
  import { transformParamsToQuery } from "./transform/query.mjs";
12
12
  import { transformParamsDocumentId as curriedTransformParamsDocumentId } from "./transform/id-transform.mjs";
13
13
  import { createEventManager } from "./events.mjs";
14
+ import { load, sync } from "./utils/unidirectional-relations.mjs";
14
15
  const { validators } = validate;
15
16
  const getModel = (schema) => strapi.getModel(schema);
16
17
  const createContentTypeRepository = (uid) => {
@@ -205,7 +206,7 @@ const createContentTypeRepository = (uid) => {
205
206
  defaultLocaleCurry(contentType),
206
207
  multiLocaleToLookupCurry(contentType)
207
208
  )(params);
208
- const [draftsToPublish, publishedToDelete] = await Promise.all([
209
+ const [draftsToPublish, oldPublishedVersions] = await Promise.all([
209
210
  strapi.db.query(uid).findMany({
210
211
  where: {
211
212
  ...queryParams?.lookup,
@@ -222,14 +223,16 @@ const createContentTypeRepository = (uid) => {
222
223
  documentId,
223
224
  publishedAt: { $ne: null }
224
225
  },
225
- select: ["id"]
226
+ select: ["id", "locale"]
226
227
  })
227
228
  ]);
228
- await async.map(publishedToDelete, (entry) => entries.delete(entry.id));
229
+ const relationsToSync = await load(uid, oldPublishedVersions);
230
+ await async.map(oldPublishedVersions, (entry) => entries.delete(entry.id));
229
231
  const publishedEntries = await async.map(
230
232
  draftsToPublish,
231
233
  (draft) => entries.publish(draft, queryParams)
232
234
  );
235
+ await sync(oldPublishedVersions, publishedEntries, relationsToSync);
233
236
  publishedEntries.forEach(emitEvent("entry.publish"));
234
237
  return { documentId, entries: publishedEntries };
235
238
  }
@@ -254,7 +257,7 @@ const createContentTypeRepository = (uid) => {
254
257
  defaultLocaleCurry(contentType),
255
258
  multiLocaleToLookupCurry(contentType)
256
259
  )(params);
257
- const [versionsToDraft, versionsToDelete] = await Promise.all([
260
+ const [versionsToDraft, oldDrafts] = await Promise.all([
258
261
  strapi.db.query(uid).findMany({
259
262
  where: {
260
263
  ...queryParams?.lookup,
@@ -270,14 +273,16 @@ const createContentTypeRepository = (uid) => {
270
273
  documentId,
271
274
  publishedAt: null
272
275
  },
273
- select: ["id"]
276
+ select: ["id", "locale"]
274
277
  })
275
278
  ]);
276
- await async.map(versionsToDelete, (entry) => entries.delete(entry.id));
279
+ const relationsToSync = await load(uid, oldDrafts);
280
+ await async.map(oldDrafts, (entry) => entries.delete(entry.id));
277
281
  const draftEntries = await async.map(
278
282
  versionsToDraft,
279
283
  (entry) => entries.discardDraft(entry, queryParams)
280
284
  );
285
+ await sync(oldDrafts, draftEntries, relationsToSync);
281
286
  draftEntries.forEach(emitEvent("entry.draft-discard"));
282
287
  return { documentId, entries: draftEntries };
283
288
  }
@@ -1 +1 @@
1
- {"version":3,"file":"repository.mjs","sources":["../../../src/services/document-service/repository.ts"],"sourcesContent":["import { omit, assoc, merge, curry } from 'lodash/fp';\n\nimport { async, contentTypes as contentTypesUtils, validate } from '@strapi/utils';\n\nimport { UID } from '@strapi/types';\nimport { wrapInTransaction, type RepositoryFactoryMethod } from './common';\nimport * as DP from './draft-and-publish';\nimport * as i18n from './internationalization';\nimport * as components from './components';\n\nimport { createEntriesService } from './entries';\nimport { pickSelectionParams } from './params';\nimport { createDocumentId } from '../../utils/transform-content-types-to-models';\nimport { getDeepPopulate } from './utils/populate';\nimport { transformParamsToQuery } from './transform/query';\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { createEventManager } from './events';\n\nconst { validators } = validate;\n\n// we have to typecast to reconcile the differences between validator and database getModel\nconst getModel = ((schema: UID.Schema) => strapi.getModel(schema)) as (schema: string) => any;\n\nexport const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {\n const contentType = strapi.contentType(uid);\n const hasDraftAndPublish = contentTypesUtils.hasDraftAndPublish(contentType);\n\n // Define the validations that should be performed\n const sortValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const fieldValidations = ['scalarAttributes'];\n const filtersValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const populateValidations = {\n sort: sortValidations,\n field: fieldValidations,\n filters: filtersValidations,\n populate: ['nonAttributesOperators'],\n };\n\n const validateParams = async (params: any) => {\n const ctx = { schema: contentType, getModel };\n await validators.validateFilters(ctx, params.filters, filtersValidations);\n await validators.validateSort(ctx, params.sort, sortValidations);\n await validators.validateFields(ctx, params.fields, fieldValidations);\n await validators.validatePopulate(ctx, params.populate, populateValidations);\n\n // TODO: add validate status, locale, pagination\n\n return params;\n };\n\n const entries = createEntriesService(uid);\n\n const eventManager = createEventManager(strapi, uid);\n const emitEvent = curry(eventManager.emitEvent);\n\n async function findMany(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params || {});\n\n return strapi.db.query(uid).findMany(query);\n }\n\n async function findFirst(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n // TODO: do we really want to add filters on the findOne now that we have findFirst ?\n async function findOne(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n async function deleteDocument(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n omit('status'),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n if (params.status === 'draft') {\n throw new Error('Cannot delete a draft document');\n }\n\n const entriesToDelete = await strapi.db.query(uid).findMany(query);\n\n // Delete all matched entries and its components\n const deletedEntries = await async.map(entriesToDelete, (entryToDelete: any) =>\n entries.delete(entryToDelete.id)\n );\n\n entriesToDelete.forEach(emitEvent('entry.delete'));\n\n return { documentId, entries: deletedEntries };\n }\n\n async function create(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToData(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const doc = await entries.create(queryParams);\n\n emitEvent('entry.create', doc);\n\n if (hasDraftAndPublish && params.status === 'published') {\n return publish({\n ...params,\n documentId: doc.documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return doc;\n }\n\n async function clone(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n // Get deep populate\n const entriesToClone = await strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n // DP Enabled: Clone drafts\n // DP Disabled: Clone only the existing version (published)\n publishedAt: { $null: hasDraftAndPublish },\n },\n populate: getDeepPopulate(uid, { relationalFields: ['id'] }),\n });\n\n const clonedEntries = await async.map(\n entriesToClone,\n async.pipe(\n validateParams,\n omit('id'),\n // assign new documentId\n assoc('documentId', createDocumentId()),\n // Merge new data into it\n (data) => merge(data, queryParams.data),\n (data) => entries.create({ ...queryParams, data, status: 'draft' })\n )\n );\n\n clonedEntries.forEach(emitEvent('entry.create'));\n\n return { documentId: clonedEntries.at(0)?.documentId, entries: clonedEntries };\n }\n\n async function update(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToLookup(contentType),\n DP.statusToData(contentType),\n // Default locale will be set if not provided\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const { data, ...restParams } = await transformParamsDocumentId(uid, queryParams || {});\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);\n\n // Validation\n // Find if document exists\n const entryToUpdate = await strapi.db\n .query(uid)\n .findOne({ ...query, where: { ...queryParams?.lookup, ...query?.where, documentId } });\n\n let updatedDraft = null;\n if (entryToUpdate) {\n updatedDraft = await entries.update(entryToUpdate, queryParams);\n emitEvent('entry.update', updatedDraft);\n }\n\n if (!updatedDraft) {\n const documentExists = await strapi.db\n .query(contentType.uid)\n .findOne({ where: { documentId } });\n\n if (documentExists) {\n updatedDraft = await entries.create({\n ...queryParams,\n data: { ...queryParams.data, documentId },\n });\n emitEvent('entry.create', updatedDraft);\n }\n }\n\n if (hasDraftAndPublish && updatedDraft && params.status === 'published') {\n return publish({\n ...params,\n documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return updatedDraft;\n }\n\n async function count(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultStatus(contentType),\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).count(query);\n }\n\n async function publish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [draftsToPublish, publishedToDelete] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null, // Ignore lookup\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n select: ['id'],\n }),\n ]);\n\n // Delete all published versions\n await async.map(publishedToDelete, (entry: any) => entries.delete(entry.id));\n\n // Transform draft entry data and create published versions\n const publishedEntries = await async.map(draftsToPublish, (draft: unknown) =>\n entries.publish(draft, queryParams)\n );\n\n publishedEntries.forEach(emitEvent('entry.publish'));\n return { documentId, entries: publishedEntries };\n }\n\n async function unpublish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId, publishedAt: { $ne: null } }, query)\n )(params);\n\n // Delete all published versions\n const versionsToDelete = await strapi.db.query(uid).findMany(query);\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n versionsToDelete.forEach(emitEvent('entry.unpublish'));\n return { documentId, entries: versionsToDelete };\n }\n\n async function discardDraft(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [versionsToDraft, versionsToDelete] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null,\n },\n select: ['id'],\n }),\n ]);\n\n // Delete all drafts\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n // Transform published entry data and create draft versions\n const draftEntries = await async.map(versionsToDraft, (entry: any) =>\n entries.discardDraft(entry, queryParams)\n );\n\n draftEntries.forEach(emitEvent('entry.draft-discard'));\n return { documentId, entries: draftEntries };\n }\n\n async function updateComponents(entry: any, data: any) {\n return components.updateComponents(uid, entry, data);\n }\n\n function omitComponentData(data: any) {\n return components.omitComponentData(contentType, data);\n }\n\n return {\n findMany: wrapInTransaction(findMany),\n findFirst: wrapInTransaction(findFirst),\n findOne: wrapInTransaction(findOne),\n delete: wrapInTransaction(deleteDocument),\n create: wrapInTransaction(create),\n clone: wrapInTransaction(clone),\n update: wrapInTransaction(update),\n count: wrapInTransaction(count),\n publish: hasDraftAndPublish ? wrapInTransaction(publish) : (undefined as any),\n unpublish: hasDraftAndPublish ? wrapInTransaction(unpublish) : (undefined as any),\n discardDraft: hasDraftAndPublish ? wrapInTransaction(discardDraft) : (undefined as any),\n\n updateComponents,\n omitComponentData,\n };\n};\n"],"names":["contentTypesUtils","DP.defaultToDraft","DP.statusToLookup","i18n.defaultLocale","i18n.multiLocaleToLookup","transformParamsDocumentId","i18n.localeToLookup","query","DP.filterDataPublishedAt","DP.setStatusToDraft","DP.statusToData","i18n.localeToData","doc","DP.defaultStatus","updateComponents","components.updateComponents","omitComponentData","components.omitComponentData"],"mappings":"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"}
1
+ {"version":3,"file":"repository.mjs","sources":["../../../src/services/document-service/repository.ts"],"sourcesContent":["import { omit, assoc, merge, curry } from 'lodash/fp';\n\nimport { async, contentTypes as contentTypesUtils, validate } from '@strapi/utils';\n\nimport { UID } from '@strapi/types';\nimport { wrapInTransaction, type RepositoryFactoryMethod } from './common';\nimport * as DP from './draft-and-publish';\nimport * as i18n from './internationalization';\nimport * as components from './components';\n\nimport { createEntriesService } from './entries';\nimport { pickSelectionParams } from './params';\nimport { createDocumentId } from '../../utils/transform-content-types-to-models';\nimport { getDeepPopulate } from './utils/populate';\nimport { transformParamsToQuery } from './transform/query';\nimport { transformParamsDocumentId } from './transform/id-transform';\nimport { createEventManager } from './events';\nimport * as unidirectionalRelations from './utils/unidirectional-relations';\n\nconst { validators } = validate;\n\n// we have to typecast to reconcile the differences between validator and database getModel\nconst getModel = ((schema: UID.Schema) => strapi.getModel(schema)) as (schema: string) => any;\n\nexport const createContentTypeRepository: RepositoryFactoryMethod = (uid) => {\n const contentType = strapi.contentType(uid);\n const hasDraftAndPublish = contentTypesUtils.hasDraftAndPublish(contentType);\n\n // Define the validations that should be performed\n const sortValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const fieldValidations = ['scalarAttributes'];\n const filtersValidations = ['nonAttributesOperators', 'dynamicZones', 'morphRelations'];\n const populateValidations = {\n sort: sortValidations,\n field: fieldValidations,\n filters: filtersValidations,\n populate: ['nonAttributesOperators'],\n };\n\n const validateParams = async (params: any) => {\n const ctx = { schema: contentType, getModel };\n await validators.validateFilters(ctx, params.filters, filtersValidations);\n await validators.validateSort(ctx, params.sort, sortValidations);\n await validators.validateFields(ctx, params.fields, fieldValidations);\n await validators.validatePopulate(ctx, params.populate, populateValidations);\n\n // TODO: add validate status, locale, pagination\n\n return params;\n };\n\n const entries = createEntriesService(uid);\n\n const eventManager = createEventManager(strapi, uid);\n const emitEvent = curry(eventManager.emitEvent);\n\n async function findMany(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params || {});\n\n return strapi.db.query(uid).findMany(query);\n }\n\n async function findFirst(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n // TODO: do we really want to add filters on the findOne now that we have findFirst ?\n async function findOne(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n DP.defaultToDraft,\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsDocumentId(uid),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n return strapi.db.query(uid).findOne(query);\n }\n\n async function deleteDocument(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n omit('status'),\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId }, query)\n )(params);\n\n if (params.status === 'draft') {\n throw new Error('Cannot delete a draft document');\n }\n\n const entriesToDelete = await strapi.db.query(uid).findMany(query);\n\n // Delete all matched entries and its components\n const deletedEntries = await async.map(entriesToDelete, (entryToDelete: any) =>\n entries.delete(entryToDelete.id)\n );\n\n entriesToDelete.forEach(emitEvent('entry.delete'));\n\n return { documentId, entries: deletedEntries };\n }\n\n async function create(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToData(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const doc = await entries.create(queryParams);\n\n emitEvent('entry.create', doc);\n\n if (hasDraftAndPublish && params.status === 'published') {\n return publish({\n ...params,\n documentId: doc.documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return doc;\n }\n\n async function clone(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n // Get deep populate\n const entriesToClone = await strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n // DP Enabled: Clone drafts\n // DP Disabled: Clone only the existing version (published)\n publishedAt: { $null: hasDraftAndPublish },\n },\n populate: getDeepPopulate(uid, { relationalFields: ['id'] }),\n });\n\n const clonedEntries = await async.map(\n entriesToClone,\n async.pipe(\n validateParams,\n omit('id'),\n // assign new documentId\n assoc('documentId', createDocumentId()),\n // Merge new data into it\n (data) => merge(data, queryParams.data),\n (data) => entries.create({ ...queryParams, data, status: 'draft' })\n )\n );\n\n clonedEntries.forEach(emitEvent('entry.create'));\n\n return { documentId: clonedEntries.at(0)?.documentId, entries: clonedEntries };\n }\n\n async function update(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n DP.filterDataPublishedAt,\n DP.setStatusToDraft(contentType),\n DP.statusToLookup(contentType),\n DP.statusToData(contentType),\n // Default locale will be set if not provided\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n i18n.localeToData(contentType)\n )(params);\n\n const { data, ...restParams } = await transformParamsDocumentId(uid, queryParams || {});\n const query = transformParamsToQuery(uid, pickSelectionParams(restParams || {}) as any);\n\n // Validation\n // Find if document exists\n const entryToUpdate = await strapi.db\n .query(uid)\n .findOne({ ...query, where: { ...queryParams?.lookup, ...query?.where, documentId } });\n\n let updatedDraft = null;\n if (entryToUpdate) {\n updatedDraft = await entries.update(entryToUpdate, queryParams);\n emitEvent('entry.update', updatedDraft);\n }\n\n if (!updatedDraft) {\n const documentExists = await strapi.db\n .query(contentType.uid)\n .findOne({ where: { documentId } });\n\n if (documentExists) {\n updatedDraft = await entries.create({\n ...queryParams,\n data: { ...queryParams.data, documentId },\n });\n emitEvent('entry.create', updatedDraft);\n }\n }\n\n if (hasDraftAndPublish && updatedDraft && params.status === 'published') {\n return publish({\n ...params,\n documentId,\n }).then((doc) => doc.entries[0]);\n }\n\n return updatedDraft;\n }\n\n async function count(params = {} as any) {\n const query = await async.pipe(\n validateParams,\n DP.defaultStatus(contentType),\n DP.statusToLookup(contentType),\n i18n.defaultLocale(contentType),\n i18n.localeToLookup(contentType),\n transformParamsToQuery(uid)\n )(params);\n\n return strapi.db.query(uid).count(query);\n }\n\n async function publish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [draftsToPublish, oldPublishedVersions] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null, // Ignore lookup\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n select: ['id', 'locale'],\n }),\n ]);\n\n // Load any unidirectional relation targetting the old published entries\n const relationsToSync = await unidirectionalRelations.load(uid, oldPublishedVersions);\n\n // Delete old published versions\n await async.map(oldPublishedVersions, (entry: any) => entries.delete(entry.id));\n\n // Transform draft entry data and create published versions\n const publishedEntries = await async.map(draftsToPublish, (draft: any) =>\n entries.publish(draft, queryParams)\n );\n\n // Sync unidirectional relations with the new published entries\n await unidirectionalRelations.sync(oldPublishedVersions, publishedEntries, relationsToSync);\n\n publishedEntries.forEach(emitEvent('entry.publish'));\n\n return { documentId, entries: publishedEntries };\n }\n\n async function unpublish(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const query = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType),\n transformParamsToQuery(uid),\n (query) => assoc('where', { ...query.where, documentId, publishedAt: { $ne: null } }, query)\n )(params);\n\n // Delete all published versions\n const versionsToDelete = await strapi.db.query(uid).findMany(query);\n await async.map(versionsToDelete, (entry: any) => entries.delete(entry.id));\n\n versionsToDelete.forEach(emitEvent('entry.unpublish'));\n return { documentId, entries: versionsToDelete };\n }\n\n async function discardDraft(opts = {} as any) {\n const { documentId, ...params } = opts;\n\n const queryParams = await async.pipe(\n validateParams,\n i18n.defaultLocale(contentType),\n i18n.multiLocaleToLookup(contentType)\n )(params);\n\n const [versionsToDraft, oldDrafts] = await Promise.all([\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: { $ne: null },\n },\n // Populate relations, media, compos and dz\n populate: getDeepPopulate(uid, { relationalFields: ['documentId', 'locale'] }),\n }),\n strapi.db.query(uid).findMany({\n where: {\n ...queryParams?.lookup,\n documentId,\n publishedAt: null,\n },\n select: ['id', 'locale'],\n }),\n ]);\n\n // Load any unidirectional relation targeting the old drafts\n const relationsToSync = await unidirectionalRelations.load(uid, oldDrafts);\n\n // Delete old drafts\n await async.map(oldDrafts, (entry: any) => entries.delete(entry.id));\n\n // Transform published entry data and create draft versions\n const draftEntries = await async.map(versionsToDraft, (entry: any) =>\n entries.discardDraft(entry, queryParams)\n );\n\n // Sync unidirectional relations with the new draft entries\n await unidirectionalRelations.sync(oldDrafts, draftEntries, relationsToSync);\n\n draftEntries.forEach(emitEvent('entry.draft-discard'));\n return { documentId, entries: draftEntries };\n }\n\n async function updateComponents(entry: any, data: any) {\n return components.updateComponents(uid, entry, data);\n }\n\n function omitComponentData(data: any) {\n return components.omitComponentData(contentType, data);\n }\n\n return {\n findMany: wrapInTransaction(findMany),\n findFirst: wrapInTransaction(findFirst),\n findOne: wrapInTransaction(findOne),\n delete: wrapInTransaction(deleteDocument),\n create: wrapInTransaction(create),\n clone: wrapInTransaction(clone),\n update: wrapInTransaction(update),\n count: wrapInTransaction(count),\n publish: hasDraftAndPublish ? wrapInTransaction(publish) : (undefined as any),\n unpublish: hasDraftAndPublish ? wrapInTransaction(unpublish) : (undefined as any),\n discardDraft: hasDraftAndPublish ? wrapInTransaction(discardDraft) : (undefined as any),\n\n updateComponents,\n omitComponentData,\n };\n};\n"],"names":["contentTypesUtils","DP.defaultToDraft","DP.statusToLookup","i18n.defaultLocale","i18n.multiLocaleToLookup","transformParamsDocumentId","i18n.localeToLookup","query","DP.filterDataPublishedAt","DP.setStatusToDraft","DP.statusToData","i18n.localeToData","doc","DP.defaultStatus","unidirectionalRelations.load","unidirectionalRelations.sync","updateComponents","components.updateComponents","omitComponentData","components.omitComponentData"],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { UID } from '@strapi/types';
2
+ /**
3
+ * Loads lingering relations that need to be updated when overriding a published or draft entry.
4
+ * This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.
5
+ * This is not the case for bi-directional relations, where the target entry is also linked to the source entry.
6
+ *
7
+ * @param uid The content type uid
8
+ * @param oldEntries The old entries that are being overridden
9
+ * @returns An array of relations that need to be updated with the join table reference.
10
+ */
11
+ declare const load: (uid: UID.ContentType, oldEntries: {
12
+ id: string;
13
+ locale: string;
14
+ }[]) => Promise<any>;
15
+ /**
16
+ * Updates uni directional relations to target the right entries when overriding published or draft entries.
17
+ *
18
+ * @param oldEntries The old entries that are being overridden
19
+ * @param newEntries The new entries that are overriding the old ones
20
+ * @param oldRelations The relations that were previously loaded with `load` @see load
21
+ */
22
+ declare const sync: (oldEntries: {
23
+ id: string;
24
+ locale: string;
25
+ }[], newEntries: {
26
+ id: string;
27
+ locale: string;
28
+ }[], oldRelations: {
29
+ joinTable: any;
30
+ relations: any[];
31
+ }[]) => Promise<void>;
32
+ export { load, sync };
33
+ //# sourceMappingURL=unidirectional-relations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unidirectional-relations.d.ts","sourceRoot":"","sources":["../../../../src/services/document-service/utils/unidirectional-relations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,GAAG,EAAU,MAAM,eAAe,CAAC;AAE5C;;;;;;;;GAQG;AACH,QAAA,MAAM,IAAI,QAAe,IAAI,WAAW,cAAc;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,iBA2CrF,CAAC;AAEF;;;;;;GAMG;AACH,QAAA,MAAM,IAAI,eACI;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,cAChC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAAE,gBAC9B;IAAE,SAAS,EAAE,GAAG,CAAC;IAAC,SAAS,EAAE,GAAG,EAAE,CAAA;CAAE,EAAE,kBAkCrD,CAAC;AAEF,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const fp = require("lodash/fp");
4
+ const load = async (uid, oldEntries) => {
5
+ const updates = [];
6
+ await strapi.db.transaction(async ({ trx }) => {
7
+ const contentTypes = Object.values(strapi.contentTypes);
8
+ const components = Object.values(strapi.components);
9
+ for (const model of [...contentTypes, ...components]) {
10
+ const dbModel = strapi.db.metadata.get(model.uid);
11
+ for (const attribute of Object.values(dbModel.attributes)) {
12
+ if (attribute.type !== "relation")
13
+ continue;
14
+ if (attribute.target !== uid)
15
+ continue;
16
+ if (attribute.inversedBy || attribute.mappedBy)
17
+ continue;
18
+ const joinTable = attribute.joinTable;
19
+ if (!joinTable)
20
+ continue;
21
+ const { name } = joinTable.inverseJoinColumn;
22
+ const oldEntriesIds = oldEntries.map((entry) => entry.id);
23
+ const relations = await strapi.db.getConnection().select("*").from(joinTable.name).whereIn(name, oldEntriesIds).transacting(trx);
24
+ if (relations.length === 0)
25
+ continue;
26
+ updates.push({ joinTable, relations });
27
+ }
28
+ }
29
+ });
30
+ return updates;
31
+ };
32
+ const sync = async (oldEntries, newEntries, oldRelations) => {
33
+ const newEntryByLocale = fp.keyBy("locale", newEntries);
34
+ const oldEntriesMap = oldEntries.reduce(
35
+ (acc, entry) => {
36
+ const newEntry = newEntryByLocale[entry.locale];
37
+ if (!newEntry)
38
+ return acc;
39
+ acc[entry.id] = newEntry.id;
40
+ return acc;
41
+ },
42
+ {}
43
+ );
44
+ await strapi.db.transaction(async ({ trx }) => {
45
+ const con = strapi.db.getConnection();
46
+ for (const { joinTable, relations } of oldRelations) {
47
+ const newRelations = relations.map((relation) => {
48
+ const column = joinTable.inverseJoinColumn.name;
49
+ const newId = oldEntriesMap[relation[column]];
50
+ return { ...relation, [column]: newId };
51
+ });
52
+ await con.batchInsert(joinTable.name, newRelations).transacting(trx);
53
+ }
54
+ });
55
+ };
56
+ exports.load = load;
57
+ exports.sync = sync;
58
+ //# sourceMappingURL=unidirectional-relations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unidirectional-relations.js","sources":["../../../../src/services/document-service/utils/unidirectional-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy } from 'lodash/fp';\n\nimport { UID, Schema } from '@strapi/types';\n\n/**\n * Loads lingering relations that need to be updated when overriding a published or draft entry.\n * This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.\n * This is not the case for bi-directional relations, where the target entry is also linked to the source entry.\n *\n * @param uid The content type uid\n * @param oldEntries The old entries that are being overridden\n * @returns An array of relations that need to be updated with the join table reference.\n */\nconst load = async (uid: UID.ContentType, oldEntries: { id: string; locale: string }[]) => {\n const updates = [] as any;\n\n // Iterate all components and content types to find relations that need to be updated\n await strapi.db.transaction(async ({ trx }) => {\n const contentTypes = Object.values(strapi.contentTypes) as Schema.ContentType[];\n const components = Object.values(strapi.components) as Schema.Component[];\n\n for (const model of [...contentTypes, ...components]) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as any) {\n /**\n * Only consider unidirectional relations\n */\n if (attribute.type !== 'relation') continue;\n if (attribute.target !== uid) continue;\n if (attribute.inversedBy || attribute.mappedBy) continue;\n const joinTable = attribute.joinTable;\n // TODO: joinColumn relations\n if (!joinTable) continue;\n\n const { name } = joinTable.inverseJoinColumn;\n\n /**\n * Load all relations that need to be updated\n */\n const oldEntriesIds = oldEntries.map((entry) => entry.id);\n const relations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(name, oldEntriesIds)\n .transacting(trx);\n\n if (relations.length === 0) continue;\n\n updates.push({ joinTable, relations });\n }\n }\n });\n\n return updates;\n};\n\n/**\n * Updates uni directional relations to target the right entries when overriding published or draft entries.\n *\n * @param oldEntries The old entries that are being overridden\n * @param newEntries The new entries that are overriding the old ones\n * @param oldRelations The relations that were previously loaded with `load` @see load\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n oldRelations: { joinTable: any; relations: any[] }[]\n) => {\n /**\n * Create a map of old entry ids to new entry ids\n *\n * Will be used to update the relation target ids\n */\n const newEntryByLocale = keyBy('locale', newEntries);\n const oldEntriesMap = oldEntries.reduce(\n (acc, entry) => {\n const newEntry = newEntryByLocale[entry.locale];\n if (!newEntry) return acc;\n acc[entry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n await strapi.db.transaction(async ({ trx }) => {\n const con = strapi.db.getConnection();\n\n // Iterate old relations that are deleted and insert the new ones\n for (const { joinTable, relations } of oldRelations) {\n // Update old ids with the new ones\n const newRelations = relations.map((relation) => {\n const column = joinTable.inverseJoinColumn.name;\n const newId = oldEntriesMap[relation[column]];\n return { ...relation, [column]: newId };\n });\n\n // Insert those relations into the join table\n await con.batchInsert(joinTable.name, newRelations).transacting(trx);\n }\n });\n};\n\nexport { load, sync };\n"],"names":["keyBy"],"mappings":";;;AAcM,MAAA,OAAO,OAAO,KAAsB,eAAiD;AACzF,QAAM,UAAU,CAAA;AAGhB,QAAM,OAAO,GAAG,YAAY,OAAO,EAAE,UAAU;AAC7C,UAAM,eAAe,OAAO,OAAO,OAAO,YAAY;AACtD,UAAM,aAAa,OAAO,OAAO,OAAO,UAAU;AAElD,eAAW,SAAS,CAAC,GAAG,cAAc,GAAG,UAAU,GAAG;AACpD,YAAM,UAAU,OAAO,GAAG,SAAS,IAAI,MAAM,GAAG;AAEhD,iBAAW,aAAa,OAAO,OAAO,QAAQ,UAAU,GAAU;AAIhE,YAAI,UAAU,SAAS;AAAY;AACnC,YAAI,UAAU,WAAW;AAAK;AAC1B,YAAA,UAAU,cAAc,UAAU;AAAU;AAChD,cAAM,YAAY,UAAU;AAE5B,YAAI,CAAC;AAAW;AAEV,cAAA,EAAE,KAAK,IAAI,UAAU;AAK3B,cAAM,gBAAgB,WAAW,IAAI,CAAC,UAAU,MAAM,EAAE;AACxD,cAAM,YAAY,MAAM,OAAO,GAC5B,gBACA,OAAO,GAAG,EACV,KAAK,UAAU,IAAI,EACnB,QAAQ,MAAM,aAAa,EAC3B,YAAY,GAAG;AAElB,YAAI,UAAU,WAAW;AAAG;AAE5B,gBAAQ,KAAK,EAAE,WAAW,UAAW,CAAA;AAAA,MACvC;AAAA,IACF;AAAA,EAAA,CACD;AAEM,SAAA;AACT;AASA,MAAM,OAAO,OACX,YACA,YACA,iBACG;AAMG,QAAA,mBAAmBA,GAAAA,MAAM,UAAU,UAAU;AACnD,QAAM,gBAAgB,WAAW;AAAA,IAC/B,CAAC,KAAK,UAAU;AACR,YAAA,WAAW,iBAAiB,MAAM,MAAM;AAC9C,UAAI,CAAC;AAAiB,eAAA;AAClB,UAAA,MAAM,EAAE,IAAI,SAAS;AAClB,aAAA;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EAAA;AAGH,QAAM,OAAO,GAAG,YAAY,OAAO,EAAE,UAAU;AACvC,UAAA,MAAM,OAAO,GAAG,cAAc;AAGpC,eAAW,EAAE,WAAW,UAAU,KAAK,cAAc;AAEnD,YAAM,eAAe,UAAU,IAAI,CAAC,aAAa;AACzC,cAAA,SAAS,UAAU,kBAAkB;AAC3C,cAAM,QAAQ,cAAc,SAAS,MAAM,CAAC;AAC5C,eAAO,EAAE,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM;AAAA,MAAA,CACvC;AAGD,YAAM,IAAI,YAAY,UAAU,MAAM,YAAY,EAAE,YAAY,GAAG;AAAA,IACrE;AAAA,EAAA,CACD;AACH;;;"}
@@ -0,0 +1,58 @@
1
+ import { keyBy } from "lodash/fp";
2
+ const load = async (uid, oldEntries) => {
3
+ const updates = [];
4
+ await strapi.db.transaction(async ({ trx }) => {
5
+ const contentTypes = Object.values(strapi.contentTypes);
6
+ const components = Object.values(strapi.components);
7
+ for (const model of [...contentTypes, ...components]) {
8
+ const dbModel = strapi.db.metadata.get(model.uid);
9
+ for (const attribute of Object.values(dbModel.attributes)) {
10
+ if (attribute.type !== "relation")
11
+ continue;
12
+ if (attribute.target !== uid)
13
+ continue;
14
+ if (attribute.inversedBy || attribute.mappedBy)
15
+ continue;
16
+ const joinTable = attribute.joinTable;
17
+ if (!joinTable)
18
+ continue;
19
+ const { name } = joinTable.inverseJoinColumn;
20
+ const oldEntriesIds = oldEntries.map((entry) => entry.id);
21
+ const relations = await strapi.db.getConnection().select("*").from(joinTable.name).whereIn(name, oldEntriesIds).transacting(trx);
22
+ if (relations.length === 0)
23
+ continue;
24
+ updates.push({ joinTable, relations });
25
+ }
26
+ }
27
+ });
28
+ return updates;
29
+ };
30
+ const sync = async (oldEntries, newEntries, oldRelations) => {
31
+ const newEntryByLocale = keyBy("locale", newEntries);
32
+ const oldEntriesMap = oldEntries.reduce(
33
+ (acc, entry) => {
34
+ const newEntry = newEntryByLocale[entry.locale];
35
+ if (!newEntry)
36
+ return acc;
37
+ acc[entry.id] = newEntry.id;
38
+ return acc;
39
+ },
40
+ {}
41
+ );
42
+ await strapi.db.transaction(async ({ trx }) => {
43
+ const con = strapi.db.getConnection();
44
+ for (const { joinTable, relations } of oldRelations) {
45
+ const newRelations = relations.map((relation) => {
46
+ const column = joinTable.inverseJoinColumn.name;
47
+ const newId = oldEntriesMap[relation[column]];
48
+ return { ...relation, [column]: newId };
49
+ });
50
+ await con.batchInsert(joinTable.name, newRelations).transacting(trx);
51
+ }
52
+ });
53
+ };
54
+ export {
55
+ load,
56
+ sync
57
+ };
58
+ //# sourceMappingURL=unidirectional-relations.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unidirectional-relations.mjs","sources":["../../../../src/services/document-service/utils/unidirectional-relations.ts"],"sourcesContent":["/* eslint-disable no-continue */\nimport { keyBy } from 'lodash/fp';\n\nimport { UID, Schema } from '@strapi/types';\n\n/**\n * Loads lingering relations that need to be updated when overriding a published or draft entry.\n * This is necessary because the relations are uni-directional and the target entry is not aware of the source entry.\n * This is not the case for bi-directional relations, where the target entry is also linked to the source entry.\n *\n * @param uid The content type uid\n * @param oldEntries The old entries that are being overridden\n * @returns An array of relations that need to be updated with the join table reference.\n */\nconst load = async (uid: UID.ContentType, oldEntries: { id: string; locale: string }[]) => {\n const updates = [] as any;\n\n // Iterate all components and content types to find relations that need to be updated\n await strapi.db.transaction(async ({ trx }) => {\n const contentTypes = Object.values(strapi.contentTypes) as Schema.ContentType[];\n const components = Object.values(strapi.components) as Schema.Component[];\n\n for (const model of [...contentTypes, ...components]) {\n const dbModel = strapi.db.metadata.get(model.uid);\n\n for (const attribute of Object.values(dbModel.attributes) as any) {\n /**\n * Only consider unidirectional relations\n */\n if (attribute.type !== 'relation') continue;\n if (attribute.target !== uid) continue;\n if (attribute.inversedBy || attribute.mappedBy) continue;\n const joinTable = attribute.joinTable;\n // TODO: joinColumn relations\n if (!joinTable) continue;\n\n const { name } = joinTable.inverseJoinColumn;\n\n /**\n * Load all relations that need to be updated\n */\n const oldEntriesIds = oldEntries.map((entry) => entry.id);\n const relations = await strapi.db\n .getConnection()\n .select('*')\n .from(joinTable.name)\n .whereIn(name, oldEntriesIds)\n .transacting(trx);\n\n if (relations.length === 0) continue;\n\n updates.push({ joinTable, relations });\n }\n }\n });\n\n return updates;\n};\n\n/**\n * Updates uni directional relations to target the right entries when overriding published or draft entries.\n *\n * @param oldEntries The old entries that are being overridden\n * @param newEntries The new entries that are overriding the old ones\n * @param oldRelations The relations that were previously loaded with `load` @see load\n */\nconst sync = async (\n oldEntries: { id: string; locale: string }[],\n newEntries: { id: string; locale: string }[],\n oldRelations: { joinTable: any; relations: any[] }[]\n) => {\n /**\n * Create a map of old entry ids to new entry ids\n *\n * Will be used to update the relation target ids\n */\n const newEntryByLocale = keyBy('locale', newEntries);\n const oldEntriesMap = oldEntries.reduce(\n (acc, entry) => {\n const newEntry = newEntryByLocale[entry.locale];\n if (!newEntry) return acc;\n acc[entry.id] = newEntry.id;\n return acc;\n },\n {} as Record<string, string>\n );\n\n await strapi.db.transaction(async ({ trx }) => {\n const con = strapi.db.getConnection();\n\n // Iterate old relations that are deleted and insert the new ones\n for (const { joinTable, relations } of oldRelations) {\n // Update old ids with the new ones\n const newRelations = relations.map((relation) => {\n const column = joinTable.inverseJoinColumn.name;\n const newId = oldEntriesMap[relation[column]];\n return { ...relation, [column]: newId };\n });\n\n // Insert those relations into the join table\n await con.batchInsert(joinTable.name, newRelations).transacting(trx);\n }\n });\n};\n\nexport { load, sync };\n"],"names":[],"mappings":";AAcM,MAAA,OAAO,OAAO,KAAsB,eAAiD;AACzF,QAAM,UAAU,CAAA;AAGhB,QAAM,OAAO,GAAG,YAAY,OAAO,EAAE,UAAU;AAC7C,UAAM,eAAe,OAAO,OAAO,OAAO,YAAY;AACtD,UAAM,aAAa,OAAO,OAAO,OAAO,UAAU;AAElD,eAAW,SAAS,CAAC,GAAG,cAAc,GAAG,UAAU,GAAG;AACpD,YAAM,UAAU,OAAO,GAAG,SAAS,IAAI,MAAM,GAAG;AAEhD,iBAAW,aAAa,OAAO,OAAO,QAAQ,UAAU,GAAU;AAIhE,YAAI,UAAU,SAAS;AAAY;AACnC,YAAI,UAAU,WAAW;AAAK;AAC1B,YAAA,UAAU,cAAc,UAAU;AAAU;AAChD,cAAM,YAAY,UAAU;AAE5B,YAAI,CAAC;AAAW;AAEV,cAAA,EAAE,KAAK,IAAI,UAAU;AAK3B,cAAM,gBAAgB,WAAW,IAAI,CAAC,UAAU,MAAM,EAAE;AACxD,cAAM,YAAY,MAAM,OAAO,GAC5B,gBACA,OAAO,GAAG,EACV,KAAK,UAAU,IAAI,EACnB,QAAQ,MAAM,aAAa,EAC3B,YAAY,GAAG;AAElB,YAAI,UAAU,WAAW;AAAG;AAE5B,gBAAQ,KAAK,EAAE,WAAW,UAAW,CAAA;AAAA,MACvC;AAAA,IACF;AAAA,EAAA,CACD;AAEM,SAAA;AACT;AASA,MAAM,OAAO,OACX,YACA,YACA,iBACG;AAMG,QAAA,mBAAmB,MAAM,UAAU,UAAU;AACnD,QAAM,gBAAgB,WAAW;AAAA,IAC/B,CAAC,KAAK,UAAU;AACR,YAAA,WAAW,iBAAiB,MAAM,MAAM;AAC9C,UAAI,CAAC;AAAiB,eAAA;AAClB,UAAA,MAAM,EAAE,IAAI,SAAS;AAClB,aAAA;AAAA,IACT;AAAA,IACA,CAAC;AAAA,EAAA;AAGH,QAAM,OAAO,GAAG,YAAY,OAAO,EAAE,UAAU;AACvC,UAAA,MAAM,OAAO,GAAG,cAAc;AAGpC,eAAW,EAAE,WAAW,UAAU,KAAK,cAAc;AAEnD,YAAM,eAAe,UAAU,IAAI,CAAC,aAAa;AACzC,cAAA,SAAS,UAAU,kBAAkB;AAC3C,cAAM,QAAQ,cAAc,SAAS,MAAM,CAAC;AAC5C,eAAO,EAAE,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM;AAAA,MAAA,CACvC;AAGD,YAAM,IAAI,YAAY,UAAU,MAAM,YAAY,EAAE,YAAY,GAAG;AAAA,IACrE;AAAA,EAAA,CACD;AACH;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi/core",
3
- "version": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
3
+ "version": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
4
4
  "description": "Core of Strapi",
5
5
  "homepage": "https://strapi.io",
6
6
  "bugs": {
@@ -55,15 +55,15 @@
55
55
  "@koa/cors": "5.0.0",
56
56
  "@koa/router": "12.0.1",
57
57
  "@paralleldrive/cuid2": "2.2.2",
58
- "@strapi/admin": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
59
- "@strapi/database": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
60
- "@strapi/generators": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
61
- "@strapi/logger": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
58
+ "@strapi/admin": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
59
+ "@strapi/database": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
60
+ "@strapi/generators": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
61
+ "@strapi/logger": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
62
62
  "@strapi/pack-up": "5.0.0",
63
- "@strapi/permissions": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
64
- "@strapi/types": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
65
- "@strapi/typescript-utils": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
66
- "@strapi/utils": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
63
+ "@strapi/permissions": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
64
+ "@strapi/types": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
65
+ "@strapi/typescript-utils": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
66
+ "@strapi/utils": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
67
67
  "bcryptjs": "2.4.3",
68
68
  "boxen": "5.1.2",
69
69
  "chalk": "4.1.2",
@@ -125,13 +125,13 @@
125
125
  "@types/node": "18.19.24",
126
126
  "@types/node-schedule": "2.1.7",
127
127
  "@types/statuses": "2.0.1",
128
- "eslint-config-custom": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8",
128
+ "eslint-config-custom": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c",
129
129
  "supertest": "6.3.3",
130
- "tsconfig": "0.0.0-experimental.f2351bcfa3965c60f063a492da51faa2c636eee8"
130
+ "tsconfig": "0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c"
131
131
  },
132
132
  "engines": {
133
133
  "node": ">=18.0.0 <=20.x.x",
134
134
  "npm": ">=6.0.0"
135
135
  },
136
- "gitHead": "f2351bcfa3965c60f063a492da51faa2c636eee8"
136
+ "gitHead": "f6c00790e260ea5a9b6b86abac5fea02b05d569c"
137
137
  }