@ronin/compiler 0.4.0 → 0.5.1

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.
package/dist/index.js CHANGED
@@ -96,19 +96,19 @@ var splitQuery = (query) => {
96
96
  };
97
97
 
98
98
  // src/utils/statement.ts
99
- var prepareStatementValue = (statementValues, value) => {
99
+ var prepareStatementValue = (statementParams, value) => {
100
100
  if (value === null) return "NULL";
101
- if (!statementValues) return JSON.stringify(value);
101
+ if (!statementParams) return JSON.stringify(value);
102
102
  let formattedValue = value;
103
103
  if (Array.isArray(value) || isObject(value)) {
104
104
  formattedValue = JSON.stringify(value);
105
105
  } else if (typeof value === "boolean") {
106
106
  formattedValue = value ? 1 : 0;
107
107
  }
108
- const index = statementValues.push(formattedValue);
108
+ const index = statementParams.push(formattedValue);
109
109
  return `?${index}`;
110
110
  };
111
- var composeFieldValues = (schemas, schema, statementValues, instructionName, value, options) => {
111
+ var composeFieldValues = (schemas, schema, statementParams, instructionName, value, options) => {
112
112
  const { field: schemaField, fieldSelector: selector } = getFieldFromSchema(
113
113
  schema,
114
114
  options.fieldSlug,
@@ -123,8 +123,8 @@ var composeFieldValues = (schemas, schema, statementValues, instructionName, val
123
123
  conditionValue = `(${compileQueryInput(
124
124
  value[RONIN_SCHEMA_SYMBOLS.QUERY],
125
125
  schemas,
126
- statementValues
127
- ).readStatement})`;
126
+ statementParams
127
+ ).main.statement})`;
128
128
  } else if (typeof value === "string" && value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD)) {
129
129
  let targetTable = `"${options.rootTable}"`;
130
130
  let toReplace = RONIN_SCHEMA_SYMBOLS.FIELD;
@@ -140,21 +140,21 @@ var composeFieldValues = (schemas, schema, statementValues, instructionName, val
140
140
  } else if (schemaField.type === "json" && instructionName === "to") {
141
141
  conditionSelector = `"${schemaField.slug}"`;
142
142
  if (collectStatementValue) {
143
- const preparedValue = prepareStatementValue(statementValues, value);
143
+ const preparedValue = prepareStatementValue(statementParams, value);
144
144
  conditionValue = `IIF(${conditionSelector} IS NULL, ${preparedValue}, json_patch(${conditionSelector}, ${preparedValue}))`;
145
145
  }
146
146
  } else if (collectStatementValue) {
147
- conditionValue = prepareStatementValue(statementValues, value);
147
+ conditionValue = prepareStatementValue(statementParams, value);
148
148
  }
149
149
  if (options.type === "fields") return conditionSelector;
150
150
  if (options.type === "values") return conditionValue;
151
151
  return `${conditionSelector} ${WITH_CONDITIONS[options.condition || "being"](conditionValue, value)}`;
152
152
  };
153
- var composeConditions = (schemas, schema, statementValues, instructionName, value, options) => {
153
+ var composeConditions = (schemas, schema, statementParams, instructionName, value, options) => {
154
154
  const isNested = isObject(value) && Object.keys(value).length > 0;
155
155
  if (isNested && Object.keys(value).every((key) => key in WITH_CONDITIONS)) {
156
156
  const conditions = Object.entries(value).map(
157
- ([conditionType, checkValue]) => composeConditions(schemas, schema, statementValues, instructionName, checkValue, {
157
+ ([conditionType, checkValue]) => composeConditions(schemas, schema, statementParams, instructionName, checkValue, {
158
158
  ...options,
159
159
  condition: conditionType
160
160
  })
@@ -175,7 +175,7 @@ var composeConditions = (schemas, schema, statementValues, instructionName, valu
175
175
  return composeFieldValues(
176
176
  schemas,
177
177
  schema,
178
- statementValues,
178
+ statementParams,
179
179
  instructionName,
180
180
  value,
181
181
  { ...options, fieldSlug: options.fieldSlug }
@@ -204,7 +204,7 @@ var composeConditions = (schemas, schema, statementValues, instructionName, valu
204
204
  return composeConditions(
205
205
  schemas,
206
206
  schema,
207
- statementValues,
207
+ statementParams,
208
208
  instructionName,
209
209
  recordTarget,
210
210
  options
@@ -214,7 +214,7 @@ var composeConditions = (schemas, schema, statementValues, instructionName, valu
214
214
  if (isNested) {
215
215
  const conditions = Object.entries(value).map(([field, value2]) => {
216
216
  const nestedFieldSlug = options.fieldSlug ? `${options.fieldSlug}.${field}` : field;
217
- return composeConditions(schemas, schema, statementValues, instructionName, value2, {
217
+ return composeConditions(schemas, schema, statementParams, instructionName, value2, {
218
218
  ...options,
219
219
  fieldSlug: nestedFieldSlug
220
220
  });
@@ -228,7 +228,7 @@ var composeConditions = (schemas, schema, statementValues, instructionName, valu
228
228
  (filter) => composeConditions(
229
229
  schemas,
230
230
  schema,
231
- statementValues,
231
+ statementParams,
232
232
  instructionName,
233
233
  filter,
234
234
  options
@@ -287,11 +287,11 @@ var WITH_CONDITIONS = {
287
287
  lessThan: (value) => `< ${value}`,
288
288
  lessOrEqual: (value) => `<= ${value}`
289
289
  };
290
- var handleWith = (schemas, schema, statementValues, instruction, rootTable) => {
290
+ var handleWith = (schemas, schema, statementParams, instruction, rootTable) => {
291
291
  const subStatement = composeConditions(
292
292
  schemas,
293
293
  schema,
294
- statementValues,
294
+ statementParams,
295
295
  "with",
296
296
  instruction,
297
297
  { rootTable }
@@ -317,7 +317,7 @@ var getTableForSchema = (schema) => {
317
317
  return convertToSnakeCase(schema.pluralSlug);
318
318
  };
319
319
  var composeMetaSchemaSlug = (suffix) => convertToCamelCase(`ronin_${suffix}`);
320
- var composeAssociationSchemaSlug = (schema, field) => composeMetaSchemaSlug(`${schema.pluralSlug}_${field.slug}`);
320
+ var composeAssociationSchemaSlug = (schema, field) => composeMetaSchemaSlug(`${schema.slug}_${field.slug}`);
321
321
  var getFieldSelector = (field, fieldPath, rootTable) => {
322
322
  const symbol = rootTable?.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD) ? `${rootTable.replace(RONIN_SCHEMA_SYMBOLS.FIELD, "").slice(0, -1)}.` : "";
323
323
  const tablePrefix = symbol || (rootTable ? `"${rootTable}".` : "");
@@ -352,6 +352,53 @@ var getFieldFromSchema = (schema, fieldPath, instructionName, rootTable) => {
352
352
  const fieldSelector = getFieldSelector(schemaField, fieldPath, rootTable);
353
353
  return { field: schemaField, fieldSelector };
354
354
  };
355
+ var slugToName = (slug) => {
356
+ const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
357
+ return title(name);
358
+ };
359
+ var VOWELS = ["a", "e", "i", "o", "u"];
360
+ var pluralize = (word) => {
361
+ const lastLetter = word.slice(-1).toLowerCase();
362
+ const secondLastLetter = word.slice(-2, -1).toLowerCase();
363
+ if (lastLetter === "y" && !VOWELS.includes(secondLastLetter)) {
364
+ return `${word.slice(0, -1)}ies`;
365
+ }
366
+ if (lastLetter === "s" || word.slice(-2).toLowerCase() === "ch" || word.slice(-2).toLowerCase() === "sh" || word.slice(-2).toLowerCase() === "ex") {
367
+ return `${word}es`;
368
+ }
369
+ return `${word}s`;
370
+ };
371
+ var schemaSettings = [
372
+ ["pluralSlug", "slug", pluralize],
373
+ ["name", "slug", slugToName],
374
+ ["pluralName", "pluralSlug", slugToName],
375
+ ["idPrefix", "slug", (slug) => slug.slice(0, 3)]
376
+ ];
377
+ var addDefaultSchemaFields = (schema, isNew) => {
378
+ const copiedSchema = { ...schema };
379
+ for (const [setting, base, generator] of schemaSettings) {
380
+ if (copiedSchema[setting] || !copiedSchema[base]) continue;
381
+ copiedSchema[setting] = generator(copiedSchema[base]);
382
+ }
383
+ const newFields = copiedSchema.fields || [];
384
+ if (isNew || newFields.length > 0) {
385
+ if (!copiedSchema.identifiers) copiedSchema.identifiers = {};
386
+ if (!copiedSchema.identifiers.name) {
387
+ const suitableField = newFields.find(
388
+ (field) => field.type === "string" && field.required === true && ["name"].includes(field.slug)
389
+ );
390
+ copiedSchema.identifiers.name = suitableField?.slug || "id";
391
+ }
392
+ if (!copiedSchema.identifiers.slug) {
393
+ const suitableField = newFields.find(
394
+ (field) => field.type === "string" && field.unique === true && field.required === true && ["slug", "handle"].includes(field.slug)
395
+ );
396
+ copiedSchema.identifiers.slug = suitableField?.slug || "id";
397
+ }
398
+ copiedSchema.fields = [...SYSTEM_FIELDS, ...newFields];
399
+ }
400
+ return copiedSchema;
401
+ };
355
402
  var SYSTEM_FIELDS = [
356
403
  {
357
404
  name: "ID",
@@ -392,16 +439,12 @@ var SYSTEM_FIELDS = [
392
439
  ];
393
440
  var SYSTEM_SCHEMAS = [
394
441
  {
395
- name: "Schema",
396
- pluralName: "Schemas",
397
442
  slug: "schema",
398
- pluralSlug: "schemas",
399
443
  identifiers: {
400
444
  name: "name",
401
445
  slug: "slug"
402
446
  },
403
447
  fields: [
404
- ...SYSTEM_FIELDS,
405
448
  { slug: "name", type: "string" },
406
449
  { slug: "pluralName", type: "string" },
407
450
  { slug: "slug", type: "string" },
@@ -412,20 +455,18 @@ var SYSTEM_SCHEMAS = [
412
455
  { slug: "identifiers.slug", type: "string" },
413
456
  { slug: "fields", type: "json" },
414
457
  { slug: "indexes", type: "json" },
415
- { slug: "triggers", type: "json" }
458
+ { slug: "triggers", type: "json" },
459
+ { slug: "including", type: "json" },
460
+ { slug: "for", type: "json" }
416
461
  ]
417
462
  },
418
463
  {
419
- name: "Field",
420
- pluralName: "Fields",
421
464
  slug: "field",
422
- pluralSlug: "fields",
423
465
  identifiers: {
424
466
  name: "name",
425
467
  slug: "slug"
426
468
  },
427
469
  fields: [
428
- ...SYSTEM_FIELDS,
429
470
  { slug: "name", type: "string" },
430
471
  { slug: "slug", type: "string", required: true },
431
472
  { slug: "type", type: "string", required: true },
@@ -448,16 +489,12 @@ var SYSTEM_SCHEMAS = [
448
489
  ]
449
490
  },
450
491
  {
451
- name: "Index",
452
- pluralName: "Indexes",
453
492
  slug: "index",
454
- pluralSlug: "indexes",
455
493
  identifiers: {
456
494
  name: "slug",
457
495
  slug: "slug"
458
496
  },
459
497
  fields: [
460
- ...SYSTEM_FIELDS,
461
498
  { slug: "slug", type: "string", required: true },
462
499
  {
463
500
  slug: "schema",
@@ -470,16 +507,12 @@ var SYSTEM_SCHEMAS = [
470
507
  ]
471
508
  },
472
509
  {
473
- name: "Trigger",
474
- pluralName: "Triggers",
475
510
  slug: "trigger",
476
- pluralSlug: "triggers",
477
511
  identifiers: {
478
512
  name: "slug",
479
513
  slug: "slug"
480
514
  },
481
515
  fields: [
482
- ...SYSTEM_FIELDS,
483
516
  { slug: "slug", type: "string", required: true },
484
517
  { slug: "schema", type: "reference", target: { slug: "schema" }, required: true },
485
518
  { slug: "cause", type: "string", required: true },
@@ -487,85 +520,89 @@ var SYSTEM_SCHEMAS = [
487
520
  { slug: "effects", type: "json", required: true }
488
521
  ]
489
522
  }
490
- ];
523
+ ].map((schema) => addDefaultSchemaFields(schema, true));
491
524
  var SYSTEM_SCHEMA_SLUGS = SYSTEM_SCHEMAS.flatMap(({ slug, pluralSlug }) => [
492
525
  slug,
493
526
  pluralSlug
494
527
  ]);
495
- var prepareSchema = (schema) => {
496
- const copiedSchema = { ...schema };
497
- if (!copiedSchema.pluralSlug) copiedSchema.pluralSlug = pluralize(copiedSchema.slug);
498
- if (!copiedSchema.name) copiedSchema.name = slugToName(copiedSchema.slug);
499
- if (!copiedSchema.pluralName)
500
- copiedSchema.pluralName = slugToName(copiedSchema.pluralSlug);
501
- if (!copiedSchema.idPrefix) copiedSchema.idPrefix = copiedSchema.slug.slice(0, 3);
502
- if (!copiedSchema.identifiers) copiedSchema.identifiers = {};
503
- if (!copiedSchema.identifiers.name) copiedSchema.identifiers.name = "id";
504
- if (!copiedSchema.identifiers.slug) copiedSchema.identifiers.slug = "id";
505
- return copiedSchema;
506
- };
507
528
  var addSystemSchemas = (schemas) => {
508
- const list = [...SYSTEM_SCHEMAS, ...schemas].map(prepareSchema);
509
- for (const schema of list) {
510
- const defaultIncluding = {};
529
+ const associativeSchemas = schemas.flatMap((schema) => {
530
+ const addedSchemas = [];
511
531
  for (const field of schema.fields || []) {
512
532
  if (field.type === "reference" && !field.slug.startsWith("ronin.")) {
513
- const relatedSchema = getSchemaBySlug(list, field.target.slug);
533
+ const relatedSchema = getSchemaBySlug(schemas, field.target.slug);
514
534
  let fieldSlug = relatedSchema.slug;
515
535
  if (field.kind === "many") {
516
536
  fieldSlug = composeAssociationSchemaSlug(schema, field);
517
- list.push({
537
+ addedSchemas.push({
518
538
  pluralSlug: fieldSlug,
519
539
  slug: fieldSlug,
520
- identifiers: {
521
- name: "id",
522
- slug: "id"
523
- },
524
540
  fields: [
525
541
  {
526
542
  slug: "source",
527
543
  type: "reference",
528
- target: schema
544
+ target: { slug: schema.slug }
529
545
  },
530
546
  {
531
547
  slug: "target",
532
548
  type: "reference",
533
- target: relatedSchema
549
+ target: { slug: relatedSchema.slug }
534
550
  }
535
551
  ]
536
552
  });
537
553
  }
538
- defaultIncluding[field.slug] = {
539
- get: {
540
- [fieldSlug]: {
541
- with: {
542
- // Compare the `id` field of the related schema to the reference field on
543
- // the root schema (`field.slug`).
544
- id: `${RONIN_SCHEMA_SYMBOLS.FIELD}${field.slug}`
545
- }
554
+ }
555
+ }
556
+ return addedSchemas;
557
+ });
558
+ return [...SYSTEM_SCHEMAS, ...associativeSchemas, ...schemas];
559
+ };
560
+ var addDefaultSchemaShortcuts = (list, schema) => {
561
+ const defaultIncluding = {};
562
+ for (const field of schema.fields || []) {
563
+ if (field.type === "reference" && !field.slug.startsWith("ronin.")) {
564
+ const relatedSchema = getSchemaBySlug(list, field.target.slug);
565
+ let fieldSlug = relatedSchema.slug;
566
+ if (field.kind === "many") {
567
+ fieldSlug = composeAssociationSchemaSlug(schema, field);
568
+ }
569
+ defaultIncluding[field.slug] = {
570
+ get: {
571
+ [fieldSlug]: {
572
+ with: {
573
+ // Compare the `id` field of the related schema to the reference field on
574
+ // the root schema (`field.slug`).
575
+ id: `${RONIN_SCHEMA_SYMBOLS.FIELD}${field.slug}`
546
576
  }
547
577
  }
548
- };
549
- const relatedSchemaToModify = getSchemaBySlug(list, field.target.slug);
550
- if (!relatedSchemaToModify) throw new Error("Missing related schema");
551
- relatedSchemaToModify.including = {
552
- [schema.pluralSlug]: {
553
- get: {
554
- [schema.pluralSlug]: {
555
- with: {
556
- [field.slug]: `${RONIN_SCHEMA_SYMBOLS.FIELD}id`
557
- }
558
- }
559
- }
560
- },
561
- ...relatedSchemaToModify.including
562
- };
563
- }
578
+ }
579
+ };
564
580
  }
565
- schema.fields = [...SYSTEM_FIELDS, ...schema.fields || []];
581
+ }
582
+ const childSchemas = list.map((subSchema) => {
583
+ const field = subSchema.fields?.find((field2) => {
584
+ return field2.type === "reference" && field2.target.slug === schema.slug;
585
+ });
586
+ if (!field) return null;
587
+ return { schema: subSchema, field };
588
+ }).filter((match) => match !== null);
589
+ for (const childMatch of childSchemas) {
590
+ const { schema: childSchema, field: childField } = childMatch;
591
+ const pluralSlug = childSchema.pluralSlug;
592
+ defaultIncluding[pluralSlug] = {
593
+ get: {
594
+ [pluralSlug]: {
595
+ with: {
596
+ [childField.slug]: `${RONIN_SCHEMA_SYMBOLS.FIELD}id`
597
+ }
598
+ }
599
+ }
600
+ };
601
+ }
602
+ if (Object.keys(defaultIncluding).length > 0) {
566
603
  schema.including = { ...defaultIncluding, ...schema.including };
567
604
  }
568
- return list;
605
+ return schema;
569
606
  };
570
607
  var mappedInstructions = {
571
608
  create: "to",
@@ -601,7 +638,7 @@ var getFieldStatement = (field) => {
601
638
  }
602
639
  return statement;
603
640
  };
604
- var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements) => {
641
+ var addSchemaQueries = (schemas, queryDetails, dependencyStatements) => {
605
642
  const {
606
643
  queryType,
607
644
  querySchema,
@@ -653,30 +690,33 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
653
690
  fields: ["schema.slug"]
654
691
  });
655
692
  }
656
- const tableName = convertToSnakeCase(pluralize(kind === "schemas" ? slug : schemaSlug));
693
+ const usableSlug = kind === "schemas" ? slug : schemaSlug;
694
+ const tableName = convertToSnakeCase(pluralize(usableSlug));
695
+ const targetSchema = kind === "schemas" && queryType === "create" ? null : getSchemaBySlug(schemas, usableSlug);
657
696
  if (kind === "indexes") {
658
697
  const indexName = convertToSnakeCase(slug);
659
698
  const unique = instructionList?.unique;
660
699
  const filterQuery = instructionList?.filter;
700
+ const params = [];
661
701
  let statement2 = `${tableAction}${unique ? " UNIQUE" : ""} INDEX "${indexName}"`;
662
702
  if (queryType === "create") {
663
703
  statement2 += ` ON "${tableName}"`;
664
704
  if (filterQuery) {
665
- const targetSchema = getSchemaBySlug(schemas, schemaSlug);
666
705
  const withStatement = handleWith(
667
706
  schemas,
668
707
  targetSchema,
669
- statementValues,
708
+ params,
670
709
  filterQuery
671
710
  );
672
711
  statement2 += ` WHERE (${withStatement})`;
673
712
  }
674
713
  }
675
- writeStatements.push(statement2);
714
+ dependencyStatements.push({ statement: statement2, params });
676
715
  return queryInstructions;
677
716
  }
678
717
  if (kind === "triggers") {
679
718
  const triggerName = convertToSnakeCase(slug);
719
+ const params = [];
680
720
  let statement2 = `${tableAction} TRIGGER "${triggerName}"`;
681
721
  if (queryType === "create") {
682
722
  const cause = slugToName(instructionList?.cause).toUpperCase();
@@ -687,48 +727,61 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
687
727
  statementParts.push("FOR EACH ROW");
688
728
  }
689
729
  if (filterQuery) {
690
- const targetSchema = getSchemaBySlug(schemas, schemaSlug);
691
730
  const tablePlaceholder = cause.endsWith("DELETE") ? RONIN_SCHEMA_SYMBOLS.FIELD_OLD : RONIN_SCHEMA_SYMBOLS.FIELD_NEW;
692
731
  const withStatement = handleWith(
693
732
  schemas,
694
733
  targetSchema,
695
- statementValues,
734
+ params,
696
735
  filterQuery,
697
736
  tablePlaceholder
698
737
  );
699
738
  statementParts.push("WHEN", `(${withStatement})`);
700
739
  }
701
740
  const effectStatements = effectQueries.map((effectQuery) => {
702
- return compileQueryInput(effectQuery, schemas, statementValues, {
703
- disableReturning: true
704
- }).readStatement;
741
+ return compileQueryInput(effectQuery, schemas, params, {
742
+ returning: false
743
+ }).main.statement;
705
744
  });
706
745
  if (effectStatements.length > 1) statementParts.push("BEGIN");
707
746
  statementParts.push(effectStatements.join("; "));
708
747
  if (effectStatements.length > 1) statementParts.push("END");
709
748
  statement2 += ` ${statementParts.join(" ")}`;
710
749
  }
711
- writeStatements.push(statement2);
750
+ dependencyStatements.push({ statement: statement2, params });
712
751
  return queryInstructions;
713
752
  }
714
- let statement = `${tableAction} TABLE "${tableName}"`;
753
+ const statement = `${tableAction} TABLE "${tableName}"`;
715
754
  if (kind === "schemas") {
716
- const providedFields = instructionList?.fields || [];
717
- const fields = [...SYSTEM_FIELDS, ...providedFields];
718
755
  if (queryType === "create" || queryType === "set") {
719
- queryInstructions.to = prepareSchema(queryInstructions.to);
756
+ const schemaWithFields = addDefaultSchemaFields(
757
+ queryInstructions.to,
758
+ queryType === "create"
759
+ );
760
+ const schemaWithShortcuts = addDefaultSchemaShortcuts(schemas, schemaWithFields);
761
+ queryInstructions.to = schemaWithShortcuts;
720
762
  }
721
763
  if (queryType === "create") {
764
+ const { fields } = queryInstructions.to;
722
765
  const columns = fields.map(getFieldStatement).filter(Boolean);
723
- statement += ` (${columns.join(", ")})`;
766
+ dependencyStatements.push({
767
+ statement: `${statement} (${columns.join(", ")})`,
768
+ params: []
769
+ });
770
+ schemas.push(queryInstructions.to);
724
771
  } else if (queryType === "set") {
725
772
  const newSlug = queryInstructions.to?.pluralSlug;
726
773
  if (newSlug) {
727
774
  const newTable = convertToSnakeCase(newSlug);
728
- statement += ` RENAME TO "${newTable}"`;
775
+ dependencyStatements.push({
776
+ statement: `${statement} RENAME TO "${newTable}"`,
777
+ params: []
778
+ });
729
779
  }
780
+ Object.assign(targetSchema, queryInstructions.to);
781
+ } else if (queryType === "drop") {
782
+ schemas.splice(schemas.indexOf(targetSchema), 1);
783
+ dependencyStatements.push({ statement, params: [] });
730
784
  }
731
- writeStatements.push(statement);
732
785
  return queryInstructions;
733
786
  }
734
787
  if (kind === "fields") {
@@ -740,52 +793,51 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
740
793
  fields: ["type"]
741
794
  });
742
795
  }
743
- statement += ` ADD COLUMN ${getFieldStatement(instructionList)}`;
796
+ dependencyStatements.push({
797
+ statement: `${statement} ADD COLUMN ${getFieldStatement(instructionList)}`,
798
+ params: []
799
+ });
744
800
  } else if (queryType === "set") {
745
801
  const newSlug = queryInstructions.to?.slug;
746
802
  if (newSlug) {
747
- statement += ` RENAME COLUMN "${slug}" TO "${newSlug}"`;
803
+ dependencyStatements.push({
804
+ statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`,
805
+ params: []
806
+ });
748
807
  }
749
808
  } else if (queryType === "drop") {
750
- statement += ` DROP COLUMN "${slug}"`;
809
+ dependencyStatements.push({
810
+ statement: `${statement} DROP COLUMN "${slug}"`,
811
+ params: []
812
+ });
751
813
  }
752
- writeStatements.push(statement);
753
814
  }
754
815
  return queryInstructions;
755
816
  };
756
- var slugToName = (slug) => {
757
- const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
758
- return title(name);
759
- };
760
- var VOWELS = ["a", "e", "i", "o", "u"];
761
- var pluralize = (word) => {
762
- const lastLetter = word.slice(-1).toLowerCase();
763
- const secondLastLetter = word.slice(-2, -1).toLowerCase();
764
- if (lastLetter === "y" && !VOWELS.includes(secondLastLetter)) {
765
- return `${word.slice(0, -1)}ies`;
766
- }
767
- if (lastLetter === "s" || word.slice(-2).toLowerCase() === "ch" || word.slice(-2).toLowerCase() === "sh" || word.slice(-2).toLowerCase() === "ex") {
768
- return `${word}es`;
769
- }
770
- return `${word}s`;
771
- };
772
817
 
773
818
  // src/instructions/before-after.ts
774
819
  var CURSOR_SEPARATOR = ",";
775
820
  var CURSOR_NULL_PLACEHOLDER = "RONIN_NULL";
776
- var handleBeforeOrAfter = (schema, statementValues, instructions, rootTable) => {
821
+ var handleBeforeOrAfter = (schema, statementParams, instructions, rootTable) => {
777
822
  if (!(instructions.before || instructions.after)) {
778
823
  throw new RoninError({
779
824
  message: "The `before` or `after` instruction must not be empty.",
780
- code: "MISSING_INSTRUCTION",
781
- queries: null
825
+ code: "MISSING_INSTRUCTION"
782
826
  });
783
827
  }
784
828
  if (instructions.before && instructions.after) {
785
829
  throw new RoninError({
786
830
  message: "The `before` and `after` instructions cannot co-exist. Choose one.",
787
- code: "MUTUALLY_EXCLUSIVE_INSTRUCTIONS",
788
- queries: null
831
+ code: "MUTUALLY_EXCLUSIVE_INSTRUCTIONS"
832
+ });
833
+ }
834
+ if (!instructions.limitedTo) {
835
+ let message = "When providing a pagination cursor in the `before` or `after`";
836
+ message += " instruction, a `limitedTo` instruction must be provided as well, to";
837
+ message += " define the page size.";
838
+ throw new RoninError({
839
+ message,
840
+ code: "MISSING_INSTRUCTION"
789
841
  });
790
842
  }
791
843
  const { ascending = [], descending = [] } = instructions.orderedBy || {};
@@ -799,15 +851,15 @@ var handleBeforeOrAfter = (schema, statementValues, instructions, rootTable) =>
799
851
  }
800
852
  const { field } = getFieldFromSchema(schema, key, "orderedBy");
801
853
  if (field.type === "boolean") {
802
- return prepareStatementValue(statementValues, value === "true");
854
+ return prepareStatementValue(statementParams, value === "true");
803
855
  }
804
856
  if (field.type === "number") {
805
- return prepareStatementValue(statementValues, Number.parseInt(value));
857
+ return prepareStatementValue(statementParams, Number.parseInt(value));
806
858
  }
807
859
  if (field.type === "date") {
808
860
  return `'${new Date(Number.parseInt(value)).toJSON()}'`;
809
861
  }
810
- return prepareStatementValue(statementValues, value);
862
+ return prepareStatementValue(statementParams, value);
811
863
  });
812
864
  const compareOperators = [
813
865
  // Reverse the comparison operators if we're querying for records before.
@@ -850,7 +902,7 @@ var handleBeforeOrAfter = (schema, statementValues, instructions, rootTable) =>
850
902
  };
851
903
 
852
904
  // src/instructions/for.ts
853
- var handleFor = (schemas, schema, statementValues, instruction, rootTable) => {
905
+ var handleFor = (schemas, schema, statementParams, instruction, rootTable) => {
854
906
  let statement = "";
855
907
  if (!instruction) return statement;
856
908
  for (const shortcut in instruction) {
@@ -871,7 +923,7 @@ var handleFor = (schemas, schema, statementValues, instruction, rootTable) => {
871
923
  const subStatement = composeConditions(
872
924
  schemas,
873
925
  schema,
874
- statementValues,
926
+ statementParams,
875
927
  "for",
876
928
  replacedForFilter,
877
929
  { rootTable }
@@ -882,7 +934,7 @@ var handleFor = (schemas, schema, statementValues, instruction, rootTable) => {
882
934
  };
883
935
 
884
936
  // src/instructions/including.ts
885
- var handleIncluding = (schemas, statementValues, schema, instruction, rootTable) => {
937
+ var handleIncluding = (schemas, statementParams, schema, instruction, rootTable) => {
886
938
  let statement = "";
887
939
  let rootTableSubQuery;
888
940
  let rootTableName = rootTable;
@@ -916,9 +968,9 @@ var handleIncluding = (schemas, statementValues, schema, instruction, rootTable)
916
968
  }
917
969
  },
918
970
  schemas,
919
- statementValues
971
+ statementParams
920
972
  );
921
- relatedTableSelector = `(${subSelect.readStatement})`;
973
+ relatedTableSelector = `(${subSelect.main.statement})`;
922
974
  }
923
975
  statement += `${joinType} JOIN ${relatedTableSelector} as ${tableAlias}`;
924
976
  if (joinType === "LEFT") {
@@ -929,7 +981,7 @@ var handleIncluding = (schemas, statementValues, schema, instruction, rootTable)
929
981
  const subStatement = composeConditions(
930
982
  schemas,
931
983
  relatedSchema,
932
- statementValues,
984
+ statementParams,
933
985
  "including",
934
986
  queryInstructions?.with,
935
987
  {
@@ -945,9 +997,10 @@ var handleIncluding = (schemas, statementValues, schema, instruction, rootTable)
945
997
 
946
998
  // src/instructions/limited-to.ts
947
999
  var handleLimitedTo = (single, instruction) => {
948
- const pageSize = instruction || 100;
949
- const finalPageSize = pageSize + 1;
950
- return `LIMIT ${single ? "1" : finalPageSize} `;
1000
+ let amount;
1001
+ if (instruction) amount = instruction + 1;
1002
+ if (single) amount = 1;
1003
+ return `LIMIT ${amount} `;
951
1004
  };
952
1005
 
953
1006
  // src/instructions/ordered-by.ts
@@ -983,7 +1036,7 @@ var handleOrderedBy = (schema, instruction, rootTable) => {
983
1036
  };
984
1037
 
985
1038
  // src/instructions/selecting.ts
986
- var handleSelecting = (schema, statementValues, instructions) => {
1039
+ var handleSelecting = (schema, statementParams, instructions) => {
987
1040
  let statement = instructions.selecting ? instructions.selecting.map((slug) => {
988
1041
  return getFieldFromSchema(schema, slug, "selecting").fieldSelector;
989
1042
  }).join(", ") : "*";
@@ -994,14 +1047,14 @@ var handleSelecting = (schema, statementValues, instructions) => {
994
1047
  ).filter(([_, value]) => {
995
1048
  return !(isObject(value) && Object.hasOwn(value, RONIN_SCHEMA_SYMBOLS.QUERY));
996
1049
  }).map(([key, value]) => {
997
- return `${prepareStatementValue(statementValues, value)} as "${key}"`;
1050
+ return `${prepareStatementValue(statementParams, value)} as "${key}"`;
998
1051
  }).join(", ");
999
1052
  }
1000
1053
  return statement;
1001
1054
  };
1002
1055
 
1003
1056
  // src/instructions/to.ts
1004
- var handleTo = (schemas, schema, statementValues, queryType, writeStatements, instructions, rootTable) => {
1057
+ var handleTo = (schemas, schema, statementParams, queryType, dependencyStatements, instructions, rootTable) => {
1005
1058
  const currentTime = (/* @__PURE__ */ new Date()).toISOString();
1006
1059
  const { with: withInstruction, to: toInstruction } = instructions;
1007
1060
  const defaultFields = {};
@@ -1043,7 +1096,7 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
1043
1096
  ...subQueryInstructions.including
1044
1097
  };
1045
1098
  }
1046
- return compileQueryInput(subQuery, schemas, statementValues).readStatement;
1099
+ return compileQueryInput(subQuery, schemas, statementParams).main.statement;
1047
1100
  }
1048
1101
  Object.assign(toInstruction, defaultFields);
1049
1102
  for (const fieldSlug in toInstruction) {
@@ -1059,29 +1112,28 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
1059
1112
  const source = queryType === "create" ? { id: toInstruction.id } : withInstruction;
1060
1113
  const recordDetails = { source };
1061
1114
  if (value) recordDetails.target = value;
1062
- const { readStatement } = compileQueryInput(
1115
+ return compileQueryInput(
1063
1116
  {
1064
1117
  [subQueryType]: {
1065
1118
  [associativeSchemaSlug]: subQueryType === "create" ? { to: recordDetails } : { with: recordDetails }
1066
1119
  }
1067
1120
  },
1068
1121
  schemas,
1069
- statementValues,
1070
- { disableReturning: true }
1071
- );
1072
- return readStatement;
1122
+ [],
1123
+ { returning: false }
1124
+ ).main;
1073
1125
  };
1074
1126
  if (Array.isArray(fieldValue)) {
1075
- writeStatements.push(composeStatement("drop"));
1127
+ dependencyStatements.push(composeStatement("drop"));
1076
1128
  for (const record of fieldValue) {
1077
- writeStatements.push(composeStatement("create", record));
1129
+ dependencyStatements.push(composeStatement("create", record));
1078
1130
  }
1079
1131
  } else if (isObject(fieldValue)) {
1080
1132
  for (const recordToAdd of fieldValue.containing || []) {
1081
- writeStatements.push(composeStatement("create", recordToAdd));
1133
+ dependencyStatements.push(composeStatement("create", recordToAdd));
1082
1134
  }
1083
1135
  for (const recordToRemove of fieldValue.notContaining || []) {
1084
- writeStatements.push(composeStatement("drop", recordToRemove));
1136
+ dependencyStatements.push(composeStatement("drop", recordToRemove));
1085
1137
  }
1086
1138
  }
1087
1139
  }
@@ -1089,7 +1141,7 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
1089
1141
  let statement = composeConditions(
1090
1142
  schemas,
1091
1143
  schema,
1092
- statementValues,
1144
+ statementParams,
1093
1145
  "to",
1094
1146
  toInstruction,
1095
1147
  {
@@ -1101,7 +1153,7 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
1101
1153
  const deepStatement = composeConditions(
1102
1154
  schemas,
1103
1155
  schema,
1104
- statementValues,
1156
+ statementParams,
1105
1157
  "to",
1106
1158
  toInstruction,
1107
1159
  {
@@ -1117,22 +1169,21 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
1117
1169
  };
1118
1170
 
1119
1171
  // src/utils/index.ts
1120
- var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1172
+ var compileQueryInput = (query, schemas, statementParams, options) => {
1121
1173
  const parsedQuery = splitQuery(query);
1122
1174
  const { queryType, querySchema, queryInstructions } = parsedQuery;
1123
- const schemas = addSystemSchemas(defaultSchemas);
1124
1175
  const schema = getSchemaBySlug(schemas, querySchema);
1125
1176
  const single = querySchema !== schema.pluralSlug;
1126
1177
  let instructions = formatIdentifiers(schema, queryInstructions);
1127
1178
  let table = getTableForSchema(schema);
1128
- const writeStatements = [];
1179
+ const dependencyStatements = [];
1180
+ const returning = options?.returning ?? true;
1129
1181
  instructions = addSchemaQueries(
1130
1182
  schemas,
1131
- statementValues,
1132
1183
  { queryType, querySchema, queryInstructions: instructions },
1133
- writeStatements
1184
+ dependencyStatements
1134
1185
  );
1135
- const columns = handleSelecting(schema, statementValues, {
1186
+ const columns = handleSelecting(schema, statementParams, {
1136
1187
  selecting: instructions?.selecting,
1137
1188
  including: instructions?.including
1138
1189
  });
@@ -1161,7 +1212,7 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1161
1212
  statement: including,
1162
1213
  rootTableSubQuery,
1163
1214
  rootTableName
1164
- } = handleIncluding(schemas, statementValues, schema, instructions?.including, table);
1215
+ } = handleIncluding(schemas, statementParams, schema, instructions?.including, table);
1165
1216
  if (rootTableSubQuery && rootTableName) {
1166
1217
  table = rootTableName;
1167
1218
  statement += `(${rootTableSubQuery}) as ${rootTableName} `;
@@ -1184,9 +1235,9 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1184
1235
  const toStatement = handleTo(
1185
1236
  schemas,
1186
1237
  schema,
1187
- statementValues,
1238
+ statementParams,
1188
1239
  queryType,
1189
- writeStatements,
1240
+ dependencyStatements,
1190
1241
  { with: instructions.with, to: instructions.to },
1191
1242
  isJoining ? table : void 0
1192
1243
  );
@@ -1197,7 +1248,7 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1197
1248
  const withStatement = handleWith(
1198
1249
  schemas,
1199
1250
  schema,
1200
- statementValues,
1251
+ statementParams,
1201
1252
  instructions?.with,
1202
1253
  isJoining ? table : void 0
1203
1254
  );
@@ -1207,13 +1258,13 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1207
1258
  const forStatement = handleFor(
1208
1259
  schemas,
1209
1260
  schema,
1210
- statementValues,
1261
+ statementParams,
1211
1262
  instructions?.for,
1212
1263
  isJoining ? table : void 0
1213
1264
  );
1214
1265
  if (forStatement.length > 0) conditions.push(forStatement);
1215
1266
  }
1216
- if ((queryType === "get" || queryType === "count") && !single) {
1267
+ if ((queryType === "get" || queryType === "count") && !single && instructions?.limitedTo) {
1217
1268
  instructions = instructions || {};
1218
1269
  instructions.orderedBy = instructions.orderedBy || {};
1219
1270
  instructions.orderedBy.ascending = instructions.orderedBy.ascending || [];
@@ -1235,12 +1286,13 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1235
1286
  }
1236
1287
  const beforeAndAfterStatement = handleBeforeOrAfter(
1237
1288
  schema,
1238
- statementValues,
1289
+ statementParams,
1239
1290
  {
1240
1291
  before: instructions.before,
1241
1292
  after: instructions.after,
1242
1293
  with: instructions.with,
1243
- orderedBy: instructions.orderedBy
1294
+ orderedBy: instructions.orderedBy,
1295
+ limitedTo: instructions.limitedTo
1244
1296
  },
1245
1297
  isJoining ? table : void 0
1246
1298
  );
@@ -1261,25 +1313,44 @@ var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
1261
1313
  );
1262
1314
  statement += `${orderedByStatement} `;
1263
1315
  }
1264
- if (queryType === "get" && !isJoiningMultipleRows) {
1316
+ if (queryType === "get" && !isJoiningMultipleRows && (single || instructions?.limitedTo)) {
1265
1317
  statement += handleLimitedTo(single, instructions?.limitedTo);
1266
1318
  }
1267
- if (["create", "set", "drop"].includes(queryType) && !options?.disableReturning) {
1319
+ if (["create", "set", "drop"].includes(queryType) && returning) {
1268
1320
  statement += "RETURNING * ";
1269
1321
  }
1270
- const finalStatement = statement.trimEnd();
1322
+ const mainStatement = {
1323
+ statement: statement.trimEnd(),
1324
+ params: statementParams || []
1325
+ };
1326
+ if (returning) mainStatement.returning = true;
1271
1327
  return {
1272
- writeStatements,
1273
- readStatement: finalStatement,
1274
- values: statementValues || []
1328
+ dependencies: dependencyStatements,
1329
+ main: mainStatement
1275
1330
  };
1276
1331
  };
1277
1332
 
1278
1333
  // src/index.ts
1279
- var compileQuery = (query, schemas, options) => {
1280
- const statementValues = options?.inlineValues ? null : [];
1281
- return compileQueryInput(query, schemas, statementValues);
1334
+ var compileQueries = (queries, schemas, options) => {
1335
+ const schemaList = addSystemSchemas(schemas).map((schema) => {
1336
+ return addDefaultSchemaFields(schema, true);
1337
+ });
1338
+ const schemaListWithShortcuts = schemaList.map((schema) => {
1339
+ return addDefaultSchemaShortcuts(schemaList, schema);
1340
+ });
1341
+ const dependencyStatements = [];
1342
+ const mainStatements = [];
1343
+ for (const query of queries) {
1344
+ const result = compileQueryInput(
1345
+ query,
1346
+ schemaListWithShortcuts,
1347
+ options?.inlineValues ? null : []
1348
+ );
1349
+ dependencyStatements.push(...result.dependencies);
1350
+ mainStatements.push(result.main);
1351
+ }
1352
+ return [...dependencyStatements, ...mainStatements];
1282
1353
  };
1283
1354
  export {
1284
- compileQuery
1355
+ compileQueries
1285
1356
  };