@ronin/compiler 0.2.2 → 0.3.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 (2) hide show
  1. package/dist/index.js +296 -204
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,8 +1,15 @@
1
1
  // src/utils/index.ts
2
2
  import { init as cuid } from "@paralleldrive/cuid2";
3
3
  var RONIN_SCHEMA_SYMBOLS = {
4
+ // Represents a sub query.
4
5
  QUERY: "__RONIN_QUERY",
6
+ // Represents the value of a field in a schema.
5
7
  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_",
12
+ // Represents a value provided to a query preset.
6
13
  VALUE: "__RONIN_VALUE"
7
14
  };
8
15
  var RoninError = class extends Error {
@@ -44,15 +51,22 @@ var convertToCamelCase = (str) => {
44
51
  return sanitize(str).split(SPLIT_REGEX).map((part, index) => index === 0 ? part.toLowerCase() : capitalize(part)).join("");
45
52
  };
46
53
  var isObject = (value) => value != null && typeof value === "object" && Array.isArray(value) === false;
47
- var replaceInObject = (obj, pattern, replacer) => {
54
+ var findInObject = (obj, pattern, replacer) => {
55
+ let found = false;
48
56
  for (const key in obj) {
49
57
  const value = obj[key];
50
58
  if (isObject(value)) {
51
- replaceInObject(value, pattern, replacer);
59
+ found = findInObject(value, pattern, replacer);
52
60
  } else if (typeof value === "string" && value.startsWith(pattern)) {
53
- obj[key] = value.replace(pattern, replacer);
61
+ found = true;
62
+ if (replacer) {
63
+ obj[key] = value.replace(pattern, replacer);
64
+ } else {
65
+ return found;
66
+ }
54
67
  }
55
68
  }
69
+ return found;
56
70
  };
57
71
  var flatten = (obj, prefix = "", res = {}) => {
58
72
  for (const key in obj) {
@@ -81,6 +95,209 @@ var splitQuery = (query) => {
81
95
  return { queryType, querySchema, queryInstructions };
82
96
  };
83
97
 
98
+ // src/utils/statement.ts
99
+ var prepareStatementValue = (statementValues, value, bindNull = false) => {
100
+ if (!bindNull && value === null) return "NULL";
101
+ let formattedValue = value;
102
+ if (Array.isArray(value) || isObject(value)) {
103
+ formattedValue = JSON.stringify(value);
104
+ } else if (typeof value === "boolean") {
105
+ formattedValue = value ? 1 : 0;
106
+ }
107
+ const index = statementValues.push(formattedValue);
108
+ return `?${index}`;
109
+ };
110
+ var composeFieldValues = (schemas, schema, statementValues, instructionName, value, options) => {
111
+ const { field: schemaField, fieldSelector: selector } = getFieldFromSchema(
112
+ schema,
113
+ options.fieldSlug,
114
+ instructionName,
115
+ options.rootTable
116
+ );
117
+ const isSubQuery = isObject(value) && Object.hasOwn(value, RONIN_SCHEMA_SYMBOLS.QUERY);
118
+ const collectStatementValue = options.type !== "fields";
119
+ let conditionSelector = selector;
120
+ let conditionValue = value;
121
+ if (isSubQuery && collectStatementValue) {
122
+ conditionValue = `(${compileQueryInput(
123
+ value[RONIN_SCHEMA_SYMBOLS.QUERY],
124
+ schemas,
125
+ { statementValues }
126
+ ).readStatement})`;
127
+ } else if (typeof value === "string" && value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD)) {
128
+ let targetTable = `"${options.rootTable}"`;
129
+ let toReplace = RONIN_SCHEMA_SYMBOLS.FIELD;
130
+ if (value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD_OLD)) {
131
+ targetTable = "OLD";
132
+ toReplace = RONIN_SCHEMA_SYMBOLS.FIELD_OLD;
133
+ } else if (value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD_NEW)) {
134
+ targetTable = "NEW";
135
+ toReplace = RONIN_SCHEMA_SYMBOLS.FIELD_NEW;
136
+ }
137
+ conditionSelector = `${options.customTable ? `"${options.customTable}".` : ""}"${schemaField.slug}"`;
138
+ conditionValue = `${targetTable}."${value.replace(toReplace, "")}"`;
139
+ } else if (schemaField.type === "json" && instructionName === "to") {
140
+ conditionSelector = `"${schemaField.slug}"`;
141
+ if (collectStatementValue) {
142
+ const preparedValue = prepareStatementValue(statementValues, value, false);
143
+ conditionValue = `IIF(${conditionSelector} IS NULL, ${preparedValue}, json_patch(${conditionSelector}, ${preparedValue}))`;
144
+ }
145
+ } else if (collectStatementValue) {
146
+ conditionValue = prepareStatementValue(statementValues, value, false);
147
+ }
148
+ if (options.type === "fields") return conditionSelector;
149
+ if (options.type === "values") return conditionValue;
150
+ return `${conditionSelector} ${WITH_CONDITIONS[options.condition || "being"](conditionValue, value)}`;
151
+ };
152
+ var composeConditions = (schemas, schema, statementValues, instructionName, value, options) => {
153
+ const isNested = isObject(value) && Object.keys(value).length > 0;
154
+ if (isNested && Object.keys(value).every((key) => key in WITH_CONDITIONS)) {
155
+ const conditions = Object.entries(value).map(
156
+ ([conditionType, checkValue]) => composeConditions(schemas, schema, statementValues, instructionName, checkValue, {
157
+ ...options,
158
+ condition: conditionType
159
+ })
160
+ );
161
+ return conditions.join(" AND ");
162
+ }
163
+ if (options.fieldSlug) {
164
+ const fieldDetails = getFieldFromSchema(
165
+ schema,
166
+ options.fieldSlug,
167
+ instructionName,
168
+ options.rootTable
169
+ );
170
+ const { field: schemaField } = fieldDetails;
171
+ const consumeJSON = schemaField.type === "json" && instructionName === "to";
172
+ const isSubQuery = isNested && Object.hasOwn(value, RONIN_SCHEMA_SYMBOLS.QUERY);
173
+ if (!(isObject(value) || Array.isArray(value)) || isSubQuery || consumeJSON) {
174
+ return composeFieldValues(
175
+ schemas,
176
+ schema,
177
+ statementValues,
178
+ instructionName,
179
+ value,
180
+ { ...options, fieldSlug: options.fieldSlug }
181
+ );
182
+ }
183
+ if (schemaField.type === "reference" && isNested) {
184
+ const keys = Object.keys(value);
185
+ const values = Object.values(value);
186
+ let recordTarget;
187
+ if (keys.length === 1 && keys[0] === "id") {
188
+ recordTarget = values[0];
189
+ } else {
190
+ const relatedSchema = getSchemaBySlug(schemas, schemaField.target.slug);
191
+ const subQuery = {
192
+ get: {
193
+ [relatedSchema.slug]: {
194
+ with: value,
195
+ selecting: ["id"]
196
+ }
197
+ }
198
+ };
199
+ recordTarget = {
200
+ [RONIN_SCHEMA_SYMBOLS.QUERY]: subQuery
201
+ };
202
+ }
203
+ return composeConditions(
204
+ schemas,
205
+ schema,
206
+ statementValues,
207
+ instructionName,
208
+ recordTarget,
209
+ options
210
+ );
211
+ }
212
+ }
213
+ if (isNested) {
214
+ const conditions = Object.entries(value).map(([field, value2]) => {
215
+ const nestedFieldSlug = options.fieldSlug ? `${options.fieldSlug}.${field}` : field;
216
+ return composeConditions(schemas, schema, statementValues, instructionName, value2, {
217
+ ...options,
218
+ fieldSlug: nestedFieldSlug
219
+ });
220
+ });
221
+ const joiner = instructionName === "to" ? ", " : " AND ";
222
+ if (instructionName === "to") return `${conditions.join(joiner)}`;
223
+ return conditions.length === 1 ? conditions[0] : options.fieldSlug ? `(${conditions.join(joiner)})` : conditions.join(joiner);
224
+ }
225
+ if (Array.isArray(value)) {
226
+ const conditions = value.map(
227
+ (filter) => composeConditions(
228
+ schemas,
229
+ schema,
230
+ statementValues,
231
+ instructionName,
232
+ filter,
233
+ options
234
+ )
235
+ );
236
+ return conditions.join(" OR ");
237
+ }
238
+ throw new RoninError({
239
+ message: `The \`with\` instruction must not contain an empty field. The following fields are empty: \`${options.fieldSlug}\`. If you meant to query by an empty field, try using \`null\` instead.`,
240
+ code: "INVALID_WITH_VALUE",
241
+ queries: null
242
+ });
243
+ };
244
+ var formatIdentifiers = ({ identifiers }, queryInstructions) => {
245
+ if (!queryInstructions) return queryInstructions;
246
+ const type = "with" in queryInstructions ? "with" : null;
247
+ if (!type) return queryInstructions;
248
+ const nestedInstructions = queryInstructions[type];
249
+ if (!nestedInstructions || Array.isArray(nestedInstructions))
250
+ return queryInstructions;
251
+ const newNestedInstructions = { ...nestedInstructions };
252
+ for (const oldKey of Object.keys(newNestedInstructions)) {
253
+ if (oldKey !== "titleIdentifier" && oldKey !== "slugIdentifier") continue;
254
+ const identifierName = oldKey === "titleIdentifier" ? "title" : "slug";
255
+ const value = newNestedInstructions[oldKey];
256
+ const newKey = identifiers?.[identifierName] || "id";
257
+ newNestedInstructions[newKey] = value;
258
+ delete newNestedInstructions[oldKey];
259
+ }
260
+ return {
261
+ ...queryInstructions,
262
+ [type]: newNestedInstructions
263
+ };
264
+ };
265
+
266
+ // src/instructions/with.ts
267
+ var getMatcher = (value, negative) => {
268
+ if (negative) {
269
+ if (value === null) return "IS NOT";
270
+ return "!=";
271
+ }
272
+ if (value === null) return "IS";
273
+ return "=";
274
+ };
275
+ var WITH_CONDITIONS = {
276
+ being: (value, baseValue) => `${getMatcher(baseValue, false)} ${value}`,
277
+ notBeing: (value, baseValue) => `${getMatcher(baseValue, true)} ${value}`,
278
+ startingWith: (value) => `LIKE ${value}%`,
279
+ notStartingWith: (value) => `NOT LIKE ${value}%`,
280
+ endingWith: (value) => `LIKE %${value}`,
281
+ notEndingWith: (value) => `NOT LIKE %${value}`,
282
+ containing: (value) => `LIKE %${value}%`,
283
+ notContaining: (value) => `NOT LIKE %${value}%`,
284
+ greaterThan: (value) => `> ${value}`,
285
+ greaterOrEqual: (value) => `>= ${value}`,
286
+ lessThan: (value) => `< ${value}`,
287
+ lessOrEqual: (value) => `<= ${value}`
288
+ };
289
+ var handleWith = (schemas, schema, statementValues, instruction, rootTable) => {
290
+ const subStatement = composeConditions(
291
+ schemas,
292
+ schema,
293
+ statementValues,
294
+ "with",
295
+ instruction,
296
+ { rootTable }
297
+ );
298
+ return `(${subStatement})`;
299
+ };
300
+
84
301
  // src/utils/schema.ts
85
302
  import title from "title";
86
303
  var getSchemaBySlug = (schemas, slug) => {
@@ -101,7 +318,8 @@ var getTableForSchema = (schema) => {
101
318
  var composeMetaSchemaSlug = (suffix) => convertToCamelCase(`ronin_${suffix}`);
102
319
  var composeAssociationSchemaSlug = (schema, field) => composeMetaSchemaSlug(`${schema.pluralSlug}_${field.slug}`);
103
320
  var getFieldSelector = (field, fieldPath, rootTable) => {
104
- const tablePrefix = rootTable ? `"${rootTable}".` : "";
321
+ const symbol = rootTable?.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD) ? `${rootTable.replace(RONIN_SCHEMA_SYMBOLS.FIELD, "").slice(0, -1)}.` : "";
322
+ const tablePrefix = symbol || (rootTable ? `"${rootTable}".` : "");
105
323
  if (field.type === "json") {
106
324
  const dotParts = fieldPath.split(".");
107
325
  const columnName = tablePrefix + dotParts.shift();
@@ -234,6 +452,20 @@ var SYSTEM_SCHEMAS = [
234
452
  { slug: "unique", type: "boolean" },
235
453
  { slug: "filter", type: "json" }
236
454
  ]
455
+ },
456
+ {
457
+ name: "Trigger",
458
+ pluralName: "Triggers",
459
+ slug: "trigger",
460
+ pluralSlug: "triggers",
461
+ fields: [
462
+ ...SYSTEM_FIELDS,
463
+ { slug: "slug", type: "string", required: true },
464
+ { slug: "schema", type: "reference", target: { slug: "schema" }, required: true },
465
+ { slug: "cause", type: "string", required: true },
466
+ { slug: "filter", type: "json" },
467
+ { slug: "effects", type: "json", required: true }
468
+ ]
237
469
  }
238
470
  ];
239
471
  var SYSTEM_SCHEMA_SLUGS = SYSTEM_SCHEMAS.flatMap(({ slug, pluralSlug }) => [
@@ -341,7 +573,7 @@ var getFieldStatement = (field) => {
341
573
  }
342
574
  return statement;
343
575
  };
344
- var addSchemaQueries = (queryDetails, writeStatements) => {
576
+ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements) => {
345
577
  const { queryType, querySchema, queryInstructions } = queryDetails;
346
578
  if (!["create", "set", "drop"].includes(queryType)) return;
347
579
  if (!SYSTEM_SCHEMA_SLUGS.includes(querySchema)) return;
@@ -352,7 +584,9 @@ var addSchemaQueries = (queryDetails, writeStatements) => {
352
584
  let queryTypeReadable = null;
353
585
  switch (queryType) {
354
586
  case "create": {
355
- if (kind === "schemas" || kind === "indexes") tableAction = "CREATE";
587
+ if (kind === "schemas" || kind === "indexes" || kind === "triggers") {
588
+ tableAction = "CREATE";
589
+ }
356
590
  queryTypeReadable = "creating";
357
591
  break;
358
592
  }
@@ -362,7 +596,9 @@ var addSchemaQueries = (queryDetails, writeStatements) => {
362
596
  break;
363
597
  }
364
598
  case "drop": {
365
- if (kind === "schemas" || kind === "indexes") tableAction = "DROP";
599
+ if (kind === "schemas" || kind === "indexes" || kind === "triggers") {
600
+ tableAction = "DROP";
601
+ }
366
602
  queryTypeReadable = "deleting";
367
603
  break;
368
604
  }
@@ -388,8 +624,58 @@ var addSchemaQueries = (queryDetails, writeStatements) => {
388
624
  if (kind === "indexes") {
389
625
  const indexName = convertToSnakeCase(slug);
390
626
  const unique = instructionList?.unique;
627
+ const filterQuery = instructionList?.filter;
391
628
  let statement2 = `${tableAction}${unique ? " UNIQUE" : ""} INDEX "${indexName}"`;
392
- if (queryType === "create") statement2 += ` ON "${tableName}"`;
629
+ if (queryType === "create") {
630
+ statement2 += ` ON "${tableName}"`;
631
+ if (filterQuery) {
632
+ const targetSchema = getSchemaBySlug(schemas, schemaSlug);
633
+ const withStatement = handleWith(
634
+ schemas,
635
+ targetSchema,
636
+ statementValues,
637
+ filterQuery
638
+ );
639
+ statement2 += ` WHERE (${withStatement})`;
640
+ }
641
+ }
642
+ writeStatements.push(statement2);
643
+ return;
644
+ }
645
+ if (kind === "triggers") {
646
+ const triggerName = convertToSnakeCase(slug);
647
+ let statement2 = `${tableAction} TRIGGER "${triggerName}"`;
648
+ if (queryType === "create") {
649
+ const cause = slugToName(instructionList?.cause).toUpperCase();
650
+ const statementParts = [cause, "ON", `"${tableName}"`];
651
+ const effectQueries = instructionList?.effects;
652
+ const filterQuery = instructionList?.filter;
653
+ if (filterQuery || effectQueries.some((query) => findInObject(query, RONIN_SCHEMA_SYMBOLS.FIELD))) {
654
+ statementParts.push("FOR EACH ROW");
655
+ }
656
+ if (filterQuery) {
657
+ const targetSchema = getSchemaBySlug(schemas, schemaSlug);
658
+ const tablePlaceholder = cause.endsWith("DELETE") ? RONIN_SCHEMA_SYMBOLS.FIELD_OLD : RONIN_SCHEMA_SYMBOLS.FIELD_NEW;
659
+ const withStatement = handleWith(
660
+ schemas,
661
+ targetSchema,
662
+ statementValues,
663
+ filterQuery,
664
+ tablePlaceholder
665
+ );
666
+ statementParts.push("WHEN", `(${withStatement})`);
667
+ }
668
+ const effectStatements = effectQueries.map((effectQuery) => {
669
+ return compileQueryInput(effectQuery, schemas, {
670
+ statementValues,
671
+ disableReturning: true
672
+ }).readStatement;
673
+ });
674
+ if (effectStatements.length > 1) statementParts.push("BEGIN");
675
+ statementParts.push(effectStatements.join("; "));
676
+ if (effectStatements.length > 1) statementParts.push("END");
677
+ statement2 += ` ${statementParts.join(" ")}`;
678
+ }
393
679
  writeStatements.push(statement2);
394
680
  return;
395
681
  }
@@ -447,200 +733,6 @@ var pluralize = (word) => {
447
733
  return `${word}s`;
448
734
  };
449
735
 
450
- // src/instructions/with.ts
451
- var getMatcher = (value, negative) => {
452
- if (negative) {
453
- if (value === null) return "IS NOT";
454
- return "!=";
455
- }
456
- if (value === null) return "IS";
457
- return "=";
458
- };
459
- var WITH_CONDITIONS = {
460
- being: (value, baseValue) => `${getMatcher(baseValue, false)} ${value}`,
461
- notBeing: (value, baseValue) => `${getMatcher(baseValue, true)} ${value}`,
462
- startingWith: (value) => `LIKE ${value}%`,
463
- notStartingWith: (value) => `NOT LIKE ${value}%`,
464
- endingWith: (value) => `LIKE %${value}`,
465
- notEndingWith: (value) => `NOT LIKE %${value}`,
466
- containing: (value) => `LIKE %${value}%`,
467
- notContaining: (value) => `NOT LIKE %${value}%`,
468
- greaterThan: (value) => `> ${value}`,
469
- greaterOrEqual: (value) => `>= ${value}`,
470
- lessThan: (value) => `< ${value}`,
471
- lessOrEqual: (value) => `<= ${value}`
472
- };
473
- var handleWith = (schemas, schema, statementValues, instruction, rootTable) => {
474
- const subStatement = composeConditions(
475
- schemas,
476
- schema,
477
- statementValues,
478
- "with",
479
- instruction,
480
- { rootTable }
481
- );
482
- return `(${subStatement})`;
483
- };
484
-
485
- // src/utils/statement.ts
486
- var prepareStatementValue = (statementValues, value, bindNull = false) => {
487
- if (!bindNull && value === null) return "NULL";
488
- let formattedValue = value;
489
- if (Array.isArray(value) || isObject(value)) {
490
- formattedValue = JSON.stringify(value);
491
- } else if (typeof value === "boolean") {
492
- formattedValue = value ? 1 : 0;
493
- }
494
- const index = statementValues.push(formattedValue);
495
- return `?${index}`;
496
- };
497
- var composeFieldValues = (schemas, schema, statementValues, instructionName, value, options) => {
498
- const { field: schemaField, fieldSelector: selector } = getFieldFromSchema(
499
- schema,
500
- options.fieldSlug,
501
- instructionName,
502
- options.rootTable
503
- );
504
- const isSubQuery = isObject(value) && Object.hasOwn(value, RONIN_SCHEMA_SYMBOLS.QUERY);
505
- const collectStatementValue = options.type !== "fields";
506
- let conditionSelector = selector;
507
- let conditionValue = value;
508
- if (isSubQuery && collectStatementValue) {
509
- conditionValue = `(${compileQueryInput(
510
- value[RONIN_SCHEMA_SYMBOLS.QUERY],
511
- schemas,
512
- { statementValues }
513
- ).readStatement})`;
514
- } else if (typeof value === "string" && value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD)) {
515
- conditionSelector = `"${options.customTable}"."${schemaField.slug}"`;
516
- conditionValue = `"${options.rootTable}"."${value.replace(RONIN_SCHEMA_SYMBOLS.FIELD, "")}"`;
517
- } else if (schemaField.type === "json" && instructionName === "to") {
518
- conditionSelector = `"${schemaField.slug}"`;
519
- if (collectStatementValue) {
520
- const preparedValue = prepareStatementValue(statementValues, value, false);
521
- conditionValue = `IIF(${conditionSelector} IS NULL, ${preparedValue}, json_patch(${conditionSelector}, ${preparedValue}))`;
522
- }
523
- } else if (collectStatementValue) {
524
- conditionValue = prepareStatementValue(statementValues, value, false);
525
- }
526
- if (options.type === "fields") return conditionSelector;
527
- if (options.type === "values") return conditionValue;
528
- return `${conditionSelector} ${WITH_CONDITIONS[options.condition || "being"](conditionValue, value)}`;
529
- };
530
- var composeConditions = (schemas, schema, statementValues, instructionName, value, options) => {
531
- const isNested = isObject(value) && Object.keys(value).length > 0;
532
- if (isNested && Object.keys(value).every((key) => key in WITH_CONDITIONS)) {
533
- const conditions = Object.entries(value).map(
534
- ([conditionType, checkValue]) => composeConditions(schemas, schema, statementValues, instructionName, checkValue, {
535
- ...options,
536
- condition: conditionType
537
- })
538
- );
539
- return conditions.join(" AND ");
540
- }
541
- if (options.fieldSlug) {
542
- const fieldDetails = getFieldFromSchema(
543
- schema,
544
- options.fieldSlug,
545
- instructionName,
546
- options.rootTable
547
- );
548
- const { field: schemaField } = fieldDetails;
549
- const consumeJSON = schemaField.type === "json" && instructionName === "to";
550
- const isSubQuery = isNested && Object.hasOwn(value, RONIN_SCHEMA_SYMBOLS.QUERY);
551
- if (!(isObject(value) || Array.isArray(value)) || isSubQuery || consumeJSON) {
552
- return composeFieldValues(
553
- schemas,
554
- schema,
555
- statementValues,
556
- instructionName,
557
- value,
558
- { ...options, fieldSlug: options.fieldSlug }
559
- );
560
- }
561
- if (schemaField.type === "reference" && isNested) {
562
- const keys = Object.keys(value);
563
- const values = Object.values(value);
564
- let recordTarget;
565
- if (keys.length === 1 && keys[0] === "id") {
566
- recordTarget = values[0];
567
- } else {
568
- const relatedSchema = getSchemaBySlug(schemas, schemaField.target.slug);
569
- const subQuery = {
570
- get: {
571
- [relatedSchema.slug]: {
572
- with: value,
573
- selecting: ["id"]
574
- }
575
- }
576
- };
577
- recordTarget = {
578
- [RONIN_SCHEMA_SYMBOLS.QUERY]: subQuery
579
- };
580
- }
581
- return composeConditions(
582
- schemas,
583
- schema,
584
- statementValues,
585
- instructionName,
586
- recordTarget,
587
- options
588
- );
589
- }
590
- }
591
- if (isNested) {
592
- const conditions = Object.entries(value).map(([field, value2]) => {
593
- const nestedFieldSlug = options.fieldSlug ? `${options.fieldSlug}.${field}` : field;
594
- return composeConditions(schemas, schema, statementValues, instructionName, value2, {
595
- ...options,
596
- fieldSlug: nestedFieldSlug
597
- });
598
- });
599
- const joiner = instructionName === "to" ? ", " : " AND ";
600
- if (instructionName === "to") return `${conditions.join(joiner)}`;
601
- return conditions.length === 1 ? conditions[0] : options.fieldSlug ? `(${conditions.join(joiner)})` : conditions.join(joiner);
602
- }
603
- if (Array.isArray(value)) {
604
- const conditions = value.map(
605
- (filter) => composeConditions(
606
- schemas,
607
- schema,
608
- statementValues,
609
- instructionName,
610
- filter,
611
- options
612
- )
613
- );
614
- return conditions.join(" OR ");
615
- }
616
- throw new RoninError({
617
- message: `The \`with\` instruction must not contain an empty field. The following fields are empty: \`${options.fieldSlug}\`. If you meant to query by an empty field, try using \`null\` instead.`,
618
- code: "INVALID_WITH_VALUE",
619
- queries: null
620
- });
621
- };
622
- var formatIdentifiers = ({ identifiers }, queryInstructions) => {
623
- if (!queryInstructions) return queryInstructions;
624
- const type = "with" in queryInstructions ? "with" : null;
625
- if (!type) return queryInstructions;
626
- const nestedInstructions = queryInstructions[type];
627
- if (!nestedInstructions || Array.isArray(nestedInstructions))
628
- return queryInstructions;
629
- const newNestedInstructions = { ...nestedInstructions };
630
- for (const oldKey of Object.keys(newNestedInstructions)) {
631
- if (oldKey !== "titleIdentifier" && oldKey !== "slugIdentifier") continue;
632
- const identifierName = oldKey === "titleIdentifier" ? "title" : "slug";
633
- const value = newNestedInstructions[oldKey];
634
- const newKey = identifiers?.[identifierName] || "id";
635
- newNestedInstructions[newKey] = value;
636
- delete newNestedInstructions[oldKey];
637
- }
638
- return {
639
- ...queryInstructions,
640
- [type]: newNestedInstructions
641
- };
642
- };
643
-
644
736
  // src/instructions/before-after.ts
645
737
  var CURSOR_SEPARATOR = ",";
646
738
  var CURSOR_NULL_PLACEHOLDER = "RONIN_NULL";
@@ -734,7 +826,7 @@ var handleFor = (schemas, schema, statementValues, instruction, rootTable) => {
734
826
  });
735
827
  }
736
828
  const replacedForFilter = structuredClone(forFilter);
737
- replaceInObject(
829
+ findInObject(
738
830
  replacedForFilter,
739
831
  RONIN_SCHEMA_SYMBOLS.VALUE,
740
832
  (match) => match.replace(RONIN_SCHEMA_SYMBOLS.VALUE, args)
@@ -999,7 +1091,7 @@ var compileQueryInput = (query, defaultSchemas, options) => {
999
1091
  let table = getTableForSchema(schema);
1000
1092
  const statementValues = options?.statementValues || [];
1001
1093
  const writeStatements = [];
1002
- addSchemaQueries(parsedQuery, writeStatements);
1094
+ addSchemaQueries(schemas, statementValues, parsedQuery, writeStatements);
1003
1095
  const columns = handleSelecting(schema, statementValues, {
1004
1096
  selecting: instructions?.selecting,
1005
1097
  including: instructions?.including
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {