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