@ronin/compiler 0.4.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +23 -17
- package/dist/index.d.ts +9 -14228
- package/dist/index.js +249 -178
- package/package.json +1 -1
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 = (
|
99
|
+
var prepareStatementValue = (statementParams, value) => {
|
100
100
|
if (value === null) return "NULL";
|
101
|
-
if (!
|
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 =
|
108
|
+
const index = statementParams.push(formattedValue);
|
109
109
|
return `?${index}`;
|
110
110
|
};
|
111
|
-
var composeFieldValues = (schemas, schema,
|
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
|
-
|
127
|
-
).
|
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(
|
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(
|
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,
|
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,
|
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
|
-
|
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
|
-
|
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,
|
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
|
-
|
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,
|
290
|
+
var handleWith = (schemas, schema, statementParams, instruction, rootTable) => {
|
291
291
|
const subStatement = composeConditions(
|
292
292
|
schemas,
|
293
293
|
schema,
|
294
|
-
|
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.
|
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
|
509
|
-
|
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(
|
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
|
-
|
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
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
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
|
-
|
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
|
-
|
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
|
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,
|
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
|
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
|
-
|
708
|
+
params,
|
670
709
|
filterQuery
|
671
710
|
);
|
672
711
|
statement2 += ` WHERE (${withStatement})`;
|
673
712
|
}
|
674
713
|
}
|
675
|
-
|
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
|
-
|
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,
|
703
|
-
|
704
|
-
}).
|
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
|
-
|
750
|
+
dependencyStatements.push({ statement: statement2, params });
|
712
751
|
return queryInstructions;
|
713
752
|
}
|
714
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
803
|
+
dependencyStatements.push({
|
804
|
+
statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`,
|
805
|
+
params: []
|
806
|
+
});
|
748
807
|
}
|
749
808
|
} else if (queryType === "drop") {
|
750
|
-
|
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,
|
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
|
-
|
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(
|
854
|
+
return prepareStatementValue(statementParams, value === "true");
|
803
855
|
}
|
804
856
|
if (field.type === "number") {
|
805
|
-
return prepareStatementValue(
|
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(
|
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,
|
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
|
-
|
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,
|
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
|
-
|
971
|
+
statementParams
|
920
972
|
);
|
921
|
-
relatedTableSelector = `(${subSelect.
|
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
|
-
|
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
|
-
|
949
|
-
|
950
|
-
|
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,
|
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(
|
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,
|
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,
|
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
|
-
|
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
|
-
|
1070
|
-
{
|
1071
|
-
);
|
1072
|
-
return readStatement;
|
1122
|
+
[],
|
1123
|
+
{ returning: false }
|
1124
|
+
).main;
|
1073
1125
|
};
|
1074
1126
|
if (Array.isArray(fieldValue)) {
|
1075
|
-
|
1127
|
+
dependencyStatements.push(composeStatement("drop"));
|
1076
1128
|
for (const record of fieldValue) {
|
1077
|
-
|
1129
|
+
dependencyStatements.push(composeStatement("create", record));
|
1078
1130
|
}
|
1079
1131
|
} else if (isObject(fieldValue)) {
|
1080
1132
|
for (const recordToAdd of fieldValue.containing || []) {
|
1081
|
-
|
1133
|
+
dependencyStatements.push(composeStatement("create", recordToAdd));
|
1082
1134
|
}
|
1083
1135
|
for (const recordToRemove of fieldValue.notContaining || []) {
|
1084
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
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
|
-
|
1184
|
+
dependencyStatements
|
1134
1185
|
);
|
1135
|
-
const columns = handleSelecting(schema,
|
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,
|
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
|
-
|
1238
|
+
statementParams,
|
1188
1239
|
queryType,
|
1189
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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) &&
|
1319
|
+
if (["create", "set", "drop"].includes(queryType) && returning) {
|
1268
1320
|
statement += "RETURNING * ";
|
1269
1321
|
}
|
1270
|
-
const
|
1322
|
+
const mainStatement = {
|
1323
|
+
statement: statement.trimEnd(),
|
1324
|
+
params: statementParams || []
|
1325
|
+
};
|
1326
|
+
if (returning) mainStatement.returning = true;
|
1271
1327
|
return {
|
1272
|
-
|
1273
|
-
|
1274
|
-
values: statementValues || []
|
1328
|
+
dependencies: dependencyStatements,
|
1329
|
+
main: mainStatement
|
1275
1330
|
};
|
1276
1331
|
};
|
1277
1332
|
|
1278
1333
|
// src/index.ts
|
1279
|
-
var
|
1280
|
-
const
|
1281
|
-
|
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
|
-
|
1355
|
+
compileQueries
|
1285
1356
|
};
|