@ronin/compiler 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +188 -288
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -465,6 +465,8 @@ var SYSTEM_MODELS = [
465
465
  name: "name",
466
466
  slug: "slug"
467
467
  },
468
+ // This name mimics the `sqlite_schema` table in SQLite.
469
+ table: "ronin_schema",
468
470
  fields: [
469
471
  { slug: "name", type: "string" },
470
472
  { slug: "pluralName", type: "string" },
@@ -475,98 +477,16 @@ var SYSTEM_MODELS = [
475
477
  { slug: "identifiers", type: "group" },
476
478
  { slug: "identifiers.name", type: "string" },
477
479
  { 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 }
480
+ // Providing an empty object as a default value allows us to use `json_insert`
481
+ // without needing to fall back to an empty object in the insertion statement,
482
+ // which makes the statement shorter.
483
+ { slug: "fields", type: "json", defaultValue: "{}" },
484
+ { slug: "indexes", type: "json", defaultValue: "{}" },
485
+ { slug: "triggers", type: "json", defaultValue: "{}" },
486
+ { slug: "presets", type: "json", defaultValue: "{}" }
563
487
  ]
564
488
  }
565
- ].map((model) => addDefaultModelFields(model, true));
566
- var SYSTEM_MODEL_SLUGS = SYSTEM_MODELS.flatMap(({ slug, pluralSlug }) => [
567
- slug,
568
- pluralSlug
569
- ]);
489
+ ];
570
490
  var addSystemModels = (models) => {
571
491
  const associativeModels = models.flatMap((model) => {
572
492
  const addedModels = [];
@@ -668,9 +588,9 @@ var addDefaultModelPresets = (list, model) => {
668
588
  return model;
669
589
  };
670
590
  var mappedInstructions = {
671
- add: "to",
672
- set: "with",
673
- remove: "with"
591
+ create: "to",
592
+ alter: "with",
593
+ drop: "with"
674
594
  };
675
595
  var typesInSQLite = {
676
596
  link: "TEXT",
@@ -712,50 +632,179 @@ var getFieldStatement = (models, model, field) => {
712
632
  }
713
633
  return statement;
714
634
  };
715
- var addModelQueries = (models, dependencyStatements, queryDetails) => {
716
- const { queryType, queryModel, queryInstructions } = queryDetails;
717
- if (!["add", "set", "remove"].includes(queryType)) return;
718
- if (!SYSTEM_MODEL_SLUGS.includes(queryModel)) return;
719
- const instructionName = mappedInstructions[queryType];
635
+ var PLURAL_MODEL_ENTITIES = {
636
+ field: "fields",
637
+ index: "indexes",
638
+ trigger: "triggers",
639
+ preset: "presets"
640
+ };
641
+ var transformMetaQuery = (models, dependencyStatements, statementParams, query) => {
642
+ const { queryType } = splitQuery(query);
643
+ let action = queryType;
644
+ let entity = "model";
645
+ let queryInstructions;
646
+ if (query.create) {
647
+ const init = query.create.model;
648
+ const details = "to" in query.create ? { slug: init, ...query.create.to } : init;
649
+ queryInstructions = {
650
+ to: details
651
+ };
652
+ }
653
+ if (query.drop) {
654
+ queryInstructions = {
655
+ with: { slug: query.drop.model }
656
+ };
657
+ }
658
+ if (query.alter) {
659
+ const modelSlugTest = query.alter.model;
660
+ if ("to" in query.alter) {
661
+ queryInstructions = {
662
+ with: { slug: modelSlugTest },
663
+ to: query.alter.to
664
+ };
665
+ } else {
666
+ action = Object.keys(query.alter).filter(
667
+ (key) => key !== "model"
668
+ )[0];
669
+ const details = query.alter[action];
670
+ entity = Object.keys(details)[0];
671
+ let jsonSlug = details[entity];
672
+ let jsonValue2;
673
+ if ("create" in query.alter) {
674
+ const item = query.alter.create[entity];
675
+ jsonSlug = item.slug || `${entity}Slug`;
676
+ jsonValue2 = { slug: jsonSlug, ...item };
677
+ queryInstructions = {
678
+ to: {
679
+ model: { slug: modelSlugTest },
680
+ ...jsonValue2
681
+ }
682
+ };
683
+ }
684
+ if ("alter" in query.alter) {
685
+ jsonValue2 = query.alter.alter.to;
686
+ queryInstructions = {
687
+ with: { model: { slug: modelSlugTest }, slug: jsonSlug },
688
+ to: jsonValue2
689
+ };
690
+ }
691
+ if ("drop" in query.alter) {
692
+ queryInstructions = {
693
+ with: { model: { slug: modelSlugTest }, slug: jsonSlug }
694
+ };
695
+ }
696
+ }
697
+ }
698
+ if (!queryInstructions) return query;
699
+ const instructionName = mappedInstructions[action];
720
700
  const instructionList = queryInstructions[instructionName];
721
- const kind = getModelBySlug(SYSTEM_MODELS, queryModel).pluralSlug;
722
701
  let tableAction = "ALTER";
723
- let queryTypeReadable = null;
724
- switch (queryType) {
725
- case "add": {
726
- if (kind === "models" || kind === "indexes" || kind === "triggers") {
702
+ let actionReadable = null;
703
+ switch (action) {
704
+ case "create": {
705
+ if (entity === "model" || entity === "index" || entity === "trigger") {
727
706
  tableAction = "CREATE";
728
707
  }
729
- queryTypeReadable = "creating";
708
+ actionReadable = "creating";
730
709
  break;
731
710
  }
732
- case "set": {
733
- if (kind === "models") tableAction = "ALTER";
734
- queryTypeReadable = "updating";
711
+ case "alter": {
712
+ if (entity === "model") tableAction = "ALTER";
713
+ actionReadable = "updating";
735
714
  break;
736
715
  }
737
- case "remove": {
738
- if (kind === "models" || kind === "indexes" || kind === "triggers") {
716
+ case "drop": {
717
+ if (entity === "model" || entity === "index" || entity === "trigger") {
739
718
  tableAction = "DROP";
740
719
  }
741
- queryTypeReadable = "deleting";
720
+ actionReadable = "deleting";
742
721
  break;
743
722
  }
744
723
  }
745
724
  const slug = instructionList?.slug?.being || instructionList?.slug;
746
725
  const modelInstruction = instructionList?.model;
747
726
  const modelSlug = modelInstruction?.slug?.being || modelInstruction?.slug;
748
- const usableSlug = kind === "models" ? slug : modelSlug;
727
+ const usableSlug = entity === "model" ? slug : modelSlug;
749
728
  const tableName = convertToSnakeCase(pluralize(usableSlug));
750
- const targetModel = kind === "models" && queryType === "add" ? null : getModelBySlug(models, usableSlug);
751
- if (kind === "indexes") {
729
+ const targetModel = entity === "model" && action === "create" ? null : getModelBySlug(models, usableSlug);
730
+ const statement = `${tableAction} TABLE "${tableName}"`;
731
+ if (entity === "model") {
732
+ let queryTypeDetails;
733
+ if (action === "create") {
734
+ const modelWithFields = addDefaultModelFields(queryInstructions.to, true);
735
+ const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
736
+ const { fields } = modelWithPresets;
737
+ const columns = fields.map((field) => getFieldStatement(models, modelWithPresets, field)).filter(Boolean);
738
+ dependencyStatements.push({
739
+ statement: `${statement} (${columns.join(", ")})`,
740
+ params: []
741
+ });
742
+ models.push(modelWithPresets);
743
+ queryTypeDetails = { to: modelWithPresets };
744
+ }
745
+ if (action === "alter") {
746
+ const modelWithFields = addDefaultModelFields(queryInstructions.to, false);
747
+ const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
748
+ const newSlug = modelWithPresets.pluralSlug;
749
+ if (newSlug) {
750
+ const newTable = convertToSnakeCase(newSlug);
751
+ dependencyStatements.push({
752
+ statement: `${statement} RENAME TO "${newTable}"`,
753
+ params: []
754
+ });
755
+ }
756
+ Object.assign(targetModel, modelWithPresets);
757
+ queryTypeDetails = {
758
+ with: {
759
+ slug: usableSlug
760
+ },
761
+ to: modelWithPresets
762
+ };
763
+ }
764
+ if (action === "drop") {
765
+ models.splice(models.indexOf(targetModel), 1);
766
+ dependencyStatements.push({ statement, params: [] });
767
+ queryTypeDetails = {
768
+ with: { slug: usableSlug }
769
+ };
770
+ }
771
+ const queryTypeAction = action === "create" ? "add" : action === "alter" ? "set" : "remove";
772
+ return {
773
+ [queryTypeAction]: {
774
+ model: queryTypeDetails
775
+ }
776
+ };
777
+ }
778
+ if (entity === "field") {
779
+ if (action === "create") {
780
+ if (!instructionList.type) instructionList.type = "string";
781
+ dependencyStatements.push({
782
+ statement: `${statement} ADD COLUMN ${getFieldStatement(models, targetModel, instructionList)}`,
783
+ params: []
784
+ });
785
+ } else if (action === "alter") {
786
+ const newSlug = queryInstructions.to?.slug;
787
+ if (newSlug) {
788
+ dependencyStatements.push({
789
+ statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`,
790
+ params: []
791
+ });
792
+ }
793
+ } else if (action === "drop") {
794
+ dependencyStatements.push({
795
+ statement: `${statement} DROP COLUMN "${slug}"`,
796
+ params: []
797
+ });
798
+ }
799
+ }
800
+ if (entity === "index") {
752
801
  const indexName = convertToSnakeCase(slug);
753
802
  const unique = instructionList?.unique;
754
803
  const filterQuery = instructionList?.filter;
755
804
  const fields = instructionList?.fields;
756
805
  const params = [];
757
806
  let statement2 = `${tableAction}${unique ? " UNIQUE" : ""} INDEX "${indexName}"`;
758
- if (queryType === "add") {
807
+ if (action === "create") {
759
808
  const model = targetModel;
760
809
  const columns = fields.map((field) => {
761
810
  let fieldSelector = "";
@@ -780,23 +829,22 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
780
829
  }
781
830
  }
782
831
  dependencyStatements.push({ statement: statement2, params });
783
- return;
784
832
  }
785
- if (kind === "triggers") {
833
+ if (entity === "trigger") {
786
834
  const triggerName = convertToSnakeCase(slug);
787
835
  const params = [];
788
836
  let statement2 = `${tableAction} TRIGGER "${triggerName}"`;
789
- if (queryType === "add") {
837
+ if (action === "create") {
790
838
  const currentModel = targetModel;
791
- const { when, action } = instructionList;
792
- const statementParts = [`${when} ${action}`];
839
+ const { when, action: action2 } = instructionList;
840
+ const statementParts = [`${when} ${action2}`];
793
841
  const effectQueries = instructionList?.effects;
794
842
  const filterQuery = instructionList?.filter;
795
843
  const fields = instructionList?.fields;
796
844
  if (fields) {
797
- if (action !== "UPDATE") {
845
+ if (action2 !== "UPDATE") {
798
846
  throw new RoninError({
799
- message: `When ${queryTypeReadable} ${kind}, targeting specific fields requires the \`UPDATE\` action.`,
847
+ message: `When ${actionReadable} ${PLURAL_MODEL_ENTITIES[entity]}, targeting specific fields requires the \`UPDATE\` action.`,
800
848
  code: "INVALID_MODEL_VALUE",
801
849
  fields: ["action"]
802
850
  });
@@ -807,11 +855,11 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
807
855
  statementParts.push(`OF (${fieldSelectors.join(", ")})`);
808
856
  }
809
857
  statementParts.push("ON", `"${tableName}"`);
810
- if (filterQuery || effectQueries.some((query) => findInObject(query, RONIN_MODEL_SYMBOLS.FIELD))) {
858
+ if (filterQuery || effectQueries.some((query2) => findInObject(query2, RONIN_MODEL_SYMBOLS.FIELD))) {
811
859
  statementParts.push("FOR EACH ROW");
812
860
  }
813
861
  if (filterQuery) {
814
- const tableAlias = action === "DELETE" ? RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD : RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW;
862
+ const tableAlias = action2 === "DELETE" ? RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD : RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW;
815
863
  const withStatement = handleWith(
816
864
  models,
817
865
  { ...currentModel, tableAlias },
@@ -832,57 +880,23 @@ var addModelQueries = (models, dependencyStatements, queryDetails) => {
832
880
  statement2 += ` ${statementParts.join(" ")}`;
833
881
  }
834
882
  dependencyStatements.push({ statement: statement2, params });
835
- return;
836
- }
837
- const statement = `${tableAction} TABLE "${tableName}"`;
838
- if (kind === "models") {
839
- if (queryType === "add") {
840
- const newModel = queryInstructions.to;
841
- const { fields } = newModel;
842
- const columns = fields.map((field) => getFieldStatement(models, newModel, field)).filter(Boolean);
843
- dependencyStatements.push({
844
- statement: `${statement} (${columns.join(", ")})`,
845
- params: []
846
- });
847
- models.push(newModel);
848
- } else if (queryType === "set") {
849
- const newSlug = queryInstructions.to?.pluralSlug;
850
- if (newSlug) {
851
- const newTable = convertToSnakeCase(newSlug);
852
- dependencyStatements.push({
853
- statement: `${statement} RENAME TO "${newTable}"`,
854
- params: []
855
- });
856
- }
857
- Object.assign(targetModel, queryInstructions.to);
858
- } else if (queryType === "remove") {
859
- models.splice(models.indexOf(targetModel), 1);
860
- dependencyStatements.push({ statement, params: [] });
861
- }
862
- return;
863
883
  }
864
- if (kind === "fields") {
865
- if (queryType === "add") {
866
- if (!instructionList.type) instructionList.type = "string";
867
- dependencyStatements.push({
868
- statement: `${statement} ADD COLUMN ${getFieldStatement(models, targetModel, instructionList)}`,
869
- params: []
870
- });
871
- } else if (queryType === "set") {
872
- const newSlug = queryInstructions.to?.slug;
873
- if (newSlug) {
874
- dependencyStatements.push({
875
- statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`,
876
- params: []
877
- });
884
+ const pluralType = PLURAL_MODEL_ENTITIES[entity];
885
+ const jsonAction = action === "create" ? "insert" : action === "alter" ? "patch" : "remove";
886
+ const jsonValue = action === "create" ? { ...instructionList, model: void 0 } : action === "alter" ? queryInstructions.to : null;
887
+ let json = `json_${jsonAction}(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType}, '$.${slug}'`;
888
+ if (jsonValue) json += `, ${prepareStatementValue(statementParams, jsonValue)}`;
889
+ json += ")";
890
+ return {
891
+ set: {
892
+ model: {
893
+ with: { slug: usableSlug },
894
+ to: {
895
+ [pluralType]: { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json }
896
+ }
878
897
  }
879
- } else if (queryType === "remove") {
880
- dependencyStatements.push({
881
- statement: `${statement} DROP COLUMN "${slug}"`,
882
- params: []
883
- });
884
898
  }
885
- }
899
+ };
886
900
  };
887
901
 
888
902
  // src/instructions/before-after.ts
@@ -1381,122 +1395,6 @@ var compileQueryInput = (query, models, statementParams, options) => {
1381
1395
  };
1382
1396
  };
1383
1397
 
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
1398
  // src/index.ts
1501
1399
  var compileQueries = (queries, models, options) => {
1502
1400
  const modelList = addSystemModels(models).map((model) => {
@@ -1508,15 +1406,17 @@ var compileQueries = (queries, models, options) => {
1508
1406
  const dependencyStatements = [];
1509
1407
  const mainStatements = [];
1510
1408
  for (const query of queries) {
1409
+ const statementValues = options?.inlineParams ? null : [];
1511
1410
  const transformedQuery = transformMetaQuery(
1512
1411
  modelListWithPresets,
1513
1412
  dependencyStatements,
1413
+ statementValues,
1514
1414
  query
1515
1415
  );
1516
1416
  const result = compileQueryInput(
1517
1417
  transformedQuery,
1518
1418
  modelListWithPresets,
1519
- options?.inlineParams ? null : []
1419
+ statementValues
1520
1420
  );
1521
1421
  dependencyStatements.push(...result.dependencies);
1522
1422
  mainStatements.push(result.main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ronin/compiler",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "type": "module",
5
5
  "description": "Compiles RONIN queries to SQL statements.",
6
6
  "publishConfig": {