@ronin/compiler 0.17.0 → 0.17.1-leo-ron-1099-experimental-378

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 (3) hide show
  1. package/dist/index.d.ts +19 -18
  2. package/dist/index.js +154 -147
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -261,19 +261,19 @@ type ModelField = ModelFieldBasics & ({
261
261
  /** Whether the field should be related to one record, or many records. */
262
262
  kind: 'many';
263
263
  });
264
- type ModelIndexField<T extends Array<ModelField> = Array<ModelField>> = {
264
+ type ModelIndexField<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> = {
265
265
  /** The collating sequence used for text placed inside the field. */
266
266
  collation?: ModelFieldCollation;
267
267
  /** How the records in the index should be ordered. */
268
268
  order?: 'ASC' | 'DESC';
269
269
  } & ({
270
270
  /** The field slug for which the index should be created. */
271
- slug: T[number]['slug'];
271
+ slug: keyof T;
272
272
  } | {
273
273
  /** The field expression for which the index should be created. */
274
274
  expression: string;
275
275
  });
276
- type ModelIndex<T extends Array<ModelField> = Array<ModelField>> = {
276
+ type ModelIndex<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> = {
277
277
  /**
278
278
  * The list of fields in the model for which the index should be created.
279
279
  */
@@ -281,7 +281,7 @@ type ModelIndex<T extends Array<ModelField> = Array<ModelField>> = {
281
281
  /**
282
282
  * The identifier of the index.
283
283
  */
284
- slug?: string;
284
+ slug: string;
285
285
  /**
286
286
  * Whether only one record with a unique value for the provided fields will be allowed.
287
287
  */
@@ -292,18 +292,16 @@ type ModelIndex<T extends Array<ModelField> = Array<ModelField>> = {
292
292
  */
293
293
  filter?: WithInstruction;
294
294
  };
295
- type ModelTriggerField<T extends Array<ModelField> = Array<ModelField>> = {
295
+ type ModelTriggerField<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> = {
296
296
  /**
297
297
  * The slug of the field that should cause the trigger to fire if the value of the
298
298
  * field has changed.
299
299
  */
300
- slug: T[number]['slug'];
300
+ slug: keyof T;
301
301
  };
302
- type ModelTrigger<T extends Array<ModelField> = Array<ModelField>> = {
303
- /**
304
- * The identifier of the trigger.
305
- */
306
- slug?: string;
302
+ type ModelTrigger<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> = {
303
+ /** The identifier of the trigger. */
304
+ slug: string;
307
305
  /** The type of query for which the trigger should fire. */
308
306
  action: 'INSERT' | 'UPDATE' | 'DELETE';
309
307
  /** When the trigger should fire in the case that a matching query is executed. */
@@ -324,15 +322,18 @@ type ModelPreset = {
324
322
  /** The query instructions that should be applied when the preset is used. */
325
323
  instructions: GetInstructions;
326
324
  };
327
- interface Model<T extends Array<ModelField> = Array<ModelField>> {
325
+ type ModelEntityList<T extends {
326
+ slug: string;
327
+ }> = Record<NonNullable<T['slug']>, Omit<T, 'slug'>>;
328
+ interface Model<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> {
328
329
  id: string;
329
330
  name: string;
330
331
  pluralName: string;
331
332
  slug: string;
332
333
  pluralSlug: string;
333
334
  identifiers: {
334
- name: T[number]['slug'];
335
- slug: T[number]['slug'];
335
+ name: keyof T;
336
+ slug: keyof T;
336
337
  };
337
338
  idPrefix: string;
338
339
  /** The name of the table in SQLite. */
@@ -357,11 +358,11 @@ interface Model<T extends Array<ModelField> = Array<ModelField>> {
357
358
  associationSlug?: string;
358
359
  };
359
360
  fields: T;
360
- indexes?: Array<ModelIndex<T>>;
361
- triggers?: Array<ModelTrigger<T>>;
362
- presets?: Array<ModelPreset>;
361
+ indexes?: ModelEntityList<ModelIndex<T>>;
362
+ triggers?: ModelEntityList<ModelTrigger<T>>;
363
+ presets?: ModelEntityList<ModelPreset>;
363
364
  }
364
- type PublicModel<T extends Array<ModelField> = Array<ModelField>> = Omit<Partial<Model<T>>, 'slug' | 'identifiers' | 'system' | 'tableAlias'> & {
365
+ type PublicModel<T extends ModelEntityList<ModelField> = ModelEntityList<ModelField>> = Omit<Partial<Model<T>>, 'slug' | 'identifiers' | 'system' | 'tableAlias'> & {
365
366
  slug: Required<Model['slug']>;
366
367
  identifiers?: Partial<Model['identifiers']>;
367
368
  };
package/dist/index.js CHANGED
@@ -587,22 +587,25 @@ var handleTo = (models, model, statementParams, queryType, dependencyStatements,
587
587
  var handleUsing = (model, instructions) => {
588
588
  const normalizedUsing = Array.isArray(instructions.using) ? Object.fromEntries(instructions.using.map((presetSlug) => [presetSlug, null])) : instructions.using;
589
589
  if ("links" in normalizedUsing) {
590
- for (const field of model.fields) {
590
+ for (const [fieldSlug, rest] of Object.entries(model.fields)) {
591
+ const field = { slug: fieldSlug, ...rest };
591
592
  if (field.type !== "link" || field.kind === "many") continue;
592
- normalizedUsing[field.slug] = null;
593
+ normalizedUsing[fieldSlug] = null;
593
594
  }
594
595
  }
595
596
  for (const presetSlug in normalizedUsing) {
596
597
  if (!Object.hasOwn(normalizedUsing, presetSlug) || presetSlug === "links") continue;
597
598
  const arg = normalizedUsing[presetSlug];
598
- const preset = model.presets?.find((preset2) => preset2.slug === presetSlug);
599
+ const preset = model.presets?.[presetSlug];
599
600
  if (!preset) {
600
601
  throw new RoninError({
601
602
  message: `Preset "${presetSlug}" does not exist in model "${model.name}".`,
602
603
  code: "PRESET_NOT_FOUND"
603
604
  });
604
605
  }
605
- const replacedUsingFilter = structuredClone(preset.instructions);
606
+ const replacedUsingFilter = structuredClone(
607
+ preset.instructions
608
+ );
606
609
  if (arg !== null) {
607
610
  findInObject(
608
611
  replacedUsingFilter,
@@ -827,13 +830,16 @@ var matchSelectedFields = (fields, pattern) => {
827
830
  return fields.filter((field) => regex2.test(field.slug));
828
831
  };
829
832
  var filterSelectedFields = (model, instruction) => {
830
- if (!instruction) return model.fields;
833
+ const mappedFields = Object.entries(model.fields).map(
834
+ ([fieldSlug, field]) => ({ slug: fieldSlug, ...field })
835
+ );
836
+ if (!instruction) return mappedFields;
831
837
  let selectedFields = [];
832
838
  for (const pattern of instruction) {
833
839
  const isNegative = pattern.startsWith("!");
834
840
  const cleanPattern = isNegative ? pattern.slice(1) : pattern;
835
841
  const matchedFields = matchSelectedFields(
836
- isNegative ? selectedFields : model.fields,
842
+ isNegative ? selectedFields : mappedFields,
837
843
  cleanPattern
838
844
  );
839
845
  if (isNegative) {
@@ -922,7 +928,7 @@ var composeConditions = (models, model, statementParams, instructionName, value,
922
928
  return conditions.join(" AND ");
923
929
  }
924
930
  if (options.fieldSlug) {
925
- const childField = model.fields.some(({ slug }) => {
931
+ const childField = Object.keys(model.fields).some((slug) => {
926
932
  return slug.includes(".") && slug.split(".")[0] === options.fieldSlug;
927
933
  });
928
934
  if (!childField) {
@@ -1282,19 +1288,19 @@ var addDefaultModelAttributes = (model, isNew) => {
1282
1288
  copiedModel[setting] = generator(copiedModel[base]);
1283
1289
  }
1284
1290
  const newFields = copiedModel.fields || [];
1285
- if (isNew || newFields.length > 0) {
1291
+ if (isNew || Object.keys(newFields).length > 0) {
1286
1292
  if (!copiedModel.identifiers) copiedModel.identifiers = {};
1287
1293
  if (!copiedModel.identifiers.name) {
1288
- const suitableField = newFields.find(
1289
- (field) => field.type === "string" && field.required === true && ["name"].includes(field.slug)
1294
+ const suitableField = Object.entries(newFields).find(
1295
+ ([fieldSlug, field]) => field.type === "string" && field.required === true && ["name"].includes(fieldSlug)
1290
1296
  );
1291
- copiedModel.identifiers.name = suitableField?.slug || "id";
1297
+ copiedModel.identifiers.name = suitableField?.[0] || "id";
1292
1298
  }
1293
1299
  if (!copiedModel.identifiers.slug) {
1294
- const suitableField = newFields.find(
1295
- (field) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(field.slug)
1300
+ const suitableField = Object.entries(newFields).find(
1301
+ ([fieldSlug, field]) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(fieldSlug)
1296
1302
  );
1297
- copiedModel.identifiers.slug = suitableField?.slug || "id";
1303
+ copiedModel.identifiers.slug = suitableField?.[0] || "id";
1298
1304
  }
1299
1305
  }
1300
1306
  return copiedModel;
@@ -1302,29 +1308,32 @@ var addDefaultModelAttributes = (model, isNew) => {
1302
1308
  var addDefaultModelFields = (model, isNew) => {
1303
1309
  const copiedModel = { ...model };
1304
1310
  const existingFields = copiedModel.fields || [];
1305
- if (isNew || existingFields.length > 0) {
1306
- const additionalFields = getSystemFields(copiedModel.idPrefix).filter((newField) => {
1307
- return !existingFields.some(({ slug }) => slug === newField.slug);
1308
- });
1309
- copiedModel.fields = [...additionalFields, ...existingFields];
1311
+ if (isNew || Object.keys(existingFields).length > 0) {
1312
+ const additionalFields = Object.fromEntries(
1313
+ Object.entries(getSystemFields(copiedModel.idPrefix)).filter(([newFieldSlug]) => {
1314
+ return !Object.hasOwn(existingFields, newFieldSlug);
1315
+ })
1316
+ );
1317
+ copiedModel.fields = { ...additionalFields, ...existingFields };
1310
1318
  }
1311
1319
  return copiedModel;
1312
1320
  };
1313
1321
  var addDefaultModelPresets = (list, model) => {
1314
- const defaultPresets = [];
1315
- for (const field of model.fields || []) {
1316
- if (field.type === "link" && !field.slug.startsWith("ronin.")) {
1322
+ const defaultPresets = {};
1323
+ for (const [fieldSlug, rest] of Object.entries(model.fields || {})) {
1324
+ const field = { slug: fieldSlug, ...rest };
1325
+ if (field.type === "link" && !fieldSlug.startsWith("ronin.")) {
1317
1326
  const targetModel = getModelBySlug(list, field.target);
1318
1327
  if (field.kind === "many") {
1319
1328
  const systemModel = list.find(({ system }) => {
1320
1329
  return system?.model === model.id && system?.associationSlug === field.slug;
1321
1330
  });
1322
1331
  if (!systemModel) continue;
1323
- const preset = {
1332
+ const preset2 = {
1324
1333
  instructions: {
1325
1334
  // Perform a LEFT JOIN that adds the associative table.
1326
1335
  including: {
1327
- [field.slug]: {
1336
+ [fieldSlug]: {
1328
1337
  [QUERY_SYMBOLS.QUERY]: {
1329
1338
  get: {
1330
1339
  [systemModel.pluralSlug]: {
@@ -1355,16 +1364,15 @@ var addDefaultModelPresets = (list, model) => {
1355
1364
  }
1356
1365
  }
1357
1366
  }
1358
- },
1359
- slug: field.slug
1367
+ }
1360
1368
  };
1361
- defaultPresets.push(preset);
1369
+ defaultPresets[fieldSlug] = preset2;
1362
1370
  continue;
1363
1371
  }
1364
- defaultPresets.push({
1372
+ const preset = {
1365
1373
  instructions: {
1366
1374
  including: {
1367
- [field.slug]: {
1375
+ [fieldSlug]: {
1368
1376
  [QUERY_SYMBOLS.QUERY]: {
1369
1377
  get: {
1370
1378
  [targetModel.slug]: {
@@ -1380,24 +1388,25 @@ var addDefaultModelPresets = (list, model) => {
1380
1388
  }
1381
1389
  }
1382
1390
  }
1383
- },
1384
- slug: field.slug
1385
- });
1391
+ }
1392
+ };
1393
+ defaultPresets[fieldSlug] = preset;
1386
1394
  }
1387
1395
  }
1388
1396
  const childModels = list.map((subModel) => {
1389
1397
  if (subModel.system?.associationSlug) return null;
1390
- const field = subModel.fields?.find((field2) => {
1398
+ const field = Object.entries(subModel.fields).find(([fieldSlug, rest]) => {
1399
+ const field2 = { slug: fieldSlug, ...rest };
1391
1400
  return field2.type === "link" && field2.target === model.slug;
1392
1401
  });
1393
1402
  if (!field) return null;
1394
- return { model: subModel, field };
1403
+ return { model: subModel, field: { slug: field[0], ...field[1] } };
1395
1404
  }).filter((match) => match !== null);
1396
1405
  for (const childMatch of childModels) {
1397
1406
  const { model: childModel, field: childField } = childMatch;
1398
1407
  const pluralSlug = childModel.pluralSlug;
1399
1408
  const presetSlug = childModel.system?.associationSlug || pluralSlug;
1400
- defaultPresets.push({
1409
+ const preset = {
1401
1410
  instructions: {
1402
1411
  including: {
1403
1412
  [presetSlug]: {
@@ -1414,16 +1423,18 @@ var addDefaultModelPresets = (list, model) => {
1414
1423
  }
1415
1424
  }
1416
1425
  }
1417
- },
1418
- slug: presetSlug
1419
- });
1426
+ }
1427
+ };
1428
+ defaultPresets[presetSlug] = preset;
1420
1429
  }
1421
- if (defaultPresets.length > 0) {
1422
- const existingPresets = model.presets || [];
1423
- const additionalPresets = defaultPresets.filter((newPreset) => {
1424
- return !existingPresets.some(({ slug }) => slug === newPreset.slug);
1425
- });
1426
- model.presets = [...additionalPresets, ...existingPresets];
1430
+ if (Object.keys(defaultPresets).length > 0) {
1431
+ const existingPresets = model.presets;
1432
+ const additionalPresets = Object.fromEntries(
1433
+ Object.entries(defaultPresets).filter(([newPresetSlug]) => {
1434
+ return !existingPresets?.[newPresetSlug];
1435
+ })
1436
+ );
1437
+ model.presets = { ...additionalPresets, ...existingPresets };
1427
1438
  }
1428
1439
  return model;
1429
1440
  };
@@ -1455,7 +1466,12 @@ function getFieldFromModel(model, fieldPath, source, shouldThrow = true) {
1455
1466
  const writingField = "instructionName" in source ? source.instructionName === "to" : true;
1456
1467
  const errorTarget = "instructionName" in source ? `\`${source.instructionName}\`` : `${source.modelEntityType} "${source.modelEntityName}"`;
1457
1468
  const errorPrefix = `Field "${fieldPath}" defined for ${errorTarget}`;
1458
- const modelFields = model.fields || [];
1469
+ const modelFields = Object.entries(model.fields).map(
1470
+ ([fieldSlug, field]) => ({
1471
+ slug: fieldSlug,
1472
+ ...field
1473
+ })
1474
+ );
1459
1475
  let modelField;
1460
1476
  if (fieldPath.includes(".")) {
1461
1477
  modelField = modelFields.find((field) => field.slug === fieldPath.split(".")[0]);
@@ -1479,36 +1495,31 @@ function getFieldFromModel(model, fieldPath, source, shouldThrow = true) {
1479
1495
  const fieldSelector = getFieldSelector(model, modelField, fieldPath, writingField);
1480
1496
  return { field: modelField, fieldSelector };
1481
1497
  }
1482
- var getSystemFields = (idPrefix) => [
1483
- {
1498
+ var getSystemFields = (idPrefix) => ({
1499
+ id: {
1484
1500
  name: "ID",
1485
1501
  type: "string",
1486
- slug: "id",
1487
1502
  defaultValue: ID_EXPRESSION(idPrefix)
1488
1503
  },
1489
- {
1504
+ "ronin.createdAt": {
1490
1505
  name: "RONIN - Created At",
1491
1506
  type: "date",
1492
- slug: "ronin.createdAt",
1493
1507
  defaultValue: CURRENT_TIME_EXPRESSION
1494
1508
  },
1495
- {
1509
+ "ronin.createdBy": {
1496
1510
  name: "RONIN - Created By",
1497
- type: "string",
1498
- slug: "ronin.createdBy"
1511
+ type: "string"
1499
1512
  },
1500
- {
1513
+ "ronin.updatedAt": {
1501
1514
  name: "RONIN - Updated At",
1502
1515
  type: "date",
1503
- slug: "ronin.updatedAt",
1504
1516
  defaultValue: CURRENT_TIME_EXPRESSION
1505
1517
  },
1506
- {
1518
+ "ronin.updatedBy": {
1507
1519
  name: "RONIN - Updated By",
1508
- type: "string",
1509
- slug: "ronin.updatedBy"
1520
+ type: "string"
1510
1521
  }
1511
- ];
1522
+ });
1512
1523
  var ROOT_MODEL = {
1513
1524
  slug: "model",
1514
1525
  identifiers: {
@@ -1519,43 +1530,43 @@ var ROOT_MODEL = {
1519
1530
  table: "ronin_schema",
1520
1531
  // Indicates that the model was automatically generated by RONIN.
1521
1532
  system: { model: "root" },
1522
- fields: [
1523
- { slug: "name", type: "string" },
1524
- { slug: "pluralName", type: "string" },
1525
- { slug: "slug", type: "string" },
1526
- { slug: "pluralSlug", type: "string" },
1527
- { slug: "idPrefix", type: "string" },
1528
- { slug: "table", type: "string" },
1529
- { slug: "identifiers.name", type: "string" },
1530
- { slug: "identifiers.slug", type: "string" },
1533
+ fields: {
1534
+ name: { type: "string" },
1535
+ pluralName: { type: "string" },
1536
+ slug: { type: "string" },
1537
+ pluralSlug: { type: "string" },
1538
+ idPrefix: { type: "string" },
1539
+ table: { type: "string" },
1540
+ "identifiers.name": { type: "string" },
1541
+ "identifiers.slug": { type: "string" },
1531
1542
  // Providing an empty object as a default value allows us to use `json_insert`
1532
1543
  // without needing to fall back to an empty object in the insertion statement,
1533
1544
  // which makes the statement shorter.
1534
- { slug: "fields", type: "json", defaultValue: "{}" },
1535
- { slug: "indexes", type: "json", defaultValue: "{}" },
1536
- { slug: "triggers", type: "json", defaultValue: "{}" },
1537
- { slug: "presets", type: "json", defaultValue: "{}" }
1538
- ]
1545
+ fields: { type: "json", defaultValue: "{}" },
1546
+ indexes: { type: "json", defaultValue: "{}" },
1547
+ triggers: { type: "json", defaultValue: "{}" },
1548
+ presets: { type: "json", defaultValue: "{}" }
1549
+ }
1539
1550
  };
1540
1551
  var ROOT_MODEL_WITH_ATTRIBUTES = addDefaultModelAttributes(ROOT_MODEL, true);
1541
1552
  var getSystemModels = (models, model) => {
1542
1553
  const addedModels = [];
1543
- for (const field of model.fields || []) {
1544
- if (field.type === "link" && !field.slug.startsWith("ronin.")) {
1554
+ for (const [fieldSlug, rest] of Object.entries(model.fields || {})) {
1555
+ const field = { slug: fieldSlug, ...rest };
1556
+ if (field.type === "link" && !fieldSlug.startsWith("ronin.")) {
1545
1557
  const relatedModel = getModelBySlug(models, field.target);
1546
- let fieldSlug = relatedModel.slug;
1558
+ let fieldSlug2 = relatedModel.slug;
1547
1559
  if (field.kind === "many") {
1548
- fieldSlug = composeAssociationModelSlug(model, field);
1560
+ fieldSlug2 = composeAssociationModelSlug(model, field);
1549
1561
  addedModels.push({
1550
- pluralSlug: fieldSlug,
1551
- slug: fieldSlug,
1562
+ pluralSlug: fieldSlug2,
1563
+ slug: fieldSlug2,
1552
1564
  system: {
1553
1565
  model: model.id,
1554
1566
  associationSlug: field.slug
1555
1567
  },
1556
- fields: [
1557
- {
1558
- slug: "source",
1568
+ fields: {
1569
+ source: {
1559
1570
  type: "link",
1560
1571
  target: model.slug,
1561
1572
  actions: {
@@ -1563,8 +1574,7 @@ var getSystemModels = (models, model) => {
1563
1574
  onUpdate: "CASCADE"
1564
1575
  }
1565
1576
  },
1566
- {
1567
- slug: "target",
1577
+ target: {
1568
1578
  type: "link",
1569
1579
  target: relatedModel.slug,
1570
1580
  actions: {
@@ -1572,7 +1582,7 @@ var getSystemModels = (models, model) => {
1572
1582
  onUpdate: "CASCADE"
1573
1583
  }
1574
1584
  }
1575
- ]
1585
+ }
1576
1586
  });
1577
1587
  }
1578
1588
  }
@@ -1636,13 +1646,6 @@ var PLURAL_MODEL_ENTITIES = {
1636
1646
  preset: "presets"
1637
1647
  };
1638
1648
  var PLURAL_MODEL_ENTITIES_VALUES = Object.values(PLURAL_MODEL_ENTITIES);
1639
- var formatModelEntity = (type, entities) => {
1640
- const entries = entities?.map((entity) => {
1641
- const { slug, ...rest } = "slug" in entity ? entity : { slug: `${type}Slug`, ...entity };
1642
- return [slug, rest];
1643
- });
1644
- return entries ? Object.fromEntries(entries) : void 0;
1645
- };
1646
1649
  var handleSystemModel = (models, dependencyStatements, action, inlineDefaults, systemModel, newModel) => {
1647
1650
  const { system: _, ...systemModelClean } = systemModel;
1648
1651
  const query = {
@@ -1665,11 +1668,11 @@ var handleSystemModels = (models, dependencyStatements, previousModel, newModel,
1665
1668
  oldSystemModel.system?.model === newSystemModel.system?.model
1666
1669
  ];
1667
1670
  if (oldSystemModel.system?.associationSlug) {
1668
- const oldFieldIndex = previousModel.fields.findIndex((item) => {
1669
- return item.slug === newSystemModel.system?.associationSlug;
1671
+ const oldFieldIndex = Object.keys(previousModel.fields).findIndex((slug) => {
1672
+ return slug === newSystemModel.system?.associationSlug;
1670
1673
  });
1671
- const newFieldIndex = newModel.fields.findIndex((item) => {
1672
- return item.slug === oldSystemModel.system?.associationSlug;
1674
+ const newFieldIndex = Object.keys(newModel.fields).findIndex((slug) => {
1675
+ return slug === oldSystemModel.system?.associationSlug;
1673
1676
  });
1674
1677
  conditions.push(oldFieldIndex === newFieldIndex);
1675
1678
  }
@@ -1725,7 +1728,7 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
1725
1728
  slug = query.alter[action][entity];
1726
1729
  if ("create" in query.alter) {
1727
1730
  const item = query.alter.create[entity];
1728
- slug = item.slug || `${entity}Slug`;
1731
+ slug = item.slug;
1729
1732
  jsonValue = { slug, ...item };
1730
1733
  }
1731
1734
  if ("alter" in query.alter && query.alter.alter) jsonValue = query.alter.alter.to;
@@ -1743,20 +1746,24 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
1743
1746
  [...models, modelWithFields],
1744
1747
  modelWithFields
1745
1748
  );
1746
- modelWithPresets.fields = modelWithPresets.fields.map((field2) => ({
1747
- ...field2,
1748
- // Default field type.
1749
- type: field2.type || "string",
1750
- // Default field name.
1751
- name: field2.name || slugToName(field2.slug)
1752
- }));
1753
- const columns = modelWithPresets.fields.map((field2) => getFieldStatement(models, modelWithPresets, field2)).filter(Boolean);
1754
- const entities = Object.fromEntries(
1755
- Object.entries(PLURAL_MODEL_ENTITIES).map(([type, pluralType2]) => {
1756
- const list = modelWithPresets[pluralType2];
1757
- return [pluralType2, formatModelEntity(type, list)];
1758
- })
1749
+ modelWithPresets.fields = Object.fromEntries(
1750
+ Object.entries(modelWithPresets.fields).map(([fieldSlug, rest]) => [
1751
+ fieldSlug,
1752
+ {
1753
+ ...rest,
1754
+ // Default field type.
1755
+ type: rest.type || "string",
1756
+ // Default field name.
1757
+ name: rest.name || slugToName(fieldSlug)
1758
+ }
1759
+ ])
1759
1760
  );
1761
+ const columns = Object.entries(modelWithPresets.fields).map(
1762
+ ([fieldSlug, rest]) => getFieldStatement(models, modelWithPresets, {
1763
+ slug: fieldSlug,
1764
+ ...rest
1765
+ })
1766
+ ).filter(Boolean);
1760
1767
  models.push(modelWithPresets);
1761
1768
  dependencyStatements.push({
1762
1769
  statement: `CREATE TABLE "${modelWithPresets.table}" (${columns.join(", ")})`,
@@ -1766,28 +1773,27 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
1766
1773
  ["index", "indexes"],
1767
1774
  ["trigger", "triggers"]
1768
1775
  ]) {
1769
- const entityValue = modelWithPresets[pluralModelEntity];
1770
- if (!entityValue) continue;
1771
- for (const item of entityValue) {
1776
+ const entityList = modelWithPresets[pluralModelEntity];
1777
+ if (!entityList) continue;
1778
+ for (const [itemSlug, item] of Object.entries(entityList)) {
1772
1779
  const query2 = {
1773
1780
  alter: {
1774
1781
  model: modelWithPresets.slug,
1775
1782
  create: {
1776
- [modelEntity]: item
1783
+ [modelEntity]: { slug: itemSlug, ...item }
1777
1784
  }
1778
1785
  }
1779
1786
  };
1780
- transformMetaQuery(models, dependencyStatements, null, query2, {
1787
+ const tempModels = [
1788
+ ...models.filter((model2) => model2.slug !== modelWithPresets.slug),
1789
+ { ...modelWithPresets, indexes: {}, triggers: {} }
1790
+ ];
1791
+ transformMetaQuery(tempModels, dependencyStatements, null, query2, {
1781
1792
  inlineDefaults: options.inlineDefaults
1782
1793
  });
1783
1794
  }
1784
1795
  }
1785
- const modelWithObjects = Object.assign({}, modelWithPresets);
1786
- for (const entity2 in entities) {
1787
- if (!Object.hasOwn(entities, entity2)) continue;
1788
- Object.defineProperty(modelWithObjects, entity2, { value: entities[entity2] });
1789
- }
1790
- queryTypeDetails = { with: modelWithObjects };
1796
+ queryTypeDetails = { with: modelWithPresets };
1791
1797
  getSystemModels(models, modelWithPresets).map((systemModel) => {
1792
1798
  return handleSystemModel(
1793
1799
  models,
@@ -1852,16 +1858,13 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
1852
1858
  const modelBeforeUpdate = structuredClone(model);
1853
1859
  const existingModel = model;
1854
1860
  const pluralType = PLURAL_MODEL_ENTITIES[entity];
1855
- const targetEntityIndex = existingModel[pluralType]?.findIndex(
1856
- (entity2) => entity2.slug === slug
1857
- );
1858
- if ((action === "alter" || action === "drop") && (typeof targetEntityIndex === "undefined" || targetEntityIndex === -1)) {
1861
+ const existingEntity = existingModel[pluralType]?.[slug];
1862
+ if ((action === "alter" || action === "drop") && !existingEntity) {
1859
1863
  throw new RoninError({
1860
1864
  message: `No ${entity} with slug "${slug}" defined in model "${existingModel.name}".`,
1861
1865
  code: MODEL_ENTITY_ERROR_CODES[entity]
1862
1866
  });
1863
1867
  }
1864
- const existingEntity = existingModel[pluralType]?.[targetEntityIndex];
1865
1868
  if (action === "create" && existingEntity) {
1866
1869
  throw new RoninError({
1867
1870
  message: `A ${entity} with the slug "${slug}" already exists.`,
@@ -1898,7 +1901,7 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
1898
1901
  }
1899
1902
  } else if (action === "drop" && !existingLinkField) {
1900
1903
  const systemFields = getSystemFields(existingModel.idPrefix);
1901
- const isSystemField = systemFields.some((field2) => field2.slug === slug);
1904
+ const isSystemField = slug in systemFields;
1902
1905
  if (isSystemField) {
1903
1906
  throw new RoninError({
1904
1907
  message: `The ${entity} "${slug}" is a system ${entity} and cannot be removed.`,
@@ -2002,23 +2005,33 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query,
2002
2005
  case "create": {
2003
2006
  const value = prepareStatementValue(statementParams, jsonValue);
2004
2007
  json = `json_insert(${field}, '$.${slug}', ${value})`;
2005
- existingModel[pluralType] = [
2006
- ...existingModel[pluralType] || [],
2007
- jsonValue
2008
- ];
2008
+ if (!existingModel[pluralType]) existingModel[pluralType] = {};
2009
+ existingModel[pluralType][slug] = jsonValue;
2009
2010
  break;
2010
2011
  }
2011
2012
  case "alter": {
2012
- const value = prepareStatementValue(statementParams, jsonValue);
2013
- json = `json_set(${field}, '$.${slug}', json_patch(json_extract(${field}, '$.${slug}'), ${value}))`;
2014
- const targetEntity = existingModel[pluralType];
2015
- Object.assign(targetEntity[targetEntityIndex], jsonValue);
2013
+ const targetEntities = existingModel[pluralType];
2014
+ if (jsonValue?.slug && jsonValue.slug !== slug) {
2015
+ const { slug: newSlug, ...entityValue } = jsonValue;
2016
+ Object.defineProperty(
2017
+ targetEntities,
2018
+ newSlug,
2019
+ Object.getOwnPropertyDescriptor(targetEntities, slug)
2020
+ );
2021
+ delete targetEntities[slug];
2022
+ const value = prepareStatementValue(statementParams, entityValue);
2023
+ json = `json_insert(json_remove(${field}, '$.${slug}'), '$.${newSlug}', ${value})`;
2024
+ } else {
2025
+ Object.assign(targetEntities[slug], jsonValue);
2026
+ const value = prepareStatementValue(statementParams, jsonValue);
2027
+ json = `json_set(${field}, '$.${slug}', json_patch(json_extract(${field}, '$.${slug}'), ${value}))`;
2028
+ }
2016
2029
  break;
2017
2030
  }
2018
2031
  case "drop": {
2019
2032
  json = `json_remove(${field}, '$.${slug}')`;
2020
- const targetEntity = existingModel[pluralType];
2021
- targetEntity.splice(targetEntityIndex, 1);
2033
+ const targetEntities = existingModel[pluralType];
2034
+ delete targetEntities[slug];
2022
2035
  }
2023
2036
  }
2024
2037
  handleSystemModels(
@@ -2110,7 +2123,7 @@ var Transaction = class {
2110
2123
  this.models = modelsWithPresets;
2111
2124
  return statements;
2112
2125
  };
2113
- #formatRows(fields, rows, single, isMeta) {
2126
+ #formatRows(fields, rows, single) {
2114
2127
  const records = [];
2115
2128
  for (const row of rows) {
2116
2129
  const record = fields.reduce((acc, field, fieldIndex) => {
@@ -2123,11 +2136,6 @@ var Transaction = class {
2123
2136
  newValue = Boolean(newValue);
2124
2137
  }
2125
2138
  }
2126
- if (isMeta && PLURAL_MODEL_ENTITIES_VALUES.includes(newSlug)) {
2127
- newValue = newValue ? Object.entries(newValue).map(([slug, attributes]) => {
2128
- return { slug, ...attributes };
2129
- }) : [];
2130
- }
2131
2139
  const { parentField, parentIsArray } = (() => {
2132
2140
  const lastDotIndex = newSlug.lastIndexOf(".");
2133
2141
  if (lastDotIndex === -1) return { parentField: null };
@@ -2221,9 +2229,8 @@ var Transaction = class {
2221
2229
  };
2222
2230
  const { queryType, queryModel, queryInstructions } = splitQuery(query);
2223
2231
  const model = getModelBySlug(this.models, queryModel);
2224
- const isMeta = queryModel === "model" || queryModel === "models";
2225
2232
  const modelFields = Object.fromEntries(
2226
- model.fields.map((field) => [field.slug, field.type])
2233
+ Object.entries(model.fields).map(([slug, rest]) => [slug, rest.type])
2227
2234
  );
2228
2235
  if (queryType === "count") {
2229
2236
  return addResult({ amount: rows[0][0] });
@@ -2231,13 +2238,13 @@ var Transaction = class {
2231
2238
  const single = queryModel !== model.pluralSlug;
2232
2239
  if (single) {
2233
2240
  return addResult({
2234
- record: rows[0] ? this.#formatRows(selectedFields, rows, true, isMeta) : null,
2241
+ record: rows[0] ? this.#formatRows(selectedFields, rows, true) : null,
2235
2242
  modelFields
2236
2243
  });
2237
2244
  }
2238
2245
  const pageSize = queryInstructions?.limitedTo;
2239
2246
  const result = {
2240
- records: this.#formatRows(selectedFields, rows, false, isMeta),
2247
+ records: this.#formatRows(selectedFields, rows, false),
2241
2248
  modelFields
2242
2249
  };
2243
2250
  if (pageSize && result.records.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.17.0",
3
+ "version": "0.17.1-leo-ron-1099-experimental-378",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {