@stackbit/cms-core 0.0.19-alpha.0 → 0.0.19-alpha.1
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/content-source-interface.d.ts +25 -1
- package/dist/content-source-interface.d.ts.map +1 -1
- package/dist/content-store-types.d.ts +6 -2
- package/dist/content-store-types.d.ts.map +1 -1
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +239 -186
- package/dist/content-store.js.map +1 -1
- package/package.json +2 -2
- package/src/content-source-interface.ts +36 -5
- package/src/content-store-types.ts +13 -3
- package/src/content-store.ts +265 -217
package/src/content-store.ts
CHANGED
|
@@ -17,10 +17,7 @@ import {
|
|
|
17
17
|
} from '@stackbit/sdk';
|
|
18
18
|
import { mapPromise, omitByNil } from '@stackbit/utils';
|
|
19
19
|
import * as CSITypes from './content-source-interface';
|
|
20
|
-
import {
|
|
21
|
-
DocumentObjectField,
|
|
22
|
-
isLocalizedField
|
|
23
|
-
} from './content-source-interface';
|
|
20
|
+
import { isLocalizedField } from './content-source-interface';
|
|
24
21
|
import * as ContentStoreTypes from './content-store-types';
|
|
25
22
|
import { IMAGE_MODEL } from './common/common-schema';
|
|
26
23
|
import { Timer } from './utils/timer';
|
|
@@ -411,7 +408,7 @@ export class ContentStore {
|
|
|
411
408
|
const dataIndex = contentSourceData.documents.findIndex((existingDoc) => existingDoc.srcObjectId === document.srcObjectId);
|
|
412
409
|
if (dataIndex === -1) {
|
|
413
410
|
contentSourceData.documents.push(document);
|
|
414
|
-
contentSourceData.csiDocuments.push(csiDocument)
|
|
411
|
+
contentSourceData.csiDocuments.push(csiDocument);
|
|
415
412
|
} else {
|
|
416
413
|
// the indexes of documents and csiDocuments are always the same as they are always updated at the same time
|
|
417
414
|
contentSourceData.documents.splice(dataIndex, 1, document);
|
|
@@ -1283,30 +1280,34 @@ function mapCSIDocumentToStoreDocument({
|
|
|
1283
1280
|
fields: mapCSIFieldsToStoreFields({
|
|
1284
1281
|
csiDocumentFields: csiDocument.fields,
|
|
1285
1282
|
modelFields: model.fields ?? [],
|
|
1286
|
-
|
|
1287
|
-
|
|
1283
|
+
context: {
|
|
1284
|
+
modelMap,
|
|
1285
|
+
defaultLocaleCode
|
|
1286
|
+
}
|
|
1288
1287
|
})
|
|
1289
1288
|
};
|
|
1290
1289
|
}
|
|
1291
1290
|
|
|
1291
|
+
type MapContext = {
|
|
1292
|
+
modelMap: Record<string, Model>;
|
|
1293
|
+
defaultLocaleCode?: string;
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1292
1296
|
function mapCSIFieldsToStoreFields({
|
|
1293
1297
|
csiDocumentFields,
|
|
1294
1298
|
modelFields,
|
|
1295
|
-
|
|
1296
|
-
defaultLocaleCode
|
|
1299
|
+
context
|
|
1297
1300
|
}: {
|
|
1298
1301
|
csiDocumentFields: Record<string, CSITypes.DocumentField>;
|
|
1299
1302
|
modelFields: Field[];
|
|
1300
|
-
|
|
1301
|
-
defaultLocaleCode?: string;
|
|
1303
|
+
context: MapContext;
|
|
1302
1304
|
}): Record<string, ContentStoreTypes.DocumentField> {
|
|
1303
1305
|
return modelFields.reduce((result: Record<string, ContentStoreTypes.DocumentField>, modelField) => {
|
|
1304
1306
|
const csiDocumentField = csiDocumentFields[modelField.name];
|
|
1305
|
-
const docField =
|
|
1307
|
+
const docField = mapCSIFieldToStoreField({
|
|
1306
1308
|
csiDocumentField,
|
|
1307
1309
|
modelField,
|
|
1308
|
-
|
|
1309
|
-
defaultLocaleCode
|
|
1310
|
+
context
|
|
1310
1311
|
});
|
|
1311
1312
|
docField.label = modelField.label;
|
|
1312
1313
|
result[modelField.name] = docField;
|
|
@@ -1314,16 +1315,14 @@ function mapCSIFieldsToStoreFields({
|
|
|
1314
1315
|
}, {});
|
|
1315
1316
|
}
|
|
1316
1317
|
|
|
1317
|
-
function
|
|
1318
|
+
function mapCSIFieldToStoreField({
|
|
1318
1319
|
csiDocumentField,
|
|
1319
1320
|
modelField,
|
|
1320
|
-
|
|
1321
|
-
defaultLocaleCode
|
|
1321
|
+
context
|
|
1322
1322
|
}: {
|
|
1323
1323
|
csiDocumentField: CSITypes.DocumentField | undefined;
|
|
1324
1324
|
modelField: FieldSpecificProps;
|
|
1325
|
-
|
|
1326
|
-
defaultLocaleCode?: string;
|
|
1325
|
+
context: MapContext;
|
|
1327
1326
|
}): ContentStoreTypes.DocumentField {
|
|
1328
1327
|
if (!csiDocumentField) {
|
|
1329
1328
|
const isUnset = ['object', 'model', 'reference', 'richText', 'markdown', 'image', 'file', 'json'].includes(modelField.type);
|
|
@@ -1336,11 +1335,11 @@ function mapSourceFieldToStoreField({
|
|
|
1336
1335
|
// TODO: check if need to add "options" to "enum" and subtype/min/max to "number"
|
|
1337
1336
|
switch (modelField.type) {
|
|
1338
1337
|
case 'object':
|
|
1339
|
-
return mapObjectField(csiDocumentField as CSITypes.DocumentObjectField, modelField,
|
|
1338
|
+
return mapObjectField(csiDocumentField as CSITypes.DocumentObjectField, modelField, context);
|
|
1340
1339
|
case 'model':
|
|
1341
|
-
return mapModelField(csiDocumentField as CSITypes.DocumentModelField, modelField,
|
|
1340
|
+
return mapModelField(csiDocumentField as CSITypes.DocumentModelField, modelField, context);
|
|
1342
1341
|
case 'list':
|
|
1343
|
-
return mapListField(csiDocumentField as CSITypes.DocumentListField, modelField,
|
|
1342
|
+
return mapListField(csiDocumentField as CSITypes.DocumentListField, modelField, context);
|
|
1344
1343
|
case 'richText':
|
|
1345
1344
|
return mapRichTextField(csiDocumentField as CSITypes.DocumentRichTextField);
|
|
1346
1345
|
case 'markdown':
|
|
@@ -1353,18 +1352,16 @@ function mapSourceFieldToStoreField({
|
|
|
1353
1352
|
function mapObjectField(
|
|
1354
1353
|
csiDocumentField: CSITypes.DocumentObjectField,
|
|
1355
1354
|
modelField: FieldObjectProps,
|
|
1356
|
-
|
|
1357
|
-
defaultLocaleCode?: string
|
|
1355
|
+
context: MapContext
|
|
1358
1356
|
): ContentStoreTypes.DocumentObjectField {
|
|
1359
1357
|
if (!isLocalizedField(csiDocumentField)) {
|
|
1360
1358
|
return {
|
|
1361
1359
|
type: csiDocumentField.type,
|
|
1362
|
-
srcObjectLabel: getObjectLabel(csiDocumentField.fields ?? {}, modelField ?? [], defaultLocaleCode),
|
|
1360
|
+
srcObjectLabel: getObjectLabel(csiDocumentField.fields ?? {}, modelField ?? [], context.defaultLocaleCode),
|
|
1363
1361
|
fields: mapCSIFieldsToStoreFields({
|
|
1364
1362
|
csiDocumentFields: csiDocumentField.fields ?? {},
|
|
1365
1363
|
modelFields: modelField.fields ?? [],
|
|
1366
|
-
|
|
1367
|
-
defaultLocaleCode
|
|
1364
|
+
context
|
|
1368
1365
|
})
|
|
1369
1366
|
};
|
|
1370
1367
|
}
|
|
@@ -1378,32 +1375,25 @@ function mapObjectField(
|
|
|
1378
1375
|
fields: mapCSIFieldsToStoreFields({
|
|
1379
1376
|
csiDocumentFields: locale.fields ?? {},
|
|
1380
1377
|
modelFields: modelField.fields ?? [],
|
|
1381
|
-
|
|
1382
|
-
defaultLocaleCode
|
|
1378
|
+
context
|
|
1383
1379
|
})
|
|
1384
1380
|
};
|
|
1385
1381
|
})
|
|
1386
1382
|
};
|
|
1387
1383
|
}
|
|
1388
1384
|
|
|
1389
|
-
function mapModelField(
|
|
1390
|
-
csiDocumentField: CSITypes.DocumentModelField,
|
|
1391
|
-
modelField: FieldModelProps,
|
|
1392
|
-
modelMap: Record<string, Model>,
|
|
1393
|
-
defaultLocaleCode?: string
|
|
1394
|
-
): ContentStoreTypes.DocumentModelField {
|
|
1385
|
+
function mapModelField(csiDocumentField: CSITypes.DocumentModelField, modelField: FieldModelProps, context: MapContext): ContentStoreTypes.DocumentModelField {
|
|
1395
1386
|
if (!isLocalizedField(csiDocumentField)) {
|
|
1396
|
-
const model = modelMap[csiDocumentField.modelName]!;
|
|
1387
|
+
const model = context.modelMap[csiDocumentField.modelName]!;
|
|
1397
1388
|
return {
|
|
1398
1389
|
type: csiDocumentField.type,
|
|
1399
|
-
srcObjectLabel: getObjectLabel(csiDocumentField.fields ?? {}, model, defaultLocaleCode),
|
|
1390
|
+
srcObjectLabel: getObjectLabel(csiDocumentField.fields ?? {}, model, context.defaultLocaleCode),
|
|
1400
1391
|
srcModelName: csiDocumentField.modelName,
|
|
1401
1392
|
srcModelLabel: model.label ?? _.startCase(model.name),
|
|
1402
1393
|
fields: mapCSIFieldsToStoreFields({
|
|
1403
1394
|
csiDocumentFields: csiDocumentField.fields ?? {},
|
|
1404
1395
|
modelFields: model.fields ?? [],
|
|
1405
|
-
|
|
1406
|
-
defaultLocaleCode
|
|
1396
|
+
context
|
|
1407
1397
|
})
|
|
1408
1398
|
};
|
|
1409
1399
|
}
|
|
@@ -1411,7 +1401,7 @@ function mapModelField(
|
|
|
1411
1401
|
type: csiDocumentField.type,
|
|
1412
1402
|
localized: true,
|
|
1413
1403
|
locales: _.mapValues(csiDocumentField.locales, (locale) => {
|
|
1414
|
-
const model = modelMap[locale.modelName]!;
|
|
1404
|
+
const model = context.modelMap[locale.modelName]!;
|
|
1415
1405
|
return {
|
|
1416
1406
|
locale: locale.locale,
|
|
1417
1407
|
srcObjectLabel: getObjectLabel(locale.fields ?? {}, model, locale.locale),
|
|
@@ -1420,29 +1410,22 @@ function mapModelField(
|
|
|
1420
1410
|
fields: mapCSIFieldsToStoreFields({
|
|
1421
1411
|
csiDocumentFields: locale.fields ?? {},
|
|
1422
1412
|
modelFields: model.fields ?? [],
|
|
1423
|
-
|
|
1424
|
-
defaultLocaleCode
|
|
1413
|
+
context
|
|
1425
1414
|
})
|
|
1426
1415
|
};
|
|
1427
1416
|
})
|
|
1428
1417
|
};
|
|
1429
1418
|
}
|
|
1430
1419
|
|
|
1431
|
-
function mapListField(
|
|
1432
|
-
csiDocumentField: CSITypes.DocumentListField,
|
|
1433
|
-
modelField: FieldListProps,
|
|
1434
|
-
modelMap: Record<string, Model>,
|
|
1435
|
-
defaultLocaleCode?: string
|
|
1436
|
-
): ContentStoreTypes.DocumentListField {
|
|
1420
|
+
function mapListField(csiDocumentField: CSITypes.DocumentListField, modelField: FieldListProps, context: MapContext): ContentStoreTypes.DocumentListField {
|
|
1437
1421
|
if (!isLocalizedField(csiDocumentField)) {
|
|
1438
1422
|
return {
|
|
1439
1423
|
type: csiDocumentField.type,
|
|
1440
1424
|
items: csiDocumentField.items.map((item) =>
|
|
1441
|
-
|
|
1425
|
+
mapCSIFieldToStoreField({
|
|
1442
1426
|
csiDocumentField: item,
|
|
1443
1427
|
modelField: modelField.items ?? { type: 'string' },
|
|
1444
|
-
|
|
1445
|
-
defaultLocaleCode
|
|
1428
|
+
context
|
|
1446
1429
|
})
|
|
1447
1430
|
)
|
|
1448
1431
|
};
|
|
@@ -1454,11 +1437,10 @@ function mapListField(
|
|
|
1454
1437
|
return {
|
|
1455
1438
|
locale: locale.locale,
|
|
1456
1439
|
items: (locale.items ?? []).map((item) =>
|
|
1457
|
-
|
|
1440
|
+
mapCSIFieldToStoreField({
|
|
1458
1441
|
csiDocumentField: item,
|
|
1459
1442
|
modelField: modelField.items ?? { type: 'string' },
|
|
1460
|
-
|
|
1461
|
-
defaultLocaleCode
|
|
1443
|
+
context
|
|
1462
1444
|
})
|
|
1463
1445
|
)
|
|
1464
1446
|
};
|
|
@@ -1772,166 +1754,12 @@ async function createNestedObjectRecursively({
|
|
|
1772
1754
|
userContext: unknown;
|
|
1773
1755
|
contentSourceInstance: CSITypes.ContentSourceInterface;
|
|
1774
1756
|
}): Promise<{
|
|
1775
|
-
fields: Record<string, CSITypes.
|
|
1757
|
+
fields: Record<string, CSITypes.UpdateOperationField>;
|
|
1776
1758
|
newRefDocuments: CSITypes.Document[];
|
|
1777
1759
|
}> {
|
|
1778
|
-
const createNestedField = async ({
|
|
1779
|
-
value,
|
|
1780
|
-
modelField,
|
|
1781
|
-
fieldPath
|
|
1782
|
-
}: {
|
|
1783
|
-
value: any;
|
|
1784
|
-
modelField: FieldSpecificProps;
|
|
1785
|
-
fieldPath: (string | number)[];
|
|
1786
|
-
}): Promise<{ field: CSITypes.DocumentFieldNonLocalized; newRefDocuments: CSITypes.Document[] }> => {
|
|
1787
|
-
if (modelField.type === 'object') {
|
|
1788
|
-
const result = await createNestedObjectRecursively({
|
|
1789
|
-
object: value,
|
|
1790
|
-
modelFields: modelField.fields,
|
|
1791
|
-
fieldPath,
|
|
1792
|
-
modelMap,
|
|
1793
|
-
locale,
|
|
1794
|
-
userContext,
|
|
1795
|
-
contentSourceInstance
|
|
1796
|
-
});
|
|
1797
|
-
return {
|
|
1798
|
-
field: {
|
|
1799
|
-
type: 'object',
|
|
1800
|
-
fields: result.fields
|
|
1801
|
-
},
|
|
1802
|
-
newRefDocuments: result.newRefDocuments
|
|
1803
|
-
};
|
|
1804
|
-
} else if (modelField.type === 'model') {
|
|
1805
|
-
let { $$type, ...rest } = value;
|
|
1806
|
-
const modelNames = modelField.models;
|
|
1807
|
-
// for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
|
|
1808
|
-
// the 'type' property in default values
|
|
1809
|
-
if (!$$type && 'type' in rest) {
|
|
1810
|
-
$$type = rest.type;
|
|
1811
|
-
rest = _.omit(rest, 'type');
|
|
1812
|
-
}
|
|
1813
|
-
const modelName = $$type ?? (modelNames.length === 1 ? modelNames[0] : null);
|
|
1814
|
-
if (!modelName) {
|
|
1815
|
-
throw new Error(`no $$type was specified for nested model`);
|
|
1816
|
-
}
|
|
1817
|
-
const model = modelMap[modelName];
|
|
1818
|
-
if (!model) {
|
|
1819
|
-
throw new Error(`no model with name '${modelName}' was found`);
|
|
1820
|
-
}
|
|
1821
|
-
const result = await createNestedObjectRecursively({
|
|
1822
|
-
object: rest,
|
|
1823
|
-
modelFields: model.fields ?? [],
|
|
1824
|
-
fieldPath,
|
|
1825
|
-
modelMap,
|
|
1826
|
-
locale,
|
|
1827
|
-
userContext,
|
|
1828
|
-
contentSourceInstance
|
|
1829
|
-
});
|
|
1830
|
-
return {
|
|
1831
|
-
field: {
|
|
1832
|
-
type: 'model',
|
|
1833
|
-
modelName: modelName,
|
|
1834
|
-
fields: result.fields
|
|
1835
|
-
},
|
|
1836
|
-
newRefDocuments: result.newRefDocuments
|
|
1837
|
-
};
|
|
1838
|
-
} else if (modelField.type === 'image') {
|
|
1839
|
-
let refId: string | undefined;
|
|
1840
|
-
if (_.isPlainObject(value)) {
|
|
1841
|
-
refId = value.$$ref;
|
|
1842
|
-
} else {
|
|
1843
|
-
refId = value;
|
|
1844
|
-
}
|
|
1845
|
-
if (!refId) {
|
|
1846
|
-
throw new Error(`reference field must specify a value`);
|
|
1847
|
-
}
|
|
1848
|
-
return {
|
|
1849
|
-
field: {
|
|
1850
|
-
type: 'reference',
|
|
1851
|
-
refType: 'asset',
|
|
1852
|
-
refId: refId
|
|
1853
|
-
},
|
|
1854
|
-
newRefDocuments: []
|
|
1855
|
-
};
|
|
1856
|
-
} else if (modelField.type === 'reference') {
|
|
1857
|
-
let { $$ref: refId = null, $$type: modelName = null, ...rest } = _.isPlainObject(value) ? value : { $$ref: value };
|
|
1858
|
-
if (refId) {
|
|
1859
|
-
return {
|
|
1860
|
-
field: {
|
|
1861
|
-
type: 'reference',
|
|
1862
|
-
refType: 'document',
|
|
1863
|
-
refId: refId
|
|
1864
|
-
},
|
|
1865
|
-
newRefDocuments: []
|
|
1866
|
-
};
|
|
1867
|
-
} else {
|
|
1868
|
-
const modelNames = modelField.models;
|
|
1869
|
-
if (!modelName) {
|
|
1870
|
-
// for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
|
|
1871
|
-
// the 'type' property in default values
|
|
1872
|
-
if ('type' in rest) {
|
|
1873
|
-
modelName = rest.type;
|
|
1874
|
-
rest = _.omit(rest, 'type');
|
|
1875
|
-
} else if (modelNames.length === 1) {
|
|
1876
|
-
modelName = modelNames[0];
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
const model = modelMap[modelName];
|
|
1880
|
-
if (!model) {
|
|
1881
|
-
throw new Error(`no model with name '${modelName}' was found`);
|
|
1882
|
-
}
|
|
1883
|
-
const { document, newRefDocuments } = await createDocumentRecursively({
|
|
1884
|
-
object: rest,
|
|
1885
|
-
model: model,
|
|
1886
|
-
modelMap,
|
|
1887
|
-
locale,
|
|
1888
|
-
userContext,
|
|
1889
|
-
contentSourceInstance
|
|
1890
|
-
});
|
|
1891
|
-
return {
|
|
1892
|
-
field: {
|
|
1893
|
-
type: 'reference',
|
|
1894
|
-
refType: 'document',
|
|
1895
|
-
refId: document.id
|
|
1896
|
-
},
|
|
1897
|
-
newRefDocuments: [document, ...newRefDocuments]
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
} else if (modelField.type === 'list') {
|
|
1901
|
-
if (!Array.isArray(value)) {
|
|
1902
|
-
throw new Error(`value for list field must be array`);
|
|
1903
|
-
}
|
|
1904
|
-
const itemsField = modelField.items;
|
|
1905
|
-
if (!itemsField) {
|
|
1906
|
-
throw new Error(`list field does not define items`);
|
|
1907
|
-
}
|
|
1908
|
-
const arrayResult = await mapPromise(value, async (item, index) => {
|
|
1909
|
-
return createNestedField({
|
|
1910
|
-
value: item,
|
|
1911
|
-
modelField: itemsField,
|
|
1912
|
-
fieldPath: fieldPath.concat(index)
|
|
1913
|
-
});
|
|
1914
|
-
});
|
|
1915
|
-
return {
|
|
1916
|
-
field: {
|
|
1917
|
-
type: 'list',
|
|
1918
|
-
items: arrayResult.map((result) => result.field)
|
|
1919
|
-
},
|
|
1920
|
-
newRefDocuments: arrayResult.reduce((result: CSITypes.Document[], { newRefDocuments }) => result.concat(newRefDocuments), [])
|
|
1921
|
-
};
|
|
1922
|
-
}
|
|
1923
|
-
return {
|
|
1924
|
-
field: {
|
|
1925
|
-
type: modelField.type,
|
|
1926
|
-
value: value
|
|
1927
|
-
} as CSITypes.DocumentFieldNonLocalized,
|
|
1928
|
-
newRefDocuments: []
|
|
1929
|
-
};
|
|
1930
|
-
};
|
|
1931
|
-
|
|
1932
1760
|
object = object ?? {};
|
|
1933
1761
|
const result: {
|
|
1934
|
-
fields: Record<string, CSITypes.
|
|
1762
|
+
fields: Record<string, CSITypes.UpdateOperationField>;
|
|
1935
1763
|
newRefDocuments: CSITypes.Document[];
|
|
1936
1764
|
} = {
|
|
1937
1765
|
fields: {},
|
|
@@ -1953,7 +1781,11 @@ async function createNestedObjectRecursively({
|
|
|
1953
1781
|
const fieldResult = await createNestedField({
|
|
1954
1782
|
value,
|
|
1955
1783
|
modelField,
|
|
1956
|
-
fieldPath: fieldPath.concat(fieldName)
|
|
1784
|
+
fieldPath: fieldPath.concat(fieldName),
|
|
1785
|
+
modelMap,
|
|
1786
|
+
locale,
|
|
1787
|
+
userContext,
|
|
1788
|
+
contentSourceInstance
|
|
1957
1789
|
});
|
|
1958
1790
|
result.fields[fieldName] = fieldResult.field;
|
|
1959
1791
|
result.newRefDocuments = result.newRefDocuments.concat(fieldResult.newRefDocuments);
|
|
@@ -1966,6 +1798,172 @@ async function createNestedObjectRecursively({
|
|
|
1966
1798
|
return result;
|
|
1967
1799
|
}
|
|
1968
1800
|
|
|
1801
|
+
async function createNestedField({
|
|
1802
|
+
value,
|
|
1803
|
+
modelField,
|
|
1804
|
+
fieldPath,
|
|
1805
|
+
modelMap,
|
|
1806
|
+
locale,
|
|
1807
|
+
userContext,
|
|
1808
|
+
contentSourceInstance
|
|
1809
|
+
}: {
|
|
1810
|
+
value: any;
|
|
1811
|
+
modelField: FieldSpecificProps;
|
|
1812
|
+
fieldPath: (string | number)[];
|
|
1813
|
+
modelMap: Record<string, Model>;
|
|
1814
|
+
locale?: string;
|
|
1815
|
+
userContext: unknown;
|
|
1816
|
+
contentSourceInstance: CSITypes.ContentSourceInterface;
|
|
1817
|
+
}): Promise<{ field: CSITypes.UpdateOperationField; newRefDocuments: CSITypes.Document[] }> {
|
|
1818
|
+
if (modelField.type === 'object') {
|
|
1819
|
+
const result = await createNestedObjectRecursively({
|
|
1820
|
+
object: value,
|
|
1821
|
+
modelFields: modelField.fields,
|
|
1822
|
+
fieldPath,
|
|
1823
|
+
modelMap,
|
|
1824
|
+
locale,
|
|
1825
|
+
userContext,
|
|
1826
|
+
contentSourceInstance
|
|
1827
|
+
});
|
|
1828
|
+
return {
|
|
1829
|
+
field: {
|
|
1830
|
+
type: 'object',
|
|
1831
|
+
fields: result.fields
|
|
1832
|
+
},
|
|
1833
|
+
newRefDocuments: result.newRefDocuments
|
|
1834
|
+
};
|
|
1835
|
+
} else if (modelField.type === 'model') {
|
|
1836
|
+
let { $$type, ...rest } = value;
|
|
1837
|
+
const modelNames = modelField.models;
|
|
1838
|
+
// for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
|
|
1839
|
+
// the 'type' property in default values
|
|
1840
|
+
if (!$$type && 'type' in rest) {
|
|
1841
|
+
$$type = rest.type;
|
|
1842
|
+
rest = _.omit(rest, 'type');
|
|
1843
|
+
}
|
|
1844
|
+
const modelName = $$type ?? (modelNames.length === 1 ? modelNames[0] : null);
|
|
1845
|
+
if (!modelName) {
|
|
1846
|
+
throw new Error(`no $$type was specified for nested model`);
|
|
1847
|
+
}
|
|
1848
|
+
const model = modelMap[modelName];
|
|
1849
|
+
if (!model) {
|
|
1850
|
+
throw new Error(`no model with name '${modelName}' was found`);
|
|
1851
|
+
}
|
|
1852
|
+
const result = await createNestedObjectRecursively({
|
|
1853
|
+
object: rest,
|
|
1854
|
+
modelFields: model.fields ?? [],
|
|
1855
|
+
fieldPath,
|
|
1856
|
+
modelMap,
|
|
1857
|
+
locale,
|
|
1858
|
+
userContext,
|
|
1859
|
+
contentSourceInstance
|
|
1860
|
+
});
|
|
1861
|
+
return {
|
|
1862
|
+
field: {
|
|
1863
|
+
type: 'model',
|
|
1864
|
+
modelName: modelName,
|
|
1865
|
+
fields: result.fields
|
|
1866
|
+
},
|
|
1867
|
+
newRefDocuments: result.newRefDocuments
|
|
1868
|
+
};
|
|
1869
|
+
} else if (modelField.type === 'image') {
|
|
1870
|
+
let refId: string | undefined;
|
|
1871
|
+
if (_.isPlainObject(value)) {
|
|
1872
|
+
refId = value.$$ref;
|
|
1873
|
+
} else {
|
|
1874
|
+
refId = value;
|
|
1875
|
+
}
|
|
1876
|
+
if (!refId) {
|
|
1877
|
+
throw new Error(`reference field must specify a value`);
|
|
1878
|
+
}
|
|
1879
|
+
return {
|
|
1880
|
+
field: {
|
|
1881
|
+
type: 'reference',
|
|
1882
|
+
refType: 'asset',
|
|
1883
|
+
refId: refId
|
|
1884
|
+
},
|
|
1885
|
+
newRefDocuments: []
|
|
1886
|
+
};
|
|
1887
|
+
} else if (modelField.type === 'reference') {
|
|
1888
|
+
let { $$ref: refId = null, $$type: modelName = null, ...rest } = _.isPlainObject(value) ? value : { $$ref: value };
|
|
1889
|
+
if (refId) {
|
|
1890
|
+
return {
|
|
1891
|
+
field: {
|
|
1892
|
+
type: 'reference',
|
|
1893
|
+
refType: 'document',
|
|
1894
|
+
refId: refId
|
|
1895
|
+
},
|
|
1896
|
+
newRefDocuments: []
|
|
1897
|
+
};
|
|
1898
|
+
} else {
|
|
1899
|
+
const modelNames = modelField.models;
|
|
1900
|
+
if (!modelName) {
|
|
1901
|
+
// for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
|
|
1902
|
+
// the 'type' property in default values
|
|
1903
|
+
if ('type' in rest) {
|
|
1904
|
+
modelName = rest.type;
|
|
1905
|
+
rest = _.omit(rest, 'type');
|
|
1906
|
+
} else if (modelNames.length === 1) {
|
|
1907
|
+
modelName = modelNames[0];
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
const model = modelMap[modelName];
|
|
1911
|
+
if (!model) {
|
|
1912
|
+
throw new Error(`no model with name '${modelName}' was found`);
|
|
1913
|
+
}
|
|
1914
|
+
const { document, newRefDocuments } = await createDocumentRecursively({
|
|
1915
|
+
object: rest,
|
|
1916
|
+
model: model,
|
|
1917
|
+
modelMap,
|
|
1918
|
+
locale,
|
|
1919
|
+
userContext,
|
|
1920
|
+
contentSourceInstance
|
|
1921
|
+
});
|
|
1922
|
+
return {
|
|
1923
|
+
field: {
|
|
1924
|
+
type: 'reference',
|
|
1925
|
+
refType: 'document',
|
|
1926
|
+
refId: document.id
|
|
1927
|
+
},
|
|
1928
|
+
newRefDocuments: [document, ...newRefDocuments]
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
} else if (modelField.type === 'list') {
|
|
1932
|
+
if (!Array.isArray(value)) {
|
|
1933
|
+
throw new Error(`value for list field must be array`);
|
|
1934
|
+
}
|
|
1935
|
+
const itemsField = modelField.items;
|
|
1936
|
+
if (!itemsField) {
|
|
1937
|
+
throw new Error(`list field does not define items`);
|
|
1938
|
+
}
|
|
1939
|
+
const arrayResult = await mapPromise(value, async (item, index) => {
|
|
1940
|
+
return createNestedField({
|
|
1941
|
+
value: item,
|
|
1942
|
+
modelField: itemsField,
|
|
1943
|
+
fieldPath: fieldPath.concat(index),
|
|
1944
|
+
modelMap,
|
|
1945
|
+
locale,
|
|
1946
|
+
userContext,
|
|
1947
|
+
contentSourceInstance
|
|
1948
|
+
});
|
|
1949
|
+
});
|
|
1950
|
+
return {
|
|
1951
|
+
field: {
|
|
1952
|
+
type: 'list',
|
|
1953
|
+
items: arrayResult.map((result) => result.field)
|
|
1954
|
+
},
|
|
1955
|
+
newRefDocuments: arrayResult.reduce((result: CSITypes.Document[], { newRefDocuments }) => result.concat(newRefDocuments), [])
|
|
1956
|
+
};
|
|
1957
|
+
}
|
|
1958
|
+
return {
|
|
1959
|
+
field: {
|
|
1960
|
+
type: modelField.type,
|
|
1961
|
+
value: value
|
|
1962
|
+
},
|
|
1963
|
+
newRefDocuments: []
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
|
|
1969
1967
|
function getModelFieldForFieldAtPath(
|
|
1970
1968
|
document: ContentStoreTypes.Document,
|
|
1971
1969
|
model: Model,
|
|
@@ -2093,12 +2091,13 @@ async function convertOperationField({
|
|
|
2093
2091
|
userContext: unknown;
|
|
2094
2092
|
contentSourceInstance: CSITypes.ContentSourceInterface;
|
|
2095
2093
|
}): Promise<CSITypes.UpdateOperationField> {
|
|
2096
|
-
|
|
2094
|
+
// for insert operations, the modelField will be of the list, so get the modelField of the list items
|
|
2095
|
+
const modelFieldOrListItems: FieldSpecificProps = modelField.type === 'list' ? modelField.items! : modelField;
|
|
2097
2096
|
switch (operationField.type) {
|
|
2098
|
-
case 'object':
|
|
2099
|
-
result = await createNestedObjectRecursively({
|
|
2097
|
+
case 'object': {
|
|
2098
|
+
const result = await createNestedObjectRecursively({
|
|
2100
2099
|
object: operationField.object,
|
|
2101
|
-
modelFields: (
|
|
2100
|
+
modelFields: (modelFieldOrListItems as FieldObjectProps).fields,
|
|
2102
2101
|
fieldPath: fieldPath,
|
|
2103
2102
|
modelMap,
|
|
2104
2103
|
locale,
|
|
@@ -2109,12 +2108,13 @@ async function convertOperationField({
|
|
|
2109
2108
|
type: operationField.type,
|
|
2110
2109
|
fields: result.fields
|
|
2111
2110
|
};
|
|
2112
|
-
|
|
2111
|
+
}
|
|
2112
|
+
case 'model': {
|
|
2113
2113
|
const model = modelMap[operationField.modelName];
|
|
2114
2114
|
if (!model) {
|
|
2115
2115
|
throw new Error(`error updating document, could not find document model: '${operationField.modelName}'`);
|
|
2116
2116
|
}
|
|
2117
|
-
result = await createNestedObjectRecursively({
|
|
2117
|
+
const result = await createNestedObjectRecursively({
|
|
2118
2118
|
object: operationField.object,
|
|
2119
2119
|
modelFields: model.fields!,
|
|
2120
2120
|
fieldPath,
|
|
@@ -2128,6 +2128,54 @@ async function convertOperationField({
|
|
|
2128
2128
|
modelName: operationField.modelName,
|
|
2129
2129
|
fields: result.fields
|
|
2130
2130
|
};
|
|
2131
|
+
}
|
|
2132
|
+
case 'list': {
|
|
2133
|
+
if (modelField.type !== 'list') {
|
|
2134
|
+
throw new Error(`'the operation field type '${operationField.type}' does not match the model field type '${modelField.type}'`);
|
|
2135
|
+
}
|
|
2136
|
+
const result = await mapPromise(operationField.items, async (item, index) => {
|
|
2137
|
+
const result = await createNestedField({
|
|
2138
|
+
value: item,
|
|
2139
|
+
modelField: modelField.items!,
|
|
2140
|
+
fieldPath,
|
|
2141
|
+
modelMap,
|
|
2142
|
+
locale,
|
|
2143
|
+
userContext,
|
|
2144
|
+
contentSourceInstance
|
|
2145
|
+
});
|
|
2146
|
+
return result.field;
|
|
2147
|
+
});
|
|
2148
|
+
return {
|
|
2149
|
+
type: operationField.type,
|
|
2150
|
+
items: result
|
|
2151
|
+
};
|
|
2152
|
+
}
|
|
2153
|
+
case 'string':
|
|
2154
|
+
if (typeof operationField.value !== 'string') {
|
|
2155
|
+
return {
|
|
2156
|
+
type: operationField.type,
|
|
2157
|
+
value: ''
|
|
2158
|
+
};
|
|
2159
|
+
}
|
|
2160
|
+
return operationField as CSITypes.UpdateOperationField;
|
|
2161
|
+
case 'enum':
|
|
2162
|
+
if (typeof operationField.value !== 'string') {
|
|
2163
|
+
if (modelFieldOrListItems.type !== 'enum') {
|
|
2164
|
+
throw new Error(`'the operation field type 'enum' does not match the model field type '${modelFieldOrListItems.type}'`);
|
|
2165
|
+
}
|
|
2166
|
+
const option = modelFieldOrListItems.options[0]!;
|
|
2167
|
+
const optionValue = typeof option === 'object' ? option.value : option;
|
|
2168
|
+
return {
|
|
2169
|
+
type: operationField.type,
|
|
2170
|
+
value: optionValue
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
return operationField as CSITypes.UpdateOperationField;
|
|
2174
|
+
case 'image':
|
|
2175
|
+
if (typeof operationField.value !== 'string') {
|
|
2176
|
+
throw new Error('image value was not specified');
|
|
2177
|
+
}
|
|
2178
|
+
return operationField as CSITypes.UpdateOperationField;
|
|
2131
2179
|
default:
|
|
2132
2180
|
return operationField as CSITypes.UpdateOperationField;
|
|
2133
2181
|
}
|