@ronin/compiler 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +15 -15
  2. package/dist/index.js +169 -219
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -5880,23 +5880,23 @@ type ModelFieldReference = ModelFieldBasics & {
5880
5880
  };
5881
5881
  };
5882
5882
  type ModelField = ModelFieldNormal | ModelFieldReference;
5883
- type ModelIndexField = {
5883
+ type ModelIndexField<T extends Array<ModelField> = Array<ModelField>> = {
5884
5884
  /** The collating sequence used for text placed inside the field. */
5885
5885
  collation?: ModelFieldCollation;
5886
5886
  /** How the records in the index should be ordered. */
5887
5887
  order?: 'ASC' | 'DESC';
5888
5888
  } & ({
5889
5889
  /** The field slug for which the index should be created. */
5890
- slug: string;
5890
+ slug: T[number]['slug'];
5891
5891
  } | {
5892
5892
  /** The field expression for which the index should be created. */
5893
5893
  expression: string;
5894
5894
  });
5895
- type ModelIndex = {
5895
+ type ModelIndex<T extends Array<ModelField> = Array<ModelField>> = {
5896
5896
  /**
5897
5897
  * The list of fields in the model for which the index should be created.
5898
5898
  */
5899
- fields: Array<ModelIndexField>;
5899
+ fields: Array<ModelIndexField<T>>;
5900
5900
  /**
5901
5901
  * The identifier of the index.
5902
5902
  */
@@ -5911,14 +5911,14 @@ type ModelIndex = {
5911
5911
  */
5912
5912
  filter?: WithInstruction;
5913
5913
  };
5914
- type ModelTriggerField = {
5914
+ type ModelTriggerField<T extends Array<ModelField> = Array<ModelField>> = {
5915
5915
  /**
5916
5916
  * The slug of the field that should cause the trigger to fire if the value of the
5917
5917
  * field has changed.
5918
5918
  */
5919
- slug: string;
5919
+ slug: T[number]['slug'];
5920
5920
  };
5921
- type ModelTrigger = {
5921
+ type ModelTrigger<T extends Array<ModelField> = Array<ModelField>> = {
5922
5922
  /** The type of query for which the trigger should fire. */
5923
5923
  action: 'INSERT' | 'UPDATE' | 'DELETE';
5924
5924
  /** When the trigger should fire in the case that a matching query is executed. */
@@ -5926,7 +5926,7 @@ type ModelTrigger = {
5926
5926
  /** A list of queries that should be executed when the trigger fires. */
5927
5927
  effects: Array<Query>;
5928
5928
  /** A list of field slugs for which the trigger should fire. */
5929
- fields?: Array<ModelTriggerField>;
5929
+ fields?: Array<ModelTriggerField<T>>;
5930
5930
  /**
5931
5931
  * An object containing query instructions used to determine whether the trigger should
5932
5932
  * fire, or not.
@@ -5939,14 +5939,14 @@ type ModelPreset = {
5939
5939
  /** The query instructions that should be applied when the preset is used. */
5940
5940
  instructions: GetInstructions;
5941
5941
  };
5942
- interface Model {
5942
+ interface Model<T extends Array<ModelField> = Array<ModelField>> {
5943
5943
  name: string;
5944
5944
  pluralName: string;
5945
5945
  slug: string;
5946
5946
  pluralSlug: string;
5947
5947
  identifiers: {
5948
- name: string;
5949
- slug: string;
5948
+ name: T[number]['slug'];
5949
+ slug: T[number]['slug'];
5950
5950
  };
5951
5951
  idPrefix: string;
5952
5952
  /** The name of the table in SQLite. */
@@ -5962,12 +5962,12 @@ interface Model {
5962
5962
  * the associative model should be mounted on the source model.
5963
5963
  */
5964
5964
  associationSlug?: string;
5965
- fields: Array<ModelField>;
5966
- indexes?: Array<ModelIndex>;
5967
- triggers?: Array<ModelTrigger>;
5965
+ fields: T;
5966
+ indexes?: Array<ModelIndex<T>>;
5967
+ triggers?: Array<ModelTrigger<T>>;
5968
5968
  presets?: Array<ModelPreset>;
5969
5969
  }
5970
- type PublicModel = Omit<Partial<Model>, 'slug' | 'identifiers' | 'associationSlug' | 'table' | 'tableAlias'> & {
5970
+ type PublicModel<T extends Array<ModelField> = Array<ModelField>> = Omit<Partial<Model<T>>, 'slug' | 'identifiers' | 'associationSlug' | 'table' | 'tableAlias'> & {
5971
5971
  slug: Required<Model['slug']>;
5972
5972
  identifiers?: Partial<Model['identifiers']>;
5973
5973
  };
package/dist/index.js CHANGED
@@ -318,6 +318,151 @@ var handleWith = (models, model, statementParams, instruction, parentModel) => {
318
318
  return `(${subStatement})`;
319
319
  };
320
320
 
321
+ // src/utils/meta.ts
322
+ var PLURAL_MODEL_ENTITIES = {
323
+ field: "fields",
324
+ index: "indexes",
325
+ trigger: "triggers",
326
+ preset: "presets"
327
+ };
328
+ var transformMetaQuery = (models, dependencyStatements, statementParams, query) => {
329
+ if (query.create) {
330
+ const init = query.create.model;
331
+ const details = "to" in query.create ? { slug: init, ...query.create.to } : init;
332
+ const modelWithFields = addDefaultModelFields(details, true);
333
+ const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
334
+ const instructions = {
335
+ to: modelWithPresets
336
+ };
337
+ addModelQueries(models, dependencyStatements, {
338
+ queryType: "add",
339
+ queryModel: "model",
340
+ queryInstructions: instructions
341
+ });
342
+ return {
343
+ add: {
344
+ model: instructions
345
+ }
346
+ };
347
+ }
348
+ if (query.drop) {
349
+ const slug = query.drop.model;
350
+ const instructions = {
351
+ with: { slug }
352
+ };
353
+ addModelQueries(models, dependencyStatements, {
354
+ queryType: "remove",
355
+ queryModel: "model",
356
+ queryInstructions: instructions
357
+ });
358
+ return {
359
+ remove: {
360
+ model: instructions
361
+ }
362
+ };
363
+ }
364
+ if (query.alter) {
365
+ const slug = query.alter.model;
366
+ if ("to" in query.alter) {
367
+ const modelWithFields = addDefaultModelFields(query.alter.to, false);
368
+ const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
369
+ const instructions = {
370
+ with: { slug },
371
+ to: modelWithPresets
372
+ };
373
+ addModelQueries(models, dependencyStatements, {
374
+ queryType: "set",
375
+ queryModel: "model",
376
+ queryInstructions: instructions
377
+ });
378
+ return {
379
+ set: {
380
+ model: instructions
381
+ }
382
+ };
383
+ }
384
+ if ("create" in query.alter) {
385
+ const type2 = Object.keys(query.alter.create)[0];
386
+ const pluralType2 = PLURAL_MODEL_ENTITIES[type2];
387
+ const item = query.alter.create[type2];
388
+ const completeItem = { slug: item.slug || `${type2}Slug`, ...item };
389
+ addModelQueries(models, dependencyStatements, {
390
+ queryType: "add",
391
+ queryModel: type2,
392
+ queryInstructions: {
393
+ to: {
394
+ model: { slug },
395
+ ...completeItem
396
+ }
397
+ }
398
+ });
399
+ const value = prepareStatementValue(statementParams, completeItem);
400
+ const json2 = `json_insert(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType2}, '$.${completeItem.slug}', ${value})`;
401
+ const expression2 = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json2 };
402
+ return {
403
+ set: {
404
+ model: {
405
+ with: { slug },
406
+ to: {
407
+ [pluralType2]: expression2
408
+ }
409
+ }
410
+ }
411
+ };
412
+ }
413
+ if ("alter" in query.alter) {
414
+ const type2 = Object.keys(query.alter.alter)[0];
415
+ const pluralType2 = PLURAL_MODEL_ENTITIES[type2];
416
+ const itemSlug2 = query.alter.alter[type2];
417
+ const newItem = query.alter.alter.to;
418
+ addModelQueries(models, dependencyStatements, {
419
+ queryType: "set",
420
+ queryModel: type2,
421
+ queryInstructions: {
422
+ with: { model: { slug }, slug: itemSlug2 },
423
+ to: newItem
424
+ }
425
+ });
426
+ const value = prepareStatementValue(statementParams, newItem);
427
+ const json2 = `json_patch(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType2}, '$.${itemSlug2}', ${value})`;
428
+ const expression2 = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json2 };
429
+ return {
430
+ set: {
431
+ model: {
432
+ with: { slug },
433
+ to: {
434
+ [pluralType2]: expression2
435
+ }
436
+ }
437
+ }
438
+ };
439
+ }
440
+ const type = Object.keys(query.alter.drop)[0];
441
+ const pluralType = PLURAL_MODEL_ENTITIES[type];
442
+ const itemSlug = query.alter.drop[type];
443
+ addModelQueries(models, dependencyStatements, {
444
+ queryType: "remove",
445
+ queryModel: type,
446
+ queryInstructions: {
447
+ with: { model: { slug }, slug: itemSlug }
448
+ }
449
+ });
450
+ const json = `json_insert(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType}, '$.${itemSlug}')`;
451
+ const expression = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json };
452
+ return {
453
+ set: {
454
+ model: {
455
+ with: { slug },
456
+ to: {
457
+ [pluralType]: expression
458
+ }
459
+ }
460
+ }
461
+ };
462
+ }
463
+ return query;
464
+ };
465
+
321
466
  // src/utils/model.ts
322
467
  import title from "title";
323
468
  var getModelBySlug = (models, slug) => {
@@ -465,6 +610,8 @@ var SYSTEM_MODELS = [
465
610
  name: "name",
466
611
  slug: "slug"
467
612
  },
613
+ // This name mimics the `sqlite_schema` table in SQLite.
614
+ table: "ronin_schema",
468
615
  fields: [
469
616
  { slug: "name", type: "string" },
470
617
  { slug: "pluralName", type: "string" },
@@ -475,98 +622,16 @@ var SYSTEM_MODELS = [
475
622
  { slug: "identifiers", type: "group" },
476
623
  { slug: "identifiers.name", type: "string" },
477
624
  { slug: "identifiers.slug", type: "string" },
478
- { slug: "fields", type: "json" },
479
- { slug: "indexes", type: "json" },
480
- { slug: "triggers", type: "json" },
481
- { slug: "presets", type: "json" }
482
- ]
483
- },
484
- {
485
- slug: "field",
486
- identifiers: {
487
- name: "name",
488
- slug: "slug"
489
- },
490
- fields: [
491
- { slug: "name", type: "string" },
492
- { slug: "slug", type: "string", required: true },
493
- { slug: "type", type: "string", required: true },
494
- {
495
- slug: "model",
496
- type: "link",
497
- target: "model",
498
- required: true
499
- },
500
- { slug: "required", type: "boolean" },
501
- { slug: "defaultValue", type: "string" },
502
- { slug: "unique", type: "boolean" },
503
- { slug: "autoIncrement", type: "boolean" },
504
- // Only allowed for fields of type "link".
505
- { slug: "target", type: "string" },
506
- { slug: "kind", type: "string" },
507
- { slug: "actions", type: "group" },
508
- { slug: "actions.onDelete", type: "string" },
509
- { slug: "actions.onUpdate", type: "string" }
510
- ]
511
- },
512
- {
513
- slug: "index",
514
- identifiers: {
515
- name: "slug",
516
- slug: "slug"
517
- },
518
- fields: [
519
- { slug: "slug", type: "string", required: true },
520
- {
521
- slug: "model",
522
- type: "link",
523
- target: "model",
524
- required: true
525
- },
526
- { slug: "unique", type: "boolean" },
527
- { slug: "filter", type: "json" },
528
- { slug: "fields", type: "json", required: true }
529
- ]
530
- },
531
- {
532
- slug: "trigger",
533
- identifiers: {
534
- name: "slug",
535
- slug: "slug"
536
- },
537
- fields: [
538
- { slug: "slug", type: "string", required: true },
539
- {
540
- slug: "model",
541
- type: "link",
542
- target: "model",
543
- required: true
544
- },
545
- { slug: "when", type: "string", required: true },
546
- { slug: "action", type: "string", required: true },
547
- { slug: "filter", type: "json" },
548
- { slug: "effects", type: "json", required: true },
549
- { slug: "fields", type: "json" }
550
- ]
551
- },
552
- {
553
- slug: "preset",
554
- fields: [
555
- { slug: "slug", type: "string", required: true },
556
- {
557
- slug: "model",
558
- type: "link",
559
- target: "model",
560
- required: true
561
- },
562
- { slug: "instructions", type: "json", required: true }
625
+ // Providing an empty object as a default value allows us to use `json_insert`
626
+ // without needing to fall back to an empty object in the insertion statement,
627
+ // which makes the statement shorter.
628
+ { slug: "fields", type: "json", defaultValue: "{}" },
629
+ { slug: "indexes", type: "json", defaultValue: "{}" },
630
+ { slug: "triggers", type: "json", defaultValue: "{}" },
631
+ { slug: "presets", type: "json", defaultValue: "{}" }
563
632
  ]
564
633
  }
565
- ].map((model) => addDefaultModelFields(model, true));
566
- var SYSTEM_MODEL_SLUGS = SYSTEM_MODELS.flatMap(({ slug, pluralSlug }) => [
567
- slug,
568
- pluralSlug
569
- ]);
634
+ ];
570
635
  var addSystemModels = (models) => {
571
636
  const associativeModels = models.flatMap((model) => {
572
637
  const addedModels = [];
@@ -715,27 +780,26 @@ var getFieldStatement = (models, model, field) => {
715
780
  var addModelQueries = (models, dependencyStatements, queryDetails) => {
716
781
  const { queryType, queryModel, queryInstructions } = queryDetails;
717
782
  if (!["add", "set", "remove"].includes(queryType)) return;
718
- if (!SYSTEM_MODEL_SLUGS.includes(queryModel)) return;
783
+ if (!["model", "field", "index", "trigger", "preset"].includes(queryModel)) return;
719
784
  const instructionName = mappedInstructions[queryType];
720
785
  const instructionList = queryInstructions[instructionName];
721
- const kind = getModelBySlug(SYSTEM_MODELS, queryModel).pluralSlug;
722
786
  let tableAction = "ALTER";
723
787
  let queryTypeReadable = null;
724
788
  switch (queryType) {
725
789
  case "add": {
726
- if (kind === "models" || kind === "indexes" || kind === "triggers") {
790
+ if (queryModel === "model" || queryModel === "index" || queryModel === "trigger") {
727
791
  tableAction = "CREATE";
728
792
  }
729
793
  queryTypeReadable = "creating";
730
794
  break;
731
795
  }
732
796
  case "set": {
733
- if (kind === "models") tableAction = "ALTER";
797
+ if (queryModel === "model") tableAction = "ALTER";
734
798
  queryTypeReadable = "updating";
735
799
  break;
736
800
  }
737
801
  case "remove": {
738
- if (kind === "models" || kind === "indexes" || kind === "triggers") {
802
+ if (queryModel === "model" || queryModel === "index" || queryModel === "trigger") {
739
803
  tableAction = "DROP";
740
804
  }
741
805
  queryTypeReadable = "deleting";
@@ -745,10 +809,10 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
745
809
  const slug = instructionList?.slug?.being || instructionList?.slug;
746
810
  const modelInstruction = instructionList?.model;
747
811
  const modelSlug = modelInstruction?.slug?.being || modelInstruction?.slug;
748
- const usableSlug = kind === "models" ? slug : modelSlug;
812
+ const usableSlug = queryModel === "model" ? slug : modelSlug;
749
813
  const tableName = convertToSnakeCase(pluralize(usableSlug));
750
- const targetModel = kind === "models" && queryType === "add" ? null : getModelBySlug(models, usableSlug);
751
- if (kind === "indexes") {
814
+ const targetModel = queryModel === "model" && queryType === "add" ? null : getModelBySlug(models, usableSlug);
815
+ if (queryModel === "index") {
752
816
  const indexName = convertToSnakeCase(slug);
753
817
  const unique = instructionList?.unique;
754
818
  const filterQuery = instructionList?.filter;
@@ -782,7 +846,7 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
782
846
  dependencyStatements.push({ statement: statement2, params });
783
847
  return;
784
848
  }
785
- if (kind === "triggers") {
849
+ if (queryModel === "trigger") {
786
850
  const triggerName = convertToSnakeCase(slug);
787
851
  const params = [];
788
852
  let statement2 = `${tableAction} TRIGGER "${triggerName}"`;
@@ -796,7 +860,7 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
796
860
  if (fields) {
797
861
  if (action !== "UPDATE") {
798
862
  throw new RoninError({
799
- message: `When ${queryTypeReadable} ${kind}, targeting specific fields requires the \`UPDATE\` action.`,
863
+ message: `When ${queryTypeReadable} ${PLURAL_MODEL_ENTITIES[queryModel]}, targeting specific fields requires the \`UPDATE\` action.`,
800
864
  code: "INVALID_MODEL_VALUE",
801
865
  fields: ["action"]
802
866
  });
@@ -835,7 +899,7 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
835
899
  return;
836
900
  }
837
901
  const statement = `${tableAction} TABLE "${tableName}"`;
838
- if (kind === "models") {
902
+ if (queryModel === "model") {
839
903
  if (queryType === "add") {
840
904
  const newModel = queryInstructions.to;
841
905
  const { fields } = newModel;
@@ -861,7 +925,7 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
861
925
  }
862
926
  return;
863
927
  }
864
- if (kind === "fields") {
928
+ if (queryModel === "field") {
865
929
  if (queryType === "add") {
866
930
  if (!instructionList.type) instructionList.type = "string";
867
931
  dependencyStatements.push({
@@ -1381,122 +1445,6 @@ var compileQueryInput = (query, models, statementParams, options) => {
1381
1445
  };
1382
1446
  };
1383
1447
 
1384
- // src/utils/meta.ts
1385
- var transformMetaQuery = (models, dependencyStatements, query) => {
1386
- if (query.create) {
1387
- const init = query.create.model;
1388
- const details = "to" in query.create ? { slug: init, ...query.create.to } : init;
1389
- const modelWithFields = addDefaultModelFields(details, true);
1390
- const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
1391
- const instructions = {
1392
- to: modelWithPresets
1393
- };
1394
- addModelQueries(models, dependencyStatements, {
1395
- queryType: "add",
1396
- queryModel: "model",
1397
- queryInstructions: instructions
1398
- });
1399
- return {
1400
- add: {
1401
- model: instructions
1402
- }
1403
- };
1404
- }
1405
- if (query.drop) {
1406
- const slug = query.drop.model;
1407
- const instructions = {
1408
- with: { slug }
1409
- };
1410
- addModelQueries(models, dependencyStatements, {
1411
- queryType: "remove",
1412
- queryModel: "model",
1413
- queryInstructions: instructions
1414
- });
1415
- return {
1416
- remove: {
1417
- model: instructions
1418
- }
1419
- };
1420
- }
1421
- if (query.alter) {
1422
- const slug = query.alter.model;
1423
- if ("to" in query.alter) {
1424
- const modelWithFields = addDefaultModelFields(query.alter.to, false);
1425
- const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
1426
- const instructions2 = {
1427
- with: { slug },
1428
- to: modelWithPresets
1429
- };
1430
- addModelQueries(models, dependencyStatements, {
1431
- queryType: "set",
1432
- queryModel: "model",
1433
- queryInstructions: instructions2
1434
- });
1435
- return {
1436
- set: {
1437
- model: instructions2
1438
- }
1439
- };
1440
- }
1441
- if ("create" in query.alter) {
1442
- const type2 = Object.keys(query.alter.create)[0];
1443
- const item = query.alter.create[type2];
1444
- const completeItem = { slug: item.slug || `${type2}_slug`, ...item };
1445
- const instructions2 = {
1446
- to: {
1447
- model: { slug },
1448
- ...completeItem
1449
- }
1450
- };
1451
- addModelQueries(models, dependencyStatements, {
1452
- queryType: "add",
1453
- queryModel: type2,
1454
- queryInstructions: instructions2
1455
- });
1456
- return {
1457
- add: {
1458
- [type2]: instructions2
1459
- }
1460
- };
1461
- }
1462
- if ("alter" in query.alter) {
1463
- const type2 = Object.keys(query.alter.alter)[0];
1464
- const itemSlug2 = query.alter.alter[type2];
1465
- const newItem = query.alter.alter.to;
1466
- const instructions2 = {
1467
- with: { model: { slug }, slug: itemSlug2 },
1468
- to: newItem
1469
- };
1470
- addModelQueries(models, dependencyStatements, {
1471
- queryType: "set",
1472
- queryModel: type2,
1473
- queryInstructions: instructions2
1474
- });
1475
- return {
1476
- set: {
1477
- [type2]: instructions2
1478
- }
1479
- };
1480
- }
1481
- const type = Object.keys(query.alter.drop)[0];
1482
- const itemSlug = query.alter.drop[type];
1483
- const instructions = {
1484
- with: { model: { slug }, slug: itemSlug }
1485
- };
1486
- addModelQueries(models, dependencyStatements, {
1487
- queryType: "remove",
1488
- queryModel: type,
1489
- queryInstructions: instructions
1490
- });
1491
- return {
1492
- remove: {
1493
- [type]: instructions
1494
- }
1495
- };
1496
- }
1497
- return query;
1498
- };
1499
-
1500
1448
  // src/index.ts
1501
1449
  var compileQueries = (queries, models, options) => {
1502
1450
  const modelList = addSystemModels(models).map((model) => {
@@ -1508,15 +1456,17 @@ var compileQueries = (queries, models, options) => {
1508
1456
  const dependencyStatements = [];
1509
1457
  const mainStatements = [];
1510
1458
  for (const query of queries) {
1459
+ const statementValues = options?.inlineParams ? null : [];
1511
1460
  const transformedQuery = transformMetaQuery(
1512
1461
  modelListWithPresets,
1513
1462
  dependencyStatements,
1463
+ statementValues,
1514
1464
  query
1515
1465
  );
1516
1466
  const result = compileQueryInput(
1517
1467
  transformedQuery,
1518
1468
  modelListWithPresets,
1519
- options?.inlineParams ? null : []
1469
+ statementValues
1520
1470
  );
1521
1471
  dependencyStatements.push(...result.dependencies);
1522
1472
  mainStatements.push(result.main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.8.2",
3
+ "version": "0.8.4",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {