@strapi/database 5.2.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entity-manager/index.d.ts.map +1 -1
- package/dist/entity-manager/morph-relations.d.ts +12 -0
- package/dist/entity-manager/morph-relations.d.ts.map +1 -1
- package/dist/entity-manager/relations-orderer.d.ts +1 -0
- package/dist/entity-manager/relations-orderer.d.ts.map +1 -1
- package/dist/index.js +223 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +224 -49
- package/dist/index.mjs.map +1 -1
- package/dist/metadata/relations.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "path";
|
|
2
2
|
import fse from "fs-extra";
|
|
3
3
|
import createDebug from "debug";
|
|
4
|
-
import _, { isNil, castArray, prop, omit, isInteger, snakeCase, partition, sumBy, cloneDeep, toString, toNumber, isString as isString$1, padCharsEnd, isArray, isPlainObject, isFinite, groupBy, pipe, mapValues, map, isEmpty, maxBy, pick, has, uniqBy, isNull, differenceWith, isEqual,
|
|
4
|
+
import _, { isNil, castArray, prop, omit, isInteger, snakeCase, partition, sumBy, cloneDeep, toString, toNumber, isString as isString$1, padCharsEnd, isArray, isPlainObject, isFinite, curry, groupBy, pipe, mapValues, map, isEmpty, maxBy, pick, has, uniqBy, isNull, compact, differenceWith, isEqual, difference, isObject, isNumber as isNumber$1, isUndefined, uniqWith } from "lodash/fp";
|
|
5
5
|
import crypto from "crypto";
|
|
6
6
|
import crypto$1 from "node:crypto";
|
|
7
7
|
import * as dateFns from "date-fns";
|
|
@@ -4878,6 +4878,25 @@ const deleteRelatedMorphOneRelationsAfterMorphToManyUpdate = async (rows, {
|
|
|
4878
4878
|
await createQueryBuilder(joinTable.name, db).delete().where({ $or: orWhere }).transacting(trx).execute();
|
|
4879
4879
|
}
|
|
4880
4880
|
};
|
|
4881
|
+
const encodePolymorphicId = (id, __type) => {
|
|
4882
|
+
return `${id}:::${__type}`;
|
|
4883
|
+
};
|
|
4884
|
+
const encodePolymorphicRelation = curry(({ idColumn, typeColumn }, relation) => {
|
|
4885
|
+
const newRelation = {
|
|
4886
|
+
...relation,
|
|
4887
|
+
[idColumn]: encodePolymorphicId(relation[idColumn], relation[typeColumn])
|
|
4888
|
+
};
|
|
4889
|
+
if (relation.position) {
|
|
4890
|
+
const { before, after } = relation.position;
|
|
4891
|
+
const __type = relation.position.__type || relation.__type;
|
|
4892
|
+
newRelation.position = { ...relation.position };
|
|
4893
|
+
if (before)
|
|
4894
|
+
newRelation.position.before = encodePolymorphicId(before, __type);
|
|
4895
|
+
if (after)
|
|
4896
|
+
newRelation.position.after = encodePolymorphicId(after, __type);
|
|
4897
|
+
}
|
|
4898
|
+
return newRelation;
|
|
4899
|
+
});
|
|
4881
4900
|
const getDocumentSiblingIdsQuery = (tableName, id) => {
|
|
4882
4901
|
const models = Array.from(strapi.db.metadata.values());
|
|
4883
4902
|
const isContentType = models.find((model) => {
|
|
@@ -5064,7 +5083,10 @@ const sortConnectArray = (connectArr, initialArr = [], strictSort = true) => {
|
|
|
5064
5083
|
if (!adjacentRelId || !relationInInitialArray[adjacentRelId] && !mapper[adjacentRelId]) {
|
|
5065
5084
|
needsSorting = true;
|
|
5066
5085
|
}
|
|
5067
|
-
|
|
5086
|
+
const existingRelation = mapper[relation.id];
|
|
5087
|
+
const hasNoComponent = existingRelation && !("__component" in existingRelation);
|
|
5088
|
+
const hasSameComponent = existingRelation && existingRelation.__component === relation.__component;
|
|
5089
|
+
if (existingRelation && (hasNoComponent || hasSameComponent)) {
|
|
5068
5090
|
throw new InvalidRelationError(
|
|
5069
5091
|
`The relation with id ${relation.id} is already connected. You cannot connect the same relation twice.`
|
|
5070
5092
|
);
|
|
@@ -5205,7 +5227,7 @@ const toId = (value) => {
|
|
|
5205
5227
|
if (isValidId(value)) {
|
|
5206
5228
|
return value;
|
|
5207
5229
|
}
|
|
5208
|
-
throw new Error(`Invalid id, expected a string or integer, got ${value}`);
|
|
5230
|
+
throw new Error(`Invalid id, expected a string or integer, got ${JSON.stringify(value)}`);
|
|
5209
5231
|
};
|
|
5210
5232
|
const toIds = (value) => castArray(value || []).map(toId);
|
|
5211
5233
|
const isValidId = (value) => isString$1(value) || isInteger(value);
|
|
@@ -5240,7 +5262,8 @@ const toAssocs = (data) => {
|
|
|
5240
5262
|
connect: toIdArray(data?.connect).map((elm) => ({
|
|
5241
5263
|
id: elm.id,
|
|
5242
5264
|
position: elm.position ? elm.position : { end: true },
|
|
5243
|
-
__pivot: elm.__pivot ?? {}
|
|
5265
|
+
__pivot: elm.__pivot ?? {},
|
|
5266
|
+
__type: elm.__type
|
|
5244
5267
|
})),
|
|
5245
5268
|
disconnect: toIdArray(data?.disconnect)
|
|
5246
5269
|
};
|
|
@@ -5515,23 +5538,33 @@ const createEntityManager = (db) => {
|
|
|
5515
5538
|
const { joinTable } = attribute;
|
|
5516
5539
|
const { joinColumn, morphColumn } = joinTable;
|
|
5517
5540
|
const { idColumn, typeColumn, typeField = "__type" } = morphColumn;
|
|
5518
|
-
if (isEmpty(cleanRelationData.set)) {
|
|
5541
|
+
if (isEmpty(cleanRelationData.set) && isEmpty(cleanRelationData.connect)) {
|
|
5519
5542
|
continue;
|
|
5520
5543
|
}
|
|
5521
|
-
const
|
|
5544
|
+
const dataset = cleanRelationData.set || cleanRelationData.connect || [];
|
|
5545
|
+
const rows = dataset.map((data2, idx) => ({
|
|
5522
5546
|
[joinColumn.name]: id,
|
|
5523
5547
|
[idColumn.name]: data2.id,
|
|
5524
5548
|
[typeColumn.name]: data2[typeField],
|
|
5525
5549
|
..."on" in joinTable && joinTable.on || {},
|
|
5526
5550
|
...data2.__pivot || {},
|
|
5527
5551
|
order: idx + 1
|
|
5528
|
-
}))
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5552
|
+
}));
|
|
5553
|
+
const orderMap = relationsOrderer(
|
|
5554
|
+
[],
|
|
5555
|
+
morphColumn.idColumn.name,
|
|
5556
|
+
"order",
|
|
5557
|
+
true
|
|
5558
|
+
// Always make a strict connect when inserting
|
|
5559
|
+
).connect(
|
|
5560
|
+
// Merge id & __type to get a single id key
|
|
5561
|
+
dataset.map(encodePolymorphicRelation({ idColumn: "id", typeColumn: "__type" }))
|
|
5562
|
+
).get().reduce((acc, rel, idx) => ({ ...acc, [rel.id]: idx }), {});
|
|
5563
|
+
rows.forEach((row) => {
|
|
5564
|
+
const rowId = row[morphColumn.idColumn.name];
|
|
5565
|
+
const rowType = row[morphColumn.typeColumn.name];
|
|
5566
|
+
const encodedId = encodePolymorphicId(rowId, rowType);
|
|
5567
|
+
row.order = orderMap[encodedId];
|
|
5535
5568
|
});
|
|
5536
5569
|
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5537
5570
|
continue;
|
|
@@ -5631,25 +5664,67 @@ const createEntityManager = (db) => {
|
|
|
5631
5664
|
const { joinTable } = targetAttribute;
|
|
5632
5665
|
const { joinColumn, morphColumn } = joinTable;
|
|
5633
5666
|
const { idColumn, typeColumn } = morphColumn;
|
|
5667
|
+
const hasSet = !isEmpty(cleanRelationData.set);
|
|
5668
|
+
const hasConnect = !isEmpty(cleanRelationData.connect);
|
|
5669
|
+
const hasDisconnect = !isEmpty(cleanRelationData.disconnect);
|
|
5670
|
+
if (!hasSet && (hasConnect || hasDisconnect)) {
|
|
5671
|
+
const idsToDelete = [
|
|
5672
|
+
...cleanRelationData.disconnect || [],
|
|
5673
|
+
...cleanRelationData.connect || []
|
|
5674
|
+
];
|
|
5675
|
+
if (!isEmpty(idsToDelete)) {
|
|
5676
|
+
const where = {
|
|
5677
|
+
$or: idsToDelete.map((item) => {
|
|
5678
|
+
return {
|
|
5679
|
+
[idColumn.name]: id,
|
|
5680
|
+
[typeColumn.name]: uid,
|
|
5681
|
+
[joinColumn.name]: item.id,
|
|
5682
|
+
...joinTable.on || {},
|
|
5683
|
+
field: attributeName
|
|
5684
|
+
};
|
|
5685
|
+
})
|
|
5686
|
+
};
|
|
5687
|
+
await this.createQueryBuilder(joinTable.name).delete().where(where).transacting(trx).execute();
|
|
5688
|
+
}
|
|
5689
|
+
if (hasConnect) {
|
|
5690
|
+
const start = await this.createQueryBuilder(joinTable.name).where({
|
|
5691
|
+
[idColumn.name]: id,
|
|
5692
|
+
[typeColumn.name]: uid,
|
|
5693
|
+
...joinTable.on || {},
|
|
5694
|
+
...data.__pivot || {}
|
|
5695
|
+
}).max("order").first().transacting(trx).execute();
|
|
5696
|
+
const startOrder = start?.max || 0;
|
|
5697
|
+
const rows = (cleanRelationData.connect ?? []).map((data2, idx) => ({
|
|
5698
|
+
[joinColumn.name]: data2.id,
|
|
5699
|
+
[idColumn.name]: id,
|
|
5700
|
+
[typeColumn.name]: uid,
|
|
5701
|
+
...joinTable.on || {},
|
|
5702
|
+
...data2.__pivot || {},
|
|
5703
|
+
order: startOrder + idx + 1,
|
|
5704
|
+
field: attributeName
|
|
5705
|
+
}));
|
|
5706
|
+
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5707
|
+
}
|
|
5708
|
+
continue;
|
|
5709
|
+
}
|
|
5634
5710
|
await this.createQueryBuilder(joinTable.name).delete().where({
|
|
5635
5711
|
[idColumn.name]: id,
|
|
5636
5712
|
[typeColumn.name]: uid,
|
|
5637
5713
|
...joinTable.on || {},
|
|
5638
5714
|
field: attributeName
|
|
5639
5715
|
}).transacting(trx).execute();
|
|
5640
|
-
if (
|
|
5641
|
-
|
|
5716
|
+
if (hasSet) {
|
|
5717
|
+
const rows = (cleanRelationData.set ?? []).map((data2, idx) => ({
|
|
5718
|
+
[joinColumn.name]: data2.id,
|
|
5719
|
+
[idColumn.name]: id,
|
|
5720
|
+
[typeColumn.name]: uid,
|
|
5721
|
+
...joinTable.on || {},
|
|
5722
|
+
...data2.__pivot || {},
|
|
5723
|
+
order: idx + 1,
|
|
5724
|
+
field: attributeName
|
|
5725
|
+
}));
|
|
5726
|
+
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5642
5727
|
}
|
|
5643
|
-
const rows = cleanRelationData.set?.map((data2, idx) => ({
|
|
5644
|
-
[joinColumn.name]: data2.id,
|
|
5645
|
-
[idColumn.name]: id,
|
|
5646
|
-
[typeColumn.name]: uid,
|
|
5647
|
-
...joinTable.on || {},
|
|
5648
|
-
...data2.__pivot || {},
|
|
5649
|
-
order: idx + 1,
|
|
5650
|
-
field: attributeName
|
|
5651
|
-
}));
|
|
5652
|
-
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5653
5728
|
}
|
|
5654
5729
|
continue;
|
|
5655
5730
|
}
|
|
@@ -5660,29 +5735,129 @@ const createEntityManager = (db) => {
|
|
|
5660
5735
|
const { joinTable } = attribute;
|
|
5661
5736
|
const { joinColumn, morphColumn } = joinTable;
|
|
5662
5737
|
const { idColumn, typeColumn, typeField = "__type" } = morphColumn;
|
|
5663
|
-
|
|
5664
|
-
|
|
5665
|
-
|
|
5666
|
-
|
|
5667
|
-
|
|
5738
|
+
const hasSet = !isEmpty(cleanRelationData.set);
|
|
5739
|
+
const hasConnect = !isEmpty(cleanRelationData.connect);
|
|
5740
|
+
const hasDisconnect = !isEmpty(cleanRelationData.disconnect);
|
|
5741
|
+
if (!hasSet && (hasConnect || hasDisconnect)) {
|
|
5742
|
+
const idsToDelete = [
|
|
5743
|
+
...cleanRelationData.disconnect || [],
|
|
5744
|
+
...cleanRelationData.connect || []
|
|
5745
|
+
];
|
|
5746
|
+
const rowsToDelete = [
|
|
5747
|
+
...(cleanRelationData.disconnect ?? []).map((data2, idx) => ({
|
|
5748
|
+
[joinColumn.name]: id,
|
|
5749
|
+
[idColumn.name]: data2.id,
|
|
5750
|
+
[typeColumn.name]: data2[typeField],
|
|
5751
|
+
..."on" in joinTable && joinTable.on || {},
|
|
5752
|
+
...data2.__pivot || {},
|
|
5753
|
+
order: idx + 1
|
|
5754
|
+
})),
|
|
5755
|
+
...(cleanRelationData.connect ?? []).map((data2, idx) => ({
|
|
5756
|
+
[joinColumn.name]: id,
|
|
5757
|
+
[idColumn.name]: data2.id,
|
|
5758
|
+
// @ts-expect-error TODO
|
|
5759
|
+
[typeColumn.name]: data2[typeField],
|
|
5760
|
+
..."on" in joinTable && joinTable.on || {},
|
|
5761
|
+
...data2.__pivot || {},
|
|
5762
|
+
order: idx + 1
|
|
5763
|
+
}))
|
|
5764
|
+
];
|
|
5765
|
+
const adjacentRelations = await this.createQueryBuilder(joinTable.name).where({
|
|
5766
|
+
$or: [
|
|
5767
|
+
{
|
|
5768
|
+
[joinColumn.name]: id,
|
|
5769
|
+
[idColumn.name]: {
|
|
5770
|
+
$in: compact(
|
|
5771
|
+
cleanRelationData.connect?.map(
|
|
5772
|
+
(r) => r.position?.after || r.position?.before
|
|
5773
|
+
)
|
|
5774
|
+
)
|
|
5775
|
+
}
|
|
5776
|
+
},
|
|
5777
|
+
{
|
|
5778
|
+
[joinColumn.name]: id,
|
|
5779
|
+
order: this.createQueryBuilder(joinTable.name).max("order").where({ [joinColumn.name]: id }).where(joinTable.on || {}).transacting(trx).getKnexQuery()
|
|
5780
|
+
}
|
|
5781
|
+
]
|
|
5782
|
+
}).where(joinTable.on || {}).transacting(trx).execute();
|
|
5783
|
+
if (!isEmpty(idsToDelete)) {
|
|
5784
|
+
const where = {
|
|
5785
|
+
$or: idsToDelete.map((item) => {
|
|
5786
|
+
return {
|
|
5787
|
+
[idColumn.name]: item.id,
|
|
5788
|
+
[typeColumn.name]: item[typeField],
|
|
5789
|
+
[joinColumn.name]: id,
|
|
5790
|
+
...joinTable.on || {}
|
|
5791
|
+
};
|
|
5792
|
+
})
|
|
5793
|
+
};
|
|
5794
|
+
await this.createQueryBuilder(joinTable.name).delete().where(where).transacting(trx).execute();
|
|
5795
|
+
await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rowsToDelete, {
|
|
5796
|
+
uid,
|
|
5797
|
+
attributeName,
|
|
5798
|
+
joinTable,
|
|
5799
|
+
db,
|
|
5800
|
+
transaction: trx
|
|
5801
|
+
});
|
|
5802
|
+
}
|
|
5803
|
+
if (hasConnect) {
|
|
5804
|
+
const dataset = cleanRelationData.connect || [];
|
|
5805
|
+
const rows = dataset.map((data2) => ({
|
|
5806
|
+
[joinColumn.name]: id,
|
|
5807
|
+
[idColumn.name]: data2.id,
|
|
5808
|
+
[typeColumn.name]: data2[typeField],
|
|
5809
|
+
...joinTable.on || {},
|
|
5810
|
+
...data2.__pivot || {},
|
|
5811
|
+
field: attributeName
|
|
5812
|
+
}));
|
|
5813
|
+
const orderMap = relationsOrderer(
|
|
5814
|
+
// Merge id & __type to get a single id key
|
|
5815
|
+
adjacentRelations.map(
|
|
5816
|
+
encodePolymorphicRelation({
|
|
5817
|
+
idColumn: idColumn.name,
|
|
5818
|
+
typeColumn: typeColumn.name
|
|
5819
|
+
})
|
|
5820
|
+
),
|
|
5821
|
+
idColumn.name,
|
|
5822
|
+
"order",
|
|
5823
|
+
cleanRelationData.options?.strict
|
|
5824
|
+
).connect(
|
|
5825
|
+
// Merge id & __type to get a single id key
|
|
5826
|
+
dataset.map(encodePolymorphicRelation({ idColumn: "id", typeColumn: "__type" }))
|
|
5827
|
+
).getOrderMap();
|
|
5828
|
+
rows.forEach((row) => {
|
|
5829
|
+
const rowId = row[idColumn.name];
|
|
5830
|
+
const rowType = row[typeColumn.name];
|
|
5831
|
+
const encodedId = encodePolymorphicId(rowId, rowType);
|
|
5832
|
+
row.order = orderMap[encodedId];
|
|
5833
|
+
});
|
|
5834
|
+
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5835
|
+
}
|
|
5668
5836
|
continue;
|
|
5669
5837
|
}
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5838
|
+
if (hasSet) {
|
|
5839
|
+
await this.createQueryBuilder(joinTable.name).delete().where({
|
|
5840
|
+
[joinColumn.name]: id,
|
|
5841
|
+
...joinTable.on || {}
|
|
5842
|
+
}).transacting(trx).execute();
|
|
5843
|
+
const rows = (cleanRelationData.set ?? []).map((data2, idx) => ({
|
|
5844
|
+
[joinColumn.name]: id,
|
|
5845
|
+
[idColumn.name]: data2.id,
|
|
5846
|
+
[typeColumn.name]: data2[typeField],
|
|
5847
|
+
field: attributeName,
|
|
5848
|
+
...joinTable.on || {},
|
|
5849
|
+
...data2.__pivot || {},
|
|
5850
|
+
order: idx + 1
|
|
5851
|
+
}));
|
|
5852
|
+
await deleteRelatedMorphOneRelationsAfterMorphToManyUpdate(rows, {
|
|
5853
|
+
uid,
|
|
5854
|
+
attributeName,
|
|
5855
|
+
joinTable,
|
|
5856
|
+
db,
|
|
5857
|
+
transaction: trx
|
|
5858
|
+
});
|
|
5859
|
+
await this.createQueryBuilder(joinTable.name).insert(rows).transacting(trx).execute();
|
|
5860
|
+
}
|
|
5686
5861
|
continue;
|
|
5687
5862
|
}
|
|
5688
5863
|
if ("joinColumn" in attribute && attribute.joinColumn && attribute.owner) {
|
|
@@ -6107,7 +6282,7 @@ const QUERIES = {
|
|
|
6107
6282
|
FROM :tableName:
|
|
6108
6283
|
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
|
|
6109
6284
|
WHERE document_id IS NULL
|
|
6110
|
-
GROUP BY :tableName:.id, :joinColumn:
|
|
6285
|
+
GROUP BY :tableName:.id, :joinTableName:.:joinColumn:
|
|
6111
6286
|
LIMIT 1;
|
|
6112
6287
|
`,
|
|
6113
6288
|
params
|
|
@@ -6121,7 +6296,7 @@ const QUERIES = {
|
|
|
6121
6296
|
FROM :tableName:
|
|
6122
6297
|
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
|
|
6123
6298
|
WHERE document_id IS NULL
|
|
6124
|
-
GROUP BY :tableName:.id, :joinColumn:
|
|
6299
|
+
GROUP BY :tableName:.id, :joinTableName:.:joinColumn:
|
|
6125
6300
|
LIMIT 1;
|
|
6126
6301
|
`,
|
|
6127
6302
|
params
|
|
@@ -6135,7 +6310,7 @@ const QUERIES = {
|
|
|
6135
6310
|
FROM :tableName:
|
|
6136
6311
|
LEFT JOIN :joinTableName: ON :tableName:.id = :joinTableName:.:joinColumn:
|
|
6137
6312
|
WHERE document_id IS NULL
|
|
6138
|
-
GROUP BY :joinColumn:
|
|
6313
|
+
GROUP BY :joinTableName:.:joinColumn:
|
|
6139
6314
|
LIMIT 1;
|
|
6140
6315
|
`,
|
|
6141
6316
|
params
|