@ronin/compiler 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.js CHANGED
@@ -1,19 +1,23 @@
1
1
  // src/utils/helpers.ts
2
2
  import { init as cuid } from "@paralleldrive/cuid2";
3
- var RONIN_SCHEMA_SYMBOLS = {
3
+ var RONIN_MODEL_SYMBOLS = {
4
4
  // Represents a sub query.
5
5
  QUERY: "__RONIN_QUERY",
6
- // Represents the value of a field in a schema.
6
+ // Represents an expression that should be evaluated.
7
+ EXPRESSION: "__RONIN_EXPRESSION",
8
+ // Represents the value of a field in the model.
7
9
  FIELD: "__RONIN_FIELD_",
8
- // Represents the old value of a field in a schema. Used for triggers.
9
- FIELD_OLD: "__RONIN_FIELD_OLD_",
10
- // Represents the new value of a field in a schema. Used for triggers.
11
- FIELD_NEW: "__RONIN_FIELD_NEW_",
10
+ // Represents the value of a field in the model of a parent query.
11
+ FIELD_PARENT: "__RONIN_FIELD_PARENT_",
12
+ // Represents the old value of a field in the parent model. Used for triggers.
13
+ FIELD_PARENT_OLD: "__RONIN_FIELD_PARENT_OLD_",
14
+ // Represents the new value of a field in the parent model. Used for triggers.
15
+ FIELD_PARENT_NEW: "__RONIN_FIELD_PARENT_NEW_",
12
16
  // Represents a value provided to a query preset.
13
17
  VALUE: "__RONIN_VALUE"
14
18
  };
15
- var RONIN_SCHEMA_FIELD_REGEX = new RegExp(
16
- `${RONIN_SCHEMA_SYMBOLS.FIELD}[a-zA-Z0-9]+`,
19
+ var RONIN_MODEL_FIELD_REGEX = new RegExp(
20
+ `${RONIN_MODEL_SYMBOLS.FIELD}[_a-zA-Z0-9]+`,
17
21
  "g"
18
22
  );
19
23
  var RoninError = class extends Error {
@@ -94,9 +98,9 @@ var expand = (obj) => {
94
98
  };
95
99
  var splitQuery = (query) => {
96
100
  const queryType = Object.keys(query)[0];
97
- const querySchema = Object.keys(query[queryType])[0];
98
- const queryInstructions = query[queryType][querySchema];
99
- return { queryType, querySchema, queryInstructions };
101
+ const queryModel = Object.keys(query[queryType])[0];
102
+ const queryInstructions = query[queryType][queryModel];
103
+ return { queryType, queryModel, queryInstructions };
100
104
  };
101
105
 
102
106
  // src/utils/statement.ts
@@ -112,39 +116,44 @@ var prepareStatementValue = (statementParams, value) => {
112
116
  const index = statementParams.push(formattedValue);
113
117
  return `?${index}`;
114
118
  };
115
- var composeFieldValues = (schemas, schema, statementParams, instructionName, value, options) => {
116
- const { field: schemaField, fieldSelector: selector } = getFieldFromSchema(
117
- schema,
119
+ var parseFieldExpression = (model, instructionName, expression, parentModel) => {
120
+ return expression.replace(RONIN_MODEL_FIELD_REGEX, (match) => {
121
+ let toReplace = RONIN_MODEL_SYMBOLS.FIELD;
122
+ let rootModel = model;
123
+ if (match.startsWith(RONIN_MODEL_SYMBOLS.FIELD_PARENT)) {
124
+ rootModel = parentModel;
125
+ toReplace = RONIN_MODEL_SYMBOLS.FIELD_PARENT;
126
+ if (match.startsWith(RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD)) {
127
+ rootModel.tableAlias = toReplace = RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD;
128
+ } else if (match.startsWith(RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW)) {
129
+ rootModel.tableAlias = toReplace = RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW;
130
+ }
131
+ }
132
+ const fieldSlug = match.replace(toReplace, "");
133
+ const field = getFieldFromModel(rootModel, fieldSlug, instructionName);
134
+ return field.fieldSelector;
135
+ });
136
+ };
137
+ var composeFieldValues = (models, model, statementParams, instructionName, value, options) => {
138
+ const { fieldSelector: conditionSelector } = getFieldFromModel(
139
+ model,
118
140
  options.fieldSlug,
119
- instructionName,
120
- options.rootTable
141
+ instructionName
121
142
  );
122
143
  const collectStatementValue = options.type !== "fields";
123
- let conditionSelector = selector;
144
+ const symbol = getSymbol(value);
124
145
  let conditionValue = value;
125
- if (getSubQuery(value) && collectStatementValue) {
126
- conditionValue = `(${compileQueryInput(
127
- value[RONIN_SCHEMA_SYMBOLS.QUERY],
128
- schemas,
129
- statementParams
130
- ).main.statement})`;
131
- } else if (typeof value === "string" && value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD)) {
132
- let targetTable = `"${options.rootTable}"`;
133
- let toReplace = RONIN_SCHEMA_SYMBOLS.FIELD;
134
- if (value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD_OLD)) {
135
- targetTable = "OLD";
136
- toReplace = RONIN_SCHEMA_SYMBOLS.FIELD_OLD;
137
- } else if (value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD_NEW)) {
138
- targetTable = "NEW";
139
- toReplace = RONIN_SCHEMA_SYMBOLS.FIELD_NEW;
146
+ if (symbol) {
147
+ if (symbol?.type === "expression") {
148
+ conditionValue = parseFieldExpression(
149
+ model,
150
+ instructionName,
151
+ symbol.value,
152
+ options.parentModel
153
+ );
140
154
  }
141
- conditionSelector = `${options.customTable ? `"${options.customTable}".` : ""}"${schemaField.slug}"`;
142
- conditionValue = `${targetTable}."${value.replace(toReplace, "")}"`;
143
- } else if (schemaField.type === "json" && instructionName === "to") {
144
- conditionSelector = `"${schemaField.slug}"`;
145
- if (collectStatementValue) {
146
- const preparedValue = prepareStatementValue(statementParams, value);
147
- conditionValue = `IIF(${conditionSelector} IS NULL, ${preparedValue}, json_patch(${conditionSelector}, ${preparedValue}))`;
155
+ if (symbol.type === "query" && collectStatementValue) {
156
+ conditionValue = `(${compileQueryInput(symbol.value, models, statementParams).main.statement})`;
148
157
  }
149
158
  } else if (collectStatementValue) {
150
159
  conditionValue = prepareStatementValue(statementParams, value);
@@ -153,11 +162,11 @@ var composeFieldValues = (schemas, schema, statementParams, instructionName, val
153
162
  if (options.type === "values") return conditionValue;
154
163
  return `${conditionSelector} ${WITH_CONDITIONS[options.condition || "being"](conditionValue, value)}`;
155
164
  };
156
- var composeConditions = (schemas, schema, statementParams, instructionName, value, options) => {
165
+ var composeConditions = (models, model, statementParams, instructionName, value, options) => {
157
166
  const isNested = isObject(value) && Object.keys(value).length > 0;
158
167
  if (isNested && Object.keys(value).every((key) => key in WITH_CONDITIONS)) {
159
168
  const conditions = Object.entries(value).map(
160
- ([conditionType, checkValue]) => composeConditions(schemas, schema, statementParams, instructionName, checkValue, {
169
+ ([conditionType, checkValue]) => composeConditions(models, model, statementParams, instructionName, checkValue, {
161
170
  ...options,
162
171
  condition: conditionType
163
172
  })
@@ -165,47 +174,42 @@ var composeConditions = (schemas, schema, statementParams, instructionName, valu
165
174
  return conditions.join(" AND ");
166
175
  }
167
176
  if (options.fieldSlug) {
168
- const fieldDetails = getFieldFromSchema(
169
- schema,
170
- options.fieldSlug,
171
- instructionName,
172
- options.rootTable
173
- );
174
- const { field: schemaField } = fieldDetails;
175
- const consumeJSON = schemaField.type === "json" && instructionName === "to";
176
- if (!(isObject(value) || Array.isArray(value)) || getSubQuery(value) || consumeJSON) {
177
+ const fieldDetails = getFieldFromModel(model, options.fieldSlug, instructionName);
178
+ const { field: modelField } = fieldDetails;
179
+ const consumeJSON = modelField.type === "json" && instructionName === "to";
180
+ if (!(isObject(value) || Array.isArray(value)) || getSymbol(value) || consumeJSON) {
177
181
  return composeFieldValues(
178
- schemas,
179
- schema,
182
+ models,
183
+ model,
180
184
  statementParams,
181
185
  instructionName,
182
186
  value,
183
187
  { ...options, fieldSlug: options.fieldSlug }
184
188
  );
185
189
  }
186
- if (schemaField.type === "reference" && isNested) {
190
+ if (modelField.type === "reference" && isNested) {
187
191
  const keys = Object.keys(value);
188
192
  const values = Object.values(value);
189
193
  let recordTarget;
190
194
  if (keys.length === 1 && keys[0] === "id") {
191
195
  recordTarget = values[0];
192
196
  } else {
193
- const relatedSchema = getSchemaBySlug(schemas, schemaField.target.slug);
197
+ const relatedModel = getModelBySlug(models, modelField.target.slug);
194
198
  const subQuery = {
195
199
  get: {
196
- [relatedSchema.slug]: {
200
+ [relatedModel.slug]: {
197
201
  with: value,
198
202
  selecting: ["id"]
199
203
  }
200
204
  }
201
205
  };
202
206
  recordTarget = {
203
- [RONIN_SCHEMA_SYMBOLS.QUERY]: subQuery
207
+ [RONIN_MODEL_SYMBOLS.QUERY]: subQuery
204
208
  };
205
209
  }
206
210
  return composeConditions(
207
- schemas,
208
- schema,
211
+ models,
212
+ model,
209
213
  statementParams,
210
214
  instructionName,
211
215
  recordTarget,
@@ -216,7 +220,7 @@ var composeConditions = (schemas, schema, statementParams, instructionName, valu
216
220
  if (isNested) {
217
221
  const conditions = Object.entries(value).map(([field, value2]) => {
218
222
  const nestedFieldSlug = options.fieldSlug ? `${options.fieldSlug}.${field}` : field;
219
- return composeConditions(schemas, schema, statementParams, instructionName, value2, {
223
+ return composeConditions(models, model, statementParams, instructionName, value2, {
220
224
  ...options,
221
225
  fieldSlug: nestedFieldSlug
222
226
  });
@@ -227,14 +231,7 @@ var composeConditions = (schemas, schema, statementParams, instructionName, valu
227
231
  }
228
232
  if (Array.isArray(value)) {
229
233
  const conditions = value.map(
230
- (filter) => composeConditions(
231
- schemas,
232
- schema,
233
- statementParams,
234
- instructionName,
235
- filter,
236
- options
237
- )
234
+ (filter) => composeConditions(models, model, statementParams, instructionName, filter, options)
238
235
  );
239
236
  return conditions.join(" OR ");
240
237
  }
@@ -265,8 +262,22 @@ var formatIdentifiers = ({ identifiers }, queryInstructions) => {
265
262
  [type]: newNestedInstructions
266
263
  };
267
264
  };
268
- var getSubQuery = (value) => {
269
- return isObject(value) ? value[RONIN_SCHEMA_SYMBOLS.QUERY] || null : null;
265
+ var getSymbol = (value) => {
266
+ if (!isObject(value)) return null;
267
+ const objectValue = value;
268
+ if (RONIN_MODEL_SYMBOLS.QUERY in objectValue) {
269
+ return {
270
+ type: "query",
271
+ value: objectValue[RONIN_MODEL_SYMBOLS.QUERY]
272
+ };
273
+ }
274
+ if (RONIN_MODEL_SYMBOLS.EXPRESSION in objectValue) {
275
+ return {
276
+ type: "expression",
277
+ value: objectValue[RONIN_MODEL_SYMBOLS.EXPRESSION]
278
+ };
279
+ }
280
+ return null;
270
281
  };
271
282
 
272
283
  // src/instructions/with.ts
@@ -292,41 +303,37 @@ var WITH_CONDITIONS = {
292
303
  lessThan: (value) => `< ${value}`,
293
304
  lessOrEqual: (value) => `<= ${value}`
294
305
  };
295
- var handleWith = (schemas, schema, statementParams, instruction, rootTable) => {
306
+ var handleWith = (models, model, statementParams, instruction, parentModel) => {
296
307
  const subStatement = composeConditions(
297
- schemas,
298
- schema,
308
+ models,
309
+ model,
299
310
  statementParams,
300
311
  "with",
301
312
  instruction,
302
- { rootTable }
313
+ { parentModel }
303
314
  );
304
315
  return `(${subStatement})`;
305
316
  };
306
317
 
307
- // src/utils/schema.ts
318
+ // src/utils/model.ts
308
319
  import title from "title";
309
- var getSchemaBySlug = (schemas, slug) => {
310
- const schema = schemas.find((schema2) => {
311
- return schema2.slug === slug || schema2.pluralSlug === slug;
320
+ var getModelBySlug = (models, slug) => {
321
+ const model = models.find((model2) => {
322
+ return model2.slug === slug || model2.pluralSlug === slug;
312
323
  });
313
- if (!schema) {
324
+ if (!model) {
314
325
  throw new RoninError({
315
- message: `No matching schema with either Slug or Plural Slug of "${slug}" could be found.`,
316
- code: "SCHEMA_NOT_FOUND"
326
+ message: `No matching model with either Slug or Plural Slug of "${slug}" could be found.`,
327
+ code: "MODEL_NOT_FOUND"
317
328
  });
318
329
  }
319
- return schema;
320
- };
321
- var getTableForSchema = (schema) => {
322
- return convertToSnakeCase(schema.pluralSlug);
330
+ return model;
323
331
  };
324
- var composeMetaSchemaSlug = (suffix) => convertToCamelCase(`ronin_${suffix}`);
325
- var composeAssociationSchemaSlug = (schema, field) => composeMetaSchemaSlug(`${schema.slug}_${field.slug}`);
326
- var getFieldSelector = (field, fieldPath, rootTable) => {
327
- const symbol = rootTable?.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD) ? `${rootTable.replace(RONIN_SCHEMA_SYMBOLS.FIELD, "").slice(0, -1)}.` : "";
328
- const tablePrefix = symbol || (rootTable ? `"${rootTable}".` : "");
329
- if (field.type === "json") {
332
+ var composeAssociationModelSlug = (model, field) => convertToCamelCase(`ronin_link_${model.slug}_${field.slug}`);
333
+ var getFieldSelector = (model, field, fieldPath, instructionName) => {
334
+ const symbol = model.tableAlias?.startsWith(RONIN_MODEL_SYMBOLS.FIELD_PARENT) ? `${model.tableAlias.replace(RONIN_MODEL_SYMBOLS.FIELD_PARENT, "").slice(0, -1)}.` : "";
335
+ const tablePrefix = symbol || (model.tableAlias ? `"${model.tableAlias}".` : "");
336
+ if (field.type === "json" && instructionName !== "to") {
330
337
  const dotParts = fieldPath.split(".");
331
338
  const columnName = tablePrefix + dotParts.shift();
332
339
  const jsonField = dotParts.join(".");
@@ -334,28 +341,33 @@ var getFieldSelector = (field, fieldPath, rootTable) => {
334
341
  }
335
342
  return `${tablePrefix}"${fieldPath}"`;
336
343
  };
337
- var getFieldFromSchema = (schema, fieldPath, instructionName, rootTable) => {
344
+ var getFieldFromModel = (model, fieldPath, instructionName) => {
338
345
  const errorPrefix = `Field "${fieldPath}" defined for \`${instructionName}\``;
339
- const schemaFields = schema.fields || [];
340
- let schemaField;
346
+ const modelFields = model.fields || [];
347
+ let modelField;
341
348
  if (fieldPath.includes(".")) {
342
- schemaField = schemaFields.find((field) => field.slug === fieldPath.split(".")[0]);
343
- if (schemaField?.type === "json") {
344
- const fieldSelector2 = getFieldSelector(schemaField, fieldPath, rootTable);
345
- return { field: schemaField, fieldSelector: fieldSelector2 };
349
+ modelField = modelFields.find((field) => field.slug === fieldPath.split(".")[0]);
350
+ if (modelField?.type === "json") {
351
+ const fieldSelector2 = getFieldSelector(
352
+ model,
353
+ modelField,
354
+ fieldPath,
355
+ instructionName
356
+ );
357
+ return { field: modelField, fieldSelector: fieldSelector2 };
346
358
  }
347
359
  }
348
- schemaField = schemaFields.find((field) => field.slug === fieldPath);
349
- if (!schemaField) {
360
+ modelField = modelFields.find((field) => field.slug === fieldPath);
361
+ if (!modelField) {
350
362
  throw new RoninError({
351
- message: `${errorPrefix} does not exist in schema "${schema.name}".`,
363
+ message: `${errorPrefix} does not exist in model "${model.name}".`,
352
364
  code: "FIELD_NOT_FOUND",
353
365
  field: fieldPath,
354
366
  queries: null
355
367
  });
356
368
  }
357
- const fieldSelector = getFieldSelector(schemaField, fieldPath, rootTable);
358
- return { field: schemaField, fieldSelector };
369
+ const fieldSelector = getFieldSelector(model, modelField, fieldPath, instructionName);
370
+ return { field: modelField, fieldSelector };
359
371
  };
360
372
  var slugToName = (slug) => {
361
373
  const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
@@ -373,36 +385,37 @@ var pluralize = (word) => {
373
385
  }
374
386
  return `${word}s`;
375
387
  };
376
- var schemaSettings = [
388
+ var modelSettings = [
377
389
  ["pluralSlug", "slug", pluralize],
378
390
  ["name", "slug", slugToName],
379
391
  ["pluralName", "pluralSlug", slugToName],
380
- ["idPrefix", "slug", (slug) => slug.slice(0, 3)]
392
+ ["idPrefix", "slug", (slug) => slug.slice(0, 3)],
393
+ ["table", "pluralSlug", convertToSnakeCase]
381
394
  ];
382
- var addDefaultSchemaFields = (schema, isNew) => {
383
- const copiedSchema = { ...schema };
384
- for (const [setting, base, generator] of schemaSettings) {
385
- if (copiedSchema[setting] || !copiedSchema[base]) continue;
386
- copiedSchema[setting] = generator(copiedSchema[base]);
395
+ var addDefaultModelFields = (model, isNew) => {
396
+ const copiedModel = { ...model };
397
+ for (const [setting, base, generator] of modelSettings) {
398
+ if (copiedModel[setting] || !copiedModel[base]) continue;
399
+ copiedModel[setting] = generator(copiedModel[base]);
387
400
  }
388
- const newFields = copiedSchema.fields || [];
401
+ const newFields = copiedModel.fields || [];
389
402
  if (isNew || newFields.length > 0) {
390
- if (!copiedSchema.identifiers) copiedSchema.identifiers = {};
391
- if (!copiedSchema.identifiers.name) {
403
+ if (!copiedModel.identifiers) copiedModel.identifiers = {};
404
+ if (!copiedModel.identifiers.name) {
392
405
  const suitableField = newFields.find(
393
406
  (field) => field.type === "string" && field.required === true && ["name"].includes(field.slug)
394
407
  );
395
- copiedSchema.identifiers.name = suitableField?.slug || "id";
408
+ copiedModel.identifiers.name = suitableField?.slug || "id";
396
409
  }
397
- if (!copiedSchema.identifiers.slug) {
410
+ if (!copiedModel.identifiers.slug) {
398
411
  const suitableField = newFields.find(
399
412
  (field) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(field.slug)
400
413
  );
401
- copiedSchema.identifiers.slug = suitableField?.slug || "id";
414
+ copiedModel.identifiers.slug = suitableField?.slug || "id";
402
415
  }
403
- copiedSchema.fields = [...SYSTEM_FIELDS, ...newFields];
416
+ copiedModel.fields = [...SYSTEM_FIELDS, ...newFields];
404
417
  }
405
- return copiedSchema;
418
+ return copiedModel;
406
419
  };
407
420
  var SYSTEM_FIELDS = [
408
421
  {
@@ -442,9 +455,9 @@ var SYSTEM_FIELDS = [
442
455
  slug: "ronin.updatedBy"
443
456
  }
444
457
  ];
445
- var SYSTEM_SCHEMAS = [
458
+ var SYSTEM_MODELS = [
446
459
  {
447
- slug: "schema",
460
+ slug: "model",
448
461
  identifiers: {
449
462
  name: "name",
450
463
  slug: "slug"
@@ -455,6 +468,7 @@ var SYSTEM_SCHEMAS = [
455
468
  { slug: "slug", type: "string" },
456
469
  { slug: "pluralSlug", type: "string" },
457
470
  { slug: "idPrefix", type: "string" },
471
+ { slug: "table", type: "string" },
458
472
  { slug: "identifiers", type: "group" },
459
473
  { slug: "identifiers.name", type: "string" },
460
474
  { slug: "identifiers.slug", type: "string" },
@@ -475,9 +489,9 @@ var SYSTEM_SCHEMAS = [
475
489
  { slug: "slug", type: "string", required: true },
476
490
  { slug: "type", type: "string", required: true },
477
491
  {
478
- slug: "schema",
492
+ slug: "model",
479
493
  type: "reference",
480
- target: { slug: "schema" },
494
+ target: { slug: "model" },
481
495
  required: true
482
496
  },
483
497
  { slug: "required", type: "boolean" },
@@ -485,7 +499,7 @@ var SYSTEM_SCHEMAS = [
485
499
  { slug: "unique", type: "boolean" },
486
500
  { slug: "autoIncrement", type: "boolean" },
487
501
  // Only allowed for fields of type "reference".
488
- { slug: "target", type: "reference", target: { slug: "schema" } },
502
+ { slug: "target", type: "reference", target: { slug: "model" } },
489
503
  { slug: "kind", type: "string" },
490
504
  { slug: "actions", type: "group" },
491
505
  { slug: "actions.onDelete", type: "string" },
@@ -501,9 +515,9 @@ var SYSTEM_SCHEMAS = [
501
515
  fields: [
502
516
  { slug: "slug", type: "string", required: true },
503
517
  {
504
- slug: "schema",
518
+ slug: "model",
505
519
  type: "reference",
506
- target: { slug: "schema" },
520
+ target: { slug: "model" },
507
521
  required: true
508
522
  },
509
523
  { slug: "unique", type: "boolean" },
@@ -520,9 +534,9 @@ var SYSTEM_SCHEMAS = [
520
534
  fields: [
521
535
  { slug: "slug", type: "string", required: true },
522
536
  {
523
- slug: "schema",
537
+ slug: "model",
524
538
  type: "reference",
525
- target: { slug: "schema" },
539
+ target: { slug: "model" },
526
540
  required: true
527
541
  },
528
542
  { slug: "when", type: "string", required: true },
@@ -537,71 +551,71 @@ var SYSTEM_SCHEMAS = [
537
551
  fields: [
538
552
  { slug: "slug", type: "string", required: true },
539
553
  {
540
- slug: "schema",
554
+ slug: "model",
541
555
  type: "reference",
542
- target: { slug: "schema" },
556
+ target: { slug: "model" },
543
557
  required: true
544
558
  },
545
559
  { slug: "instructions", type: "json", required: true }
546
560
  ]
547
561
  }
548
- ].map((schema) => addDefaultSchemaFields(schema, true));
549
- var SYSTEM_SCHEMA_SLUGS = SYSTEM_SCHEMAS.flatMap(({ slug, pluralSlug }) => [
562
+ ].map((model) => addDefaultModelFields(model, true));
563
+ var SYSTEM_MODEL_SLUGS = SYSTEM_MODELS.flatMap(({ slug, pluralSlug }) => [
550
564
  slug,
551
565
  pluralSlug
552
566
  ]);
553
- var addSystemSchemas = (schemas) => {
554
- const associativeSchemas = schemas.flatMap((schema) => {
555
- const addedSchemas = [];
556
- for (const field of schema.fields || []) {
567
+ var addSystemModels = (models) => {
568
+ const associativeModels = models.flatMap((model) => {
569
+ const addedModels = [];
570
+ for (const field of model.fields || []) {
557
571
  if (field.type === "reference" && !field.slug.startsWith("ronin.")) {
558
- const relatedSchema = getSchemaBySlug(schemas, field.target.slug);
559
- let fieldSlug = relatedSchema.slug;
572
+ const relatedModel = getModelBySlug(models, field.target.slug);
573
+ let fieldSlug = relatedModel.slug;
560
574
  if (field.kind === "many") {
561
- fieldSlug = composeAssociationSchemaSlug(schema, field);
562
- addedSchemas.push({
575
+ fieldSlug = composeAssociationModelSlug(model, field);
576
+ addedModels.push({
563
577
  pluralSlug: fieldSlug,
564
578
  slug: fieldSlug,
579
+ associationSlug: field.slug,
565
580
  fields: [
566
581
  {
567
582
  slug: "source",
568
583
  type: "reference",
569
- target: { slug: schema.slug }
584
+ target: { slug: model.slug }
570
585
  },
571
586
  {
572
587
  slug: "target",
573
588
  type: "reference",
574
- target: { slug: relatedSchema.slug }
589
+ target: { slug: relatedModel.slug }
575
590
  }
576
591
  ]
577
592
  });
578
593
  }
579
594
  }
580
595
  }
581
- return addedSchemas;
596
+ return addedModels;
582
597
  });
583
- return [...SYSTEM_SCHEMAS, ...associativeSchemas, ...schemas];
598
+ return [...SYSTEM_MODELS, ...associativeModels, ...models];
584
599
  };
585
- var addDefaultSchemaPresets = (list, schema) => {
600
+ var addDefaultModelPresets = (list, model) => {
586
601
  const defaultPresets = [];
587
- for (const field of schema.fields || []) {
602
+ for (const field of model.fields || []) {
588
603
  if (field.type === "reference" && !field.slug.startsWith("ronin.")) {
589
- const relatedSchema = getSchemaBySlug(list, field.target.slug);
590
- let fieldSlug = relatedSchema.slug;
591
- if (field.kind === "many") {
592
- fieldSlug = composeAssociationSchemaSlug(schema, field);
593
- }
604
+ const relatedModel = getModelBySlug(list, field.target.slug);
605
+ if (field.kind === "many") continue;
594
606
  defaultPresets.push({
595
607
  instructions: {
596
608
  including: {
597
609
  [field.slug]: {
598
- [RONIN_SCHEMA_SYMBOLS.QUERY]: {
610
+ [RONIN_MODEL_SYMBOLS.QUERY]: {
599
611
  get: {
600
- [fieldSlug]: {
612
+ [relatedModel.slug]: {
601
613
  with: {
602
- // Compare the `id` field of the related schema to the reference field on
603
- // the root schema (`field.slug`).
604
- id: `${RONIN_SCHEMA_SYMBOLS.FIELD}${field.slug}`
614
+ // Compare the `id` field of the related model to the reference field on
615
+ // the root model (`field.slug`).
616
+ id: {
617
+ [RONIN_MODEL_SYMBOLS.EXPRESSION]: `${RONIN_MODEL_SYMBOLS.FIELD_PARENT}${field.slug}`
618
+ }
605
619
  }
606
620
  }
607
621
  }
@@ -613,25 +627,28 @@ var addDefaultSchemaPresets = (list, schema) => {
613
627
  });
614
628
  }
615
629
  }
616
- const childSchemas = list.map((subSchema) => {
617
- const field = subSchema.fields?.find((field2) => {
618
- return field2.type === "reference" && field2.target.slug === schema.slug;
630
+ const childModels = list.map((subModel) => {
631
+ const field = subModel.fields?.find((field2) => {
632
+ return field2.type === "reference" && field2.target.slug === model.slug;
619
633
  });
620
634
  if (!field) return null;
621
- return { schema: subSchema, field };
635
+ return { model: subModel, field };
622
636
  }).filter((match) => match !== null);
623
- for (const childMatch of childSchemas) {
624
- const { schema: childSchema, field: childField } = childMatch;
625
- const pluralSlug = childSchema.pluralSlug;
637
+ for (const childMatch of childModels) {
638
+ const { model: childModel, field: childField } = childMatch;
639
+ const pluralSlug = childModel.pluralSlug;
640
+ const presetSlug = childModel.associationSlug || pluralSlug;
626
641
  defaultPresets.push({
627
642
  instructions: {
628
643
  including: {
629
- [pluralSlug]: {
630
- [RONIN_SCHEMA_SYMBOLS.QUERY]: {
644
+ [presetSlug]: {
645
+ [RONIN_MODEL_SYMBOLS.QUERY]: {
631
646
  get: {
632
647
  [pluralSlug]: {
633
648
  with: {
634
- [childField.slug]: `${RONIN_SCHEMA_SYMBOLS.FIELD}id`
649
+ [childField.slug]: {
650
+ [RONIN_MODEL_SYMBOLS.EXPRESSION]: `${RONIN_MODEL_SYMBOLS.FIELD_PARENT}id`
651
+ }
635
652
  }
636
653
  }
637
654
  }
@@ -639,13 +656,13 @@ var addDefaultSchemaPresets = (list, schema) => {
639
656
  }
640
657
  }
641
658
  },
642
- slug: pluralSlug
659
+ slug: presetSlug
643
660
  });
644
661
  }
645
662
  if (Object.keys(defaultPresets).length > 0) {
646
- schema.presets = [...defaultPresets, ...schema.presets || []];
663
+ model.presets = [...defaultPresets, ...model.presets || []];
647
664
  }
648
- return schema;
665
+ return model;
649
666
  };
650
667
  var mappedInstructions = {
651
668
  create: "to",
@@ -681,35 +698,31 @@ var getFieldStatement = (field) => {
681
698
  }
682
699
  return statement;
683
700
  };
684
- var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
685
- const {
686
- queryType,
687
- querySchema,
688
- queryInstructions: queryInstructionsRaw
689
- } = queryDetails;
701
+ var addModelQueries = (models, queryDetails, dependencyStatements) => {
702
+ const { queryType, queryModel, queryInstructions: queryInstructionsRaw } = queryDetails;
690
703
  const queryInstructions = queryInstructionsRaw;
691
704
  if (!["create", "set", "drop"].includes(queryType)) return queryInstructions;
692
- if (!SYSTEM_SCHEMA_SLUGS.includes(querySchema)) return queryInstructions;
705
+ if (!SYSTEM_MODEL_SLUGS.includes(queryModel)) return queryInstructions;
693
706
  const instructionName = mappedInstructions[queryType];
694
707
  const instructionList = queryInstructions[instructionName];
695
- const kind = getSchemaBySlug(SYSTEM_SCHEMAS, querySchema).pluralSlug;
708
+ const kind = getModelBySlug(SYSTEM_MODELS, queryModel).pluralSlug;
696
709
  let tableAction = "ALTER";
697
710
  let queryTypeReadable = null;
698
711
  switch (queryType) {
699
712
  case "create": {
700
- if (kind === "schemas" || kind === "indexes" || kind === "triggers") {
713
+ if (kind === "models" || kind === "indexes" || kind === "triggers") {
701
714
  tableAction = "CREATE";
702
715
  }
703
716
  queryTypeReadable = "creating";
704
717
  break;
705
718
  }
706
719
  case "set": {
707
- if (kind === "schemas") tableAction = "ALTER";
720
+ if (kind === "models") tableAction = "ALTER";
708
721
  queryTypeReadable = "updating";
709
722
  break;
710
723
  }
711
724
  case "drop": {
712
- if (kind === "schemas" || kind === "indexes" || kind === "triggers") {
725
+ if (kind === "models" || kind === "indexes" || kind === "triggers") {
713
726
  tableAction = "DROP";
714
727
  }
715
728
  queryTypeReadable = "deleting";
@@ -724,18 +737,18 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
724
737
  fields: ["slug"]
725
738
  });
726
739
  }
727
- const schemaInstruction = instructionList?.schema;
728
- const schemaSlug = schemaInstruction?.slug?.being || schemaInstruction?.slug;
729
- if (kind !== "schemas" && !schemaSlug) {
740
+ const modelInstruction = instructionList?.model;
741
+ const modelSlug = modelInstruction?.slug?.being || modelInstruction?.slug;
742
+ if (kind !== "models" && !modelSlug) {
730
743
  throw new RoninError({
731
- message: `When ${queryTypeReadable} ${kind}, a \`schema.slug\` field must be provided in the \`${instructionName}\` instruction.`,
744
+ message: `When ${queryTypeReadable} ${kind}, a \`model.slug\` field must be provided in the \`${instructionName}\` instruction.`,
732
745
  code: "MISSING_FIELD",
733
- fields: ["schema.slug"]
746
+ fields: ["model.slug"]
734
747
  });
735
748
  }
736
- const usableSlug = kind === "schemas" ? slug : schemaSlug;
749
+ const usableSlug = kind === "models" ? slug : modelSlug;
737
750
  const tableName = convertToSnakeCase(pluralize(usableSlug));
738
- const targetSchema = kind === "schemas" && queryType === "create" ? null : getSchemaBySlug(schemas, usableSlug);
751
+ const targetModel = kind === "models" && queryType === "create" ? null : getModelBySlug(models, usableSlug);
739
752
  if (kind === "indexes") {
740
753
  const indexName = convertToSnakeCase(slug);
741
754
  const unique = instructionList?.unique;
@@ -744,16 +757,13 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
744
757
  const params = [];
745
758
  let statement2 = `${tableAction}${unique ? " UNIQUE" : ""} INDEX "${indexName}"`;
746
759
  if (queryType === "create") {
747
- const schema = targetSchema;
760
+ const model = targetModel;
748
761
  const columns = fields.map((field) => {
749
762
  let fieldSelector = "";
750
763
  if ("slug" in field) {
751
- ({ fieldSelector } = getFieldFromSchema(schema, field.slug, "to"));
764
+ ({ fieldSelector } = getFieldFromModel(model, field.slug, "to"));
752
765
  } else if ("expression" in field) {
753
- fieldSelector = field.expression.replace(RONIN_SCHEMA_FIELD_REGEX, (match) => {
754
- const fieldSlug = match.replace(RONIN_SCHEMA_SYMBOLS.FIELD, "");
755
- return getFieldFromSchema(schema, fieldSlug, "to").fieldSelector;
756
- });
766
+ fieldSelector = parseFieldExpression(model, "to", field.expression, model);
757
767
  }
758
768
  if (field.collation) fieldSelector += ` COLLATE ${field.collation}`;
759
769
  if (field.order) fieldSelector += ` ${field.order}`;
@@ -762,8 +772,8 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
762
772
  statement2 += ` ON "${tableName}" (${columns.join(", ")})`;
763
773
  if (filterQuery) {
764
774
  const withStatement = handleWith(
765
- schemas,
766
- targetSchema,
775
+ models,
776
+ targetModel,
767
777
  params,
768
778
  filterQuery
769
779
  );
@@ -778,6 +788,7 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
778
788
  const params = [];
779
789
  let statement2 = `${tableAction} TRIGGER "${triggerName}"`;
780
790
  if (queryType === "create") {
791
+ const currentModel = targetModel;
781
792
  const { when, action } = instructionList;
782
793
  const statementParts = [`${when} ${action}`];
783
794
  const effectQueries = instructionList?.effects;
@@ -787,33 +798,33 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
787
798
  if (action !== "UPDATE") {
788
799
  throw new RoninError({
789
800
  message: `When ${queryTypeReadable} ${kind}, targeting specific fields requires the \`UPDATE\` action.`,
790
- code: "INVALID_SCHEMA_VALUE",
801
+ code: "INVALID_MODEL_VALUE",
791
802
  fields: ["action"]
792
803
  });
793
804
  }
794
805
  const fieldSelectors = fields.map((field) => {
795
- return getFieldFromSchema(targetSchema, field.slug, "to").fieldSelector;
806
+ return getFieldFromModel(currentModel, field.slug, "to").fieldSelector;
796
807
  });
797
808
  statementParts.push(`OF (${fieldSelectors.join(", ")})`);
798
809
  }
799
810
  statementParts.push("ON", `"${tableName}"`);
800
- if (filterQuery || effectQueries.some((query) => findInObject(query, RONIN_SCHEMA_SYMBOLS.FIELD))) {
811
+ if (filterQuery || effectQueries.some((query) => findInObject(query, RONIN_MODEL_SYMBOLS.FIELD))) {
801
812
  statementParts.push("FOR EACH ROW");
802
813
  }
803
814
  if (filterQuery) {
804
- const tablePlaceholder = action === "DELETE" ? RONIN_SCHEMA_SYMBOLS.FIELD_OLD : RONIN_SCHEMA_SYMBOLS.FIELD_NEW;
815
+ const tableAlias = action === "DELETE" ? RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD : RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW;
805
816
  const withStatement = handleWith(
806
- schemas,
807
- targetSchema,
817
+ models,
818
+ { ...currentModel, tableAlias },
808
819
  params,
809
- filterQuery,
810
- tablePlaceholder
820
+ filterQuery
811
821
  );
812
822
  statementParts.push("WHEN", `(${withStatement})`);
813
823
  }
814
824
  const effectStatements = effectQueries.map((effectQuery) => {
815
- return compileQueryInput(effectQuery, schemas, params, {
816
- returning: false
825
+ return compileQueryInput(effectQuery, models, params, {
826
+ returning: false,
827
+ parentModel: currentModel
817
828
  }).main.statement;
818
829
  });
819
830
  if (effectStatements.length > 1) statementParts.push("BEGIN");
@@ -825,14 +836,14 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
825
836
  return queryInstructions;
826
837
  }
827
838
  const statement = `${tableAction} TABLE "${tableName}"`;
828
- if (kind === "schemas") {
839
+ if (kind === "models") {
829
840
  if (queryType === "create" || queryType === "set") {
830
- const schemaWithFields = addDefaultSchemaFields(
841
+ const modelWithFields = addDefaultModelFields(
831
842
  queryInstructions.to,
832
843
  queryType === "create"
833
844
  );
834
- const schemaWithPresets = addDefaultSchemaPresets(schemas, schemaWithFields);
835
- queryInstructions.to = schemaWithPresets;
845
+ const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
846
+ queryInstructions.to = modelWithPresets;
836
847
  }
837
848
  if (queryType === "create") {
838
849
  const { fields } = queryInstructions.to;
@@ -841,7 +852,7 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
841
852
  statement: `${statement} (${columns.join(", ")})`,
842
853
  params: []
843
854
  });
844
- schemas.push(queryInstructions.to);
855
+ models.push(queryInstructions.to);
845
856
  } else if (queryType === "set") {
846
857
  const newSlug = queryInstructions.to?.pluralSlug;
847
858
  if (newSlug) {
@@ -851,9 +862,9 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
851
862
  params: []
852
863
  });
853
864
  }
854
- Object.assign(targetSchema, queryInstructions.to);
865
+ Object.assign(targetModel, queryInstructions.to);
855
866
  } else if (queryType === "drop") {
856
- schemas.splice(schemas.indexOf(targetSchema), 1);
867
+ models.splice(models.indexOf(targetModel), 1);
857
868
  dependencyStatements.push({ statement, params: [] });
858
869
  }
859
870
  return queryInstructions;
@@ -892,7 +903,7 @@ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
892
903
  // src/instructions/before-after.ts
893
904
  var CURSOR_SEPARATOR = ",";
894
905
  var CURSOR_NULL_PLACEHOLDER = "RONIN_NULL";
895
- var handleBeforeOrAfter = (schema, statementParams, instructions, rootTable) => {
906
+ var handleBeforeOrAfter = (model, statementParams, instructions) => {
896
907
  if (!(instructions.before || instructions.after)) {
897
908
  throw new RoninError({
898
909
  message: "The `before` or `after` instruction must not be empty.",
@@ -923,7 +934,7 @@ var handleBeforeOrAfter = (schema, statementParams, instructions, rootTable) =>
923
934
  if (value === CURSOR_NULL_PLACEHOLDER) {
924
935
  return "NULL";
925
936
  }
926
- const { field } = getFieldFromSchema(schema, key, "orderedBy");
937
+ const { field } = getFieldFromModel(model, key, "orderedBy");
927
938
  if (field.type === "boolean") {
928
939
  return prepareStatementValue(statementParams, value === "true");
929
940
  }
@@ -949,12 +960,7 @@ var handleBeforeOrAfter = (schema, statementParams, instructions, rootTable) =>
949
960
  for (let j = 0; j <= i; j++) {
950
961
  const key = keys[j];
951
962
  const value = values[j];
952
- let { field, fieldSelector } = getFieldFromSchema(
953
- schema,
954
- key,
955
- "orderedBy",
956
- rootTable
957
- );
963
+ let { field, fieldSelector } = getFieldFromModel(model, key, "orderedBy");
958
964
  if (j === i) {
959
965
  const closingParentheses = ")".repeat(condition.length);
960
966
  const operator = value === "NULL" ? "IS NOT" : compareOperators[j];
@@ -976,14 +982,14 @@ var handleBeforeOrAfter = (schema, statementParams, instructions, rootTable) =>
976
982
  };
977
983
 
978
984
  // src/instructions/for.ts
979
- var handleFor = (schema, instructions) => {
985
+ var handleFor = (model, instructions) => {
980
986
  const normalizedFor = Array.isArray(instructions.for) ? Object.fromEntries(instructions.for.map((presetSlug) => [presetSlug, null])) : instructions.for;
981
987
  for (const presetSlug in normalizedFor) {
982
988
  const arg = normalizedFor[presetSlug];
983
- const preset = schema.presets?.find((preset2) => preset2.slug === presetSlug);
989
+ const preset = model.presets?.find((preset2) => preset2.slug === presetSlug);
984
990
  if (!preset) {
985
991
  throw new RoninError({
986
- message: `Preset "${presetSlug}" does not exist in schema "${schema.name}".`,
992
+ message: `Preset "${presetSlug}" does not exist in model "${model.name}".`,
987
993
  code: "PRESET_NOT_FOUND"
988
994
  });
989
995
  }
@@ -991,8 +997,8 @@ var handleFor = (schema, instructions) => {
991
997
  if (arg !== null) {
992
998
  findInObject(
993
999
  replacedForFilter,
994
- RONIN_SCHEMA_SYMBOLS.VALUE,
995
- (match) => match.replace(RONIN_SCHEMA_SYMBOLS.VALUE, arg)
1000
+ RONIN_MODEL_SYMBOLS.VALUE,
1001
+ (match) => match.replace(RONIN_MODEL_SYMBOLS.VALUE, arg)
996
1002
  );
997
1003
  }
998
1004
  for (const subInstruction in replacedForFilter) {
@@ -1023,20 +1029,19 @@ var handleFor = (schema, instructions) => {
1023
1029
  };
1024
1030
 
1025
1031
  // src/instructions/including.ts
1026
- var handleIncluding = (schemas, statementParams, instruction, rootTable) => {
1032
+ var handleIncluding = (models, model, statementParams, instruction) => {
1027
1033
  let statement = "";
1028
- let rootTableSubQuery;
1029
- let rootTableName = rootTable;
1034
+ let tableSubQuery;
1030
1035
  for (const ephemeralFieldSlug in instruction) {
1031
- const includingQuery = getSubQuery(instruction[ephemeralFieldSlug]);
1032
- if (!includingQuery) continue;
1033
- const { queryType, querySchema, queryInstructions } = splitQuery(includingQuery);
1036
+ const symbol = getSymbol(instruction[ephemeralFieldSlug]);
1037
+ if (symbol?.type !== "query") continue;
1038
+ const { queryType, queryModel, queryInstructions } = splitQuery(symbol.value);
1034
1039
  let modifiableQueryInstructions = queryInstructions;
1035
- const relatedSchema = getSchemaBySlug(schemas, querySchema);
1040
+ const relatedModel = getModelBySlug(models, queryModel);
1036
1041
  let joinType = "LEFT";
1037
- let relatedTableSelector = `"${getTableForSchema(relatedSchema)}"`;
1042
+ let relatedTableSelector = `"${relatedModel.table}"`;
1038
1043
  const tableAlias = `including_${ephemeralFieldSlug}`;
1039
- const single = querySchema !== relatedSchema.pluralSlug;
1044
+ const single = queryModel !== relatedModel.pluralSlug;
1040
1045
  if (!modifiableQueryInstructions?.with) {
1041
1046
  joinType = "CROSS";
1042
1047
  if (single) {
@@ -1048,35 +1053,35 @@ var handleIncluding = (schemas, statementParams, instruction, rootTable) => {
1048
1053
  const subSelect = compileQueryInput(
1049
1054
  {
1050
1055
  [queryType]: {
1051
- [querySchema]: modifiableQueryInstructions
1056
+ [queryModel]: modifiableQueryInstructions
1052
1057
  }
1053
1058
  },
1054
- schemas,
1059
+ models,
1055
1060
  statementParams
1056
1061
  );
1057
1062
  relatedTableSelector = `(${subSelect.main.statement})`;
1058
1063
  }
1059
1064
  statement += `${joinType} JOIN ${relatedTableSelector} as ${tableAlias}`;
1065
+ model.tableAlias = model.table;
1060
1066
  if (joinType === "LEFT") {
1061
1067
  if (!single) {
1062
- rootTableSubQuery = `SELECT * FROM "${rootTable}" LIMIT 1`;
1063
- rootTableName = `sub_${rootTable}`;
1068
+ tableSubQuery = `SELECT * FROM "${model.table}" LIMIT 1`;
1069
+ model.tableAlias = `sub_${model.table}`;
1064
1070
  }
1065
1071
  const subStatement = composeConditions(
1066
- schemas,
1067
- relatedSchema,
1072
+ models,
1073
+ { ...relatedModel, tableAlias },
1068
1074
  statementParams,
1069
1075
  "including",
1070
1076
  queryInstructions?.with,
1071
1077
  {
1072
- rootTable: rootTableName,
1073
- customTable: tableAlias
1078
+ parentModel: model
1074
1079
  }
1075
1080
  );
1076
1081
  statement += ` ON (${subStatement})`;
1077
1082
  }
1078
1083
  }
1079
- return { statement, rootTableSubQuery, rootTableName };
1084
+ return { statement, tableSubQuery };
1080
1085
  };
1081
1086
 
1082
1087
  // src/instructions/limited-to.ts
@@ -1088,46 +1093,43 @@ var handleLimitedTo = (single, instruction) => {
1088
1093
  };
1089
1094
 
1090
1095
  // src/instructions/ordered-by.ts
1091
- var handleOrderedBy = (schema, instruction, rootTable) => {
1096
+ var handleOrderedBy = (model, instruction) => {
1092
1097
  let statement = "";
1093
- for (const field of instruction.ascending || []) {
1094
- const { field: schemaField, fieldSelector } = getFieldFromSchema(
1095
- schema,
1096
- field,
1097
- "orderedBy.ascending",
1098
- rootTable
1099
- );
1098
+ const items = [
1099
+ ...(instruction.ascending || []).map((value) => ({ value, order: "ASC" })),
1100
+ ...(instruction.descending || []).map((value) => ({ value, order: "DESC" }))
1101
+ ];
1102
+ for (const item of items) {
1100
1103
  if (statement.length > 0) {
1101
1104
  statement += ", ";
1102
1105
  }
1103
- const caseInsensitiveStatement = schemaField.type === "string" ? " COLLATE NOCASE" : "";
1104
- statement += `${fieldSelector}${caseInsensitiveStatement} ASC`;
1105
- }
1106
- for (const field of instruction.descending || []) {
1107
- const { field: schemaField, fieldSelector } = getFieldFromSchema(
1108
- schema,
1109
- field,
1110
- "orderedBy.descending",
1111
- rootTable
1112
- );
1113
- if (statement.length > 0) {
1114
- statement += ", ";
1106
+ const symbol = getSymbol(item.value);
1107
+ const instructionName = item.order === "ASC" ? "orderedBy.ascending" : "orderedBy.descending";
1108
+ if (symbol?.type === "expression") {
1109
+ statement += `(${parseFieldExpression(model, instructionName, symbol.value)}) ${item.order}`;
1110
+ continue;
1115
1111
  }
1116
- const caseInsensitiveStatement = schemaField.type === "string" ? " COLLATE NOCASE" : "";
1117
- statement += `${fieldSelector}${caseInsensitiveStatement} DESC`;
1112
+ const { field: modelField, fieldSelector } = getFieldFromModel(
1113
+ model,
1114
+ item.value,
1115
+ instructionName
1116
+ );
1117
+ const caseInsensitiveStatement = modelField.type === "string" ? " COLLATE NOCASE" : "";
1118
+ statement += `${fieldSelector}${caseInsensitiveStatement} ${item.order}`;
1118
1119
  }
1119
1120
  return `ORDER BY ${statement}`;
1120
1121
  };
1121
1122
 
1122
1123
  // src/instructions/selecting.ts
1123
- var handleSelecting = (schema, statementParams, instructions) => {
1124
+ var handleSelecting = (model, statementParams, instructions) => {
1124
1125
  let isJoining = false;
1125
1126
  let statement = instructions.selecting ? instructions.selecting.map((slug) => {
1126
- return getFieldFromSchema(schema, slug, "selecting").fieldSelector;
1127
+ return getFieldFromModel(model, slug, "selecting").fieldSelector;
1127
1128
  }).join(", ") : "*";
1128
1129
  if (instructions.including) {
1129
1130
  const filteredObject = Object.entries(instructions.including).filter(([_, value]) => {
1130
- const hasQuery = getSubQuery(value);
1131
+ const symbol = getSymbol(value);
1132
+ const hasQuery = symbol?.type === "query";
1131
1133
  if (hasQuery) isJoining = true;
1132
1134
  return !hasQuery;
1133
1135
  });
@@ -1143,12 +1145,12 @@ var handleSelecting = (schema, statementParams, instructions) => {
1143
1145
  };
1144
1146
 
1145
1147
  // src/instructions/to.ts
1146
- var handleTo = (schemas, schema, statementParams, queryType, dependencyStatements, instructions, rootTable) => {
1148
+ var handleTo = (models, model, statementParams, queryType, dependencyStatements, instructions, parentModel) => {
1147
1149
  const currentTime = (/* @__PURE__ */ new Date()).toISOString();
1148
1150
  const { with: withInstruction, to: toInstruction } = instructions;
1149
1151
  const defaultFields = {};
1150
1152
  if (queryType === "create") {
1151
- defaultFields.id = toInstruction.id || generateRecordId(schema.idPrefix);
1153
+ defaultFields.id = toInstruction.id || generateRecordId(model.idPrefix);
1152
1154
  }
1153
1155
  defaultFields.ronin = {
1154
1156
  // If records are being created, set their creation time.
@@ -1158,20 +1160,20 @@ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatement
1158
1160
  // Allow for overwriting the default values provided above.
1159
1161
  ...toInstruction.ronin
1160
1162
  };
1161
- const subQuery = getSubQuery(toInstruction);
1162
- if (subQuery) {
1163
- let { querySchema: subQuerySchemaSlug, queryInstructions: subQueryInstructions } = splitQuery(subQuery);
1164
- const subQuerySchema = getSchemaBySlug(schemas, subQuerySchemaSlug);
1163
+ const symbol = getSymbol(toInstruction);
1164
+ if (symbol?.type === "query") {
1165
+ let { queryModel: subQueryModelSlug, queryInstructions: subQueryInstructions } = splitQuery(symbol.value);
1166
+ const subQueryModel = getModelBySlug(models, subQueryModelSlug);
1165
1167
  const subQuerySelectedFields = subQueryInstructions?.selecting;
1166
1168
  const subQueryIncludedFields = subQueryInstructions?.including;
1167
1169
  const subQueryFields = [
1168
- ...subQuerySelectedFields || (subQuerySchema.fields || []).map((field) => field.slug),
1170
+ ...subQuerySelectedFields || (subQueryModel.fields || []).map((field) => field.slug),
1169
1171
  ...subQueryIncludedFields ? Object.keys(
1170
1172
  flatten(subQueryIncludedFields || {})
1171
1173
  ) : []
1172
1174
  ];
1173
1175
  for (const field of subQueryFields || []) {
1174
- getFieldFromSchema(schema, field, "to");
1176
+ getFieldFromModel(model, field, "to");
1175
1177
  }
1176
1178
  const defaultFieldsToAdd = subQuerySelectedFields ? Object.entries(flatten(defaultFields)).filter(([key]) => {
1177
1179
  return !subQuerySelectedFields.includes(key);
@@ -1184,18 +1186,15 @@ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatement
1184
1186
  ...subQueryInstructions.including
1185
1187
  };
1186
1188
  }
1187
- return compileQueryInput(subQuery, schemas, statementParams).main.statement;
1189
+ return compileQueryInput(symbol.value, models, statementParams).main.statement;
1188
1190
  }
1189
1191
  Object.assign(toInstruction, defaultFields);
1190
1192
  for (const fieldSlug in toInstruction) {
1191
1193
  const fieldValue = toInstruction[fieldSlug];
1192
- const fieldDetails = getFieldFromSchema(schema, fieldSlug, "to");
1194
+ const fieldDetails = getFieldFromModel(model, fieldSlug, "to");
1193
1195
  if (fieldDetails.field.type === "reference" && fieldDetails.field.kind === "many") {
1194
1196
  delete toInstruction[fieldSlug];
1195
- const associativeSchemaSlug = composeAssociationSchemaSlug(
1196
- schema,
1197
- fieldDetails.field
1198
- );
1197
+ const associativeModelSlug = composeAssociationModelSlug(model, fieldDetails.field);
1199
1198
  const composeStatement = (subQueryType, value) => {
1200
1199
  const source = queryType === "create" ? { id: toInstruction.id } : withInstruction;
1201
1200
  const recordDetails = { source };
@@ -1203,10 +1202,10 @@ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatement
1203
1202
  return compileQueryInput(
1204
1203
  {
1205
1204
  [subQueryType]: {
1206
- [associativeSchemaSlug]: subQueryType === "create" ? { to: recordDetails } : { with: recordDetails }
1205
+ [associativeModelSlug]: subQueryType === "create" ? { to: recordDetails } : { with: recordDetails }
1207
1206
  }
1208
1207
  },
1209
- schemas,
1208
+ models,
1210
1209
  [],
1211
1210
  { returning: false }
1212
1211
  ).main;
@@ -1226,26 +1225,19 @@ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatement
1226
1225
  }
1227
1226
  }
1228
1227
  }
1229
- let statement = composeConditions(
1230
- schemas,
1231
- schema,
1232
- statementParams,
1233
- "to",
1234
- toInstruction,
1235
- {
1236
- rootTable,
1237
- type: queryType === "create" ? "fields" : void 0
1238
- }
1239
- );
1228
+ let statement = composeConditions(models, model, statementParams, "to", toInstruction, {
1229
+ parentModel,
1230
+ type: queryType === "create" ? "fields" : void 0
1231
+ });
1240
1232
  if (queryType === "create") {
1241
1233
  const deepStatement = composeConditions(
1242
- schemas,
1243
- schema,
1234
+ models,
1235
+ model,
1244
1236
  statementParams,
1245
1237
  "to",
1246
1238
  toInstruction,
1247
1239
  {
1248
- rootTable,
1240
+ parentModel,
1249
1241
  type: "values"
1250
1242
  }
1251
1243
  );
@@ -1257,24 +1249,23 @@ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatement
1257
1249
  };
1258
1250
 
1259
1251
  // src/utils/index.ts
1260
- var compileQueryInput = (query, schemas, statementParams, options) => {
1252
+ var compileQueryInput = (query, models, statementParams, options) => {
1261
1253
  const parsedQuery = splitQuery(query);
1262
- const { queryType, querySchema, queryInstructions } = parsedQuery;
1263
- const schema = getSchemaBySlug(schemas, querySchema);
1264
- const single = querySchema !== schema.pluralSlug;
1265
- let instructions = formatIdentifiers(schema, queryInstructions);
1266
- let table = getTableForSchema(schema);
1254
+ const { queryType, queryModel, queryInstructions } = parsedQuery;
1255
+ const model = getModelBySlug(models, queryModel);
1256
+ const single = queryModel !== model.pluralSlug;
1257
+ let instructions = formatIdentifiers(model, queryInstructions);
1267
1258
  const dependencyStatements = [];
1268
1259
  const returning = options?.returning ?? true;
1269
- instructions = addSchemaQueries(
1270
- schemas,
1271
- { queryType, querySchema, queryInstructions: instructions },
1260
+ instructions = addModelQueries(
1261
+ models,
1262
+ { queryType, queryModel, queryInstructions: instructions },
1272
1263
  dependencyStatements
1273
1264
  );
1274
1265
  if (instructions && Object.hasOwn(instructions, "for")) {
1275
- instructions = handleFor(schema, instructions);
1266
+ instructions = handleFor(model, instructions);
1276
1267
  }
1277
- const { columns, isJoining } = handleSelecting(schema, statementParams, {
1268
+ const { columns, isJoining } = handleSelecting(model, statementParams, {
1278
1269
  selecting: instructions?.selecting,
1279
1270
  including: instructions?.including
1280
1271
  });
@@ -1298,21 +1289,21 @@ var compileQueryInput = (query, schemas, statementParams, options) => {
1298
1289
  }
1299
1290
  let isJoiningMultipleRows = false;
1300
1291
  if (isJoining) {
1301
- const {
1302
- statement: including,
1303
- rootTableSubQuery,
1304
- rootTableName
1305
- } = handleIncluding(schemas, statementParams, instructions?.including, table);
1306
- if (rootTableSubQuery && rootTableName) {
1307
- table = rootTableName;
1308
- statement += `(${rootTableSubQuery}) as ${rootTableName} `;
1292
+ const { statement: including, tableSubQuery } = handleIncluding(
1293
+ models,
1294
+ model,
1295
+ statementParams,
1296
+ instructions?.including
1297
+ );
1298
+ if (tableSubQuery) {
1299
+ statement += `(${tableSubQuery}) as ${model.tableAlias} `;
1309
1300
  isJoiningMultipleRows = true;
1310
1301
  } else {
1311
- statement += `"${table}" `;
1302
+ statement += `"${model.table}" `;
1312
1303
  }
1313
1304
  statement += `${including} `;
1314
1305
  } else {
1315
- statement += `"${table}" `;
1306
+ statement += `"${model.table}" `;
1316
1307
  }
1317
1308
  if (queryType === "create" || queryType === "set") {
1318
1309
  if (!isObject(instructions.to) || Object.keys(instructions.to).length === 0) {
@@ -1323,24 +1314,24 @@ var compileQueryInput = (query, schemas, statementParams, options) => {
1323
1314
  });
1324
1315
  }
1325
1316
  const toStatement = handleTo(
1326
- schemas,
1327
- schema,
1317
+ models,
1318
+ model,
1328
1319
  statementParams,
1329
1320
  queryType,
1330
1321
  dependencyStatements,
1331
1322
  { with: instructions.with, to: instructions.to },
1332
- isJoining ? table : void 0
1323
+ options?.parentModel
1333
1324
  );
1334
1325
  statement += `${toStatement} `;
1335
1326
  }
1336
1327
  const conditions = [];
1337
1328
  if (queryType !== "create" && instructions && Object.hasOwn(instructions, "with")) {
1338
1329
  const withStatement = handleWith(
1339
- schemas,
1340
- schema,
1330
+ models,
1331
+ model,
1341
1332
  statementParams,
1342
1333
  instructions?.with,
1343
- isJoining ? table : void 0
1334
+ options?.parentModel
1344
1335
  );
1345
1336
  if (withStatement.length > 0) conditions.push(withStatement);
1346
1337
  }
@@ -1364,18 +1355,13 @@ var compileQueryInput = (query, schemas, statementParams, options) => {
1364
1355
  queries: [query]
1365
1356
  });
1366
1357
  }
1367
- const beforeAndAfterStatement = handleBeforeOrAfter(
1368
- schema,
1369
- statementParams,
1370
- {
1371
- before: instructions.before,
1372
- after: instructions.after,
1373
- with: instructions.with,
1374
- orderedBy: instructions.orderedBy,
1375
- limitedTo: instructions.limitedTo
1376
- },
1377
- isJoining ? table : void 0
1378
- );
1358
+ const beforeAndAfterStatement = handleBeforeOrAfter(model, statementParams, {
1359
+ before: instructions.before,
1360
+ after: instructions.after,
1361
+ with: instructions.with,
1362
+ orderedBy: instructions.orderedBy,
1363
+ limitedTo: instructions.limitedTo
1364
+ });
1379
1365
  conditions.push(beforeAndAfterStatement);
1380
1366
  }
1381
1367
  if (conditions.length > 0) {
@@ -1386,11 +1372,7 @@ var compileQueryInput = (query, schemas, statementParams, options) => {
1386
1372
  }
1387
1373
  }
1388
1374
  if (instructions?.orderedBy) {
1389
- const orderedByStatement = handleOrderedBy(
1390
- schema,
1391
- instructions.orderedBy,
1392
- isJoining ? table : void 0
1393
- );
1375
+ const orderedByStatement = handleOrderedBy(model, instructions.orderedBy);
1394
1376
  statement += `${orderedByStatement} `;
1395
1377
  }
1396
1378
  if (queryType === "get" && !isJoiningMultipleRows && (single || instructions?.limitedTo)) {
@@ -1411,19 +1393,19 @@ var compileQueryInput = (query, schemas, statementParams, options) => {
1411
1393
  };
1412
1394
 
1413
1395
  // src/index.ts
1414
- var compileQueries = (queries, schemas, options) => {
1415
- const schemaList = addSystemSchemas(schemas).map((schema) => {
1416
- return addDefaultSchemaFields(schema, true);
1396
+ var compileQueries = (queries, models, options) => {
1397
+ const modelList = addSystemModels(models).map((model) => {
1398
+ return addDefaultModelFields(model, true);
1417
1399
  });
1418
- const schemaListWithPresets = schemaList.map((schema) => {
1419
- return addDefaultSchemaPresets(schemaList, schema);
1400
+ const modelListWithPresets = modelList.map((model) => {
1401
+ return addDefaultModelPresets(modelList, model);
1420
1402
  });
1421
1403
  const dependencyStatements = [];
1422
1404
  const mainStatements = [];
1423
1405
  for (const query of queries) {
1424
1406
  const result = compileQueryInput(
1425
1407
  query,
1426
- schemaListWithPresets,
1408
+ modelListWithPresets,
1427
1409
  options?.inlineParams ? null : []
1428
1410
  );
1429
1411
  dependencyStatements.push(...result.dependencies);