@ronin/compiler 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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": {