@ronin/compiler 0.9.0-leo-ron-1083-experimental-203 → 0.9.0-leo-ron-1083-experimental-205
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.d.ts +14 -6
- package/dist/index.js +151 -105
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
@@ -5920,7 +5920,7 @@ type ModelTriggerField<T extends Array<ModelField> = Array<ModelField>> = {
|
|
5920
5920
|
};
|
5921
5921
|
type ModelTrigger<T extends Array<ModelField> = Array<ModelField>> = {
|
5922
5922
|
/**
|
5923
|
-
* The identifier of the
|
5923
|
+
* The identifier of the trigger.
|
5924
5924
|
*/
|
5925
5925
|
slug?: string;
|
5926
5926
|
/** The type of query for which the trigger should fire. */
|
@@ -5961,17 +5961,25 @@ interface Model<T extends Array<ModelField> = Array<ModelField>> {
|
|
5961
5961
|
*/
|
5962
5962
|
tableAlias?: string;
|
5963
5963
|
/**
|
5964
|
-
*
|
5965
|
-
*
|
5966
|
-
* the associative model should be mounted on the source model.
|
5964
|
+
* Details that identify the model as a model that was automatically created by RONIN,
|
5965
|
+
* instead of being manually created by a developer.
|
5967
5966
|
*/
|
5968
|
-
|
5967
|
+
system?: {
|
5968
|
+
/** The model that caused the system model to get created. */
|
5969
|
+
model: string | 'root';
|
5970
|
+
/**
|
5971
|
+
* If the model is used to associate two models with each other (in the case of
|
5972
|
+
* many-cardinality link fields), this property should contain the field slug to
|
5973
|
+
* which the associative model should be mounted on the source model.
|
5974
|
+
*/
|
5975
|
+
associationSlug?: string;
|
5976
|
+
};
|
5969
5977
|
fields: T;
|
5970
5978
|
indexes?: Array<ModelIndex<T>>;
|
5971
5979
|
triggers?: Array<ModelTrigger<T>>;
|
5972
5980
|
presets?: Array<ModelPreset>;
|
5973
5981
|
}
|
5974
|
-
type PublicModel<T extends Array<ModelField> = Array<ModelField>> = Omit<Partial<Model<T>>, 'slug' | 'identifiers' | '
|
5982
|
+
type PublicModel<T extends Array<ModelField> = Array<ModelField>> = Omit<Partial<Model<T>>, 'slug' | 'identifiers' | 'system' | 'table' | 'tableAlias'> & {
|
5975
5983
|
slug: Required<Model['slug']>;
|
5976
5984
|
identifiers?: Partial<Model['identifiers']>;
|
5977
5985
|
};
|
package/dist/index.js
CHANGED
@@ -465,67 +465,67 @@ var SYSTEM_FIELDS = [
|
|
465
465
|
slug: "ronin.updatedBy"
|
466
466
|
}
|
467
467
|
];
|
468
|
-
var
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
var
|
498
|
-
const
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
468
|
+
var ROOT_MODEL = {
|
469
|
+
slug: "model",
|
470
|
+
identifiers: {
|
471
|
+
name: "name",
|
472
|
+
slug: "slug"
|
473
|
+
},
|
474
|
+
// This name mimics the `sqlite_schema` table in SQLite.
|
475
|
+
table: "ronin_schema",
|
476
|
+
// Indicates that the model was automatically generated by RONIN.
|
477
|
+
system: { model: "root" },
|
478
|
+
fields: [
|
479
|
+
{ slug: "name", type: "string" },
|
480
|
+
{ slug: "pluralName", type: "string" },
|
481
|
+
{ slug: "slug", type: "string" },
|
482
|
+
{ slug: "pluralSlug", type: "string" },
|
483
|
+
{ slug: "idPrefix", type: "string" },
|
484
|
+
{ slug: "table", type: "string" },
|
485
|
+
{ slug: "identifiers", type: "group" },
|
486
|
+
{ slug: "identifiers.name", type: "string" },
|
487
|
+
{ slug: "identifiers.slug", type: "string" },
|
488
|
+
// Providing an empty object as a default value allows us to use `json_insert`
|
489
|
+
// without needing to fall back to an empty object in the insertion statement,
|
490
|
+
// which makes the statement shorter.
|
491
|
+
{ slug: "fields", type: "json", defaultValue: "{}" },
|
492
|
+
{ slug: "indexes", type: "json", defaultValue: "{}" },
|
493
|
+
{ slug: "triggers", type: "json", defaultValue: "{}" },
|
494
|
+
{ slug: "presets", type: "json", defaultValue: "{}" }
|
495
|
+
]
|
496
|
+
};
|
497
|
+
var getSystemModels = (models, model) => {
|
498
|
+
const addedModels = [];
|
499
|
+
for (const field of model.fields || []) {
|
500
|
+
if (field.type === "link" && !field.slug.startsWith("ronin.")) {
|
501
|
+
const relatedModel = getModelBySlug(models, field.target);
|
502
|
+
let fieldSlug = relatedModel.slug;
|
503
|
+
if (field.kind === "many") {
|
504
|
+
fieldSlug = composeAssociationModelSlug(model, field);
|
505
|
+
addedModels.push({
|
506
|
+
pluralSlug: fieldSlug,
|
507
|
+
slug: fieldSlug,
|
508
|
+
system: {
|
509
|
+
model: model.slug,
|
510
|
+
associationSlug: field.slug
|
511
|
+
},
|
512
|
+
fields: [
|
513
|
+
{
|
514
|
+
slug: "source",
|
515
|
+
type: "link",
|
516
|
+
target: model.slug
|
517
|
+
},
|
518
|
+
{
|
519
|
+
slug: "target",
|
520
|
+
type: "link",
|
521
|
+
target: relatedModel.slug
|
522
|
+
}
|
523
|
+
]
|
524
|
+
});
|
524
525
|
}
|
525
526
|
}
|
526
|
-
|
527
|
-
|
528
|
-
return [...SYSTEM_MODELS, ...associativeModels, ...models];
|
527
|
+
}
|
528
|
+
return addedModels;
|
529
529
|
};
|
530
530
|
var addDefaultModelPresets = (list, model) => {
|
531
531
|
const defaultPresets = [];
|
@@ -567,7 +567,7 @@ var addDefaultModelPresets = (list, model) => {
|
|
567
567
|
for (const childMatch of childModels) {
|
568
568
|
const { model: childModel, field: childField } = childMatch;
|
569
569
|
const pluralSlug = childModel.pluralSlug;
|
570
|
-
const presetSlug = childModel.associationSlug || pluralSlug;
|
570
|
+
const presetSlug = childModel.system?.associationSlug || pluralSlug;
|
571
571
|
defaultPresets.push({
|
572
572
|
instructions: {
|
573
573
|
including: {
|
@@ -648,6 +648,14 @@ var formatModelEntity = (type, entities) => {
|
|
648
648
|
});
|
649
649
|
return entries ? Object.fromEntries(entries) : void 0;
|
650
650
|
};
|
651
|
+
var composeSystemModelStatement = (models, dependencyStatements, action, systemModel) => {
|
652
|
+
const { system: _, ...systemModelClean } = systemModel;
|
653
|
+
const query = {
|
654
|
+
[action]: { model: action === "create" ? systemModelClean : systemModelClean.slug }
|
655
|
+
};
|
656
|
+
const statement = compileQueryInput(query, models, []);
|
657
|
+
dependencyStatements.push(...statement.dependencies);
|
658
|
+
};
|
651
659
|
var transformMetaQuery = (models, dependencyStatements, statementParams, query) => {
|
652
660
|
const { queryType } = splitQuery(query);
|
653
661
|
const subAltering = query.alter && !("to" in query.alter);
|
@@ -676,16 +684,16 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
676
684
|
}
|
677
685
|
}
|
678
686
|
if (!(modelSlug && slug)) return query;
|
679
|
-
const tableAction = ["model", "index", "trigger"].includes(entity) ? action.toUpperCase() : "ALTER";
|
680
|
-
const tableName = convertToSnakeCase(pluralize(modelSlug));
|
681
687
|
const model = action === "create" && entity === "model" ? null : getModelBySlug(models, modelSlug);
|
682
|
-
const statement = `${tableAction} TABLE "${tableName}"`;
|
683
688
|
if (entity === "model") {
|
684
689
|
let queryTypeDetails;
|
685
690
|
if (action === "create") {
|
686
691
|
const newModel = jsonValue;
|
687
692
|
const modelWithFields = addDefaultModelFields(newModel, true);
|
688
|
-
const modelWithPresets = addDefaultModelPresets(
|
693
|
+
const modelWithPresets = addDefaultModelPresets(
|
694
|
+
[...models, modelWithFields],
|
695
|
+
modelWithFields
|
696
|
+
);
|
689
697
|
const entities = Object.fromEntries(
|
690
698
|
Object.entries(PLURAL_MODEL_ENTITIES).map(([type, pluralType2]) => {
|
691
699
|
const list = modelWithPresets[pluralType2];
|
@@ -694,7 +702,7 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
694
702
|
);
|
695
703
|
const columns = modelWithPresets.fields.map((field2) => getFieldStatement(models, modelWithPresets, field2)).filter(Boolean);
|
696
704
|
dependencyStatements.push({
|
697
|
-
statement:
|
705
|
+
statement: `CREATE TABLE "${modelWithPresets.table}" (${columns.join(", ")})`,
|
698
706
|
params: []
|
699
707
|
});
|
700
708
|
models.push(modelWithPresets);
|
@@ -703,16 +711,23 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
703
711
|
if (entities[entity2]) finalModel[entity2] = entities[entity2];
|
704
712
|
}
|
705
713
|
queryTypeDetails = { to: finalModel };
|
714
|
+
getSystemModels(models, modelWithPresets).map((systemModel) => {
|
715
|
+
return composeSystemModelStatement(
|
716
|
+
models,
|
717
|
+
dependencyStatements,
|
718
|
+
"create",
|
719
|
+
systemModel
|
720
|
+
);
|
721
|
+
});
|
706
722
|
}
|
707
723
|
if (action === "alter" && model) {
|
708
724
|
const newModel = jsonValue;
|
709
725
|
const modelWithFields = addDefaultModelFields(newModel, false);
|
710
726
|
const modelWithPresets = addDefaultModelPresets(models, modelWithFields);
|
711
|
-
const
|
712
|
-
if (
|
713
|
-
const newTable = convertToSnakeCase(newSlug);
|
727
|
+
const newTableName = modelWithPresets.table;
|
728
|
+
if (newTableName) {
|
714
729
|
dependencyStatements.push({
|
715
|
-
statement:
|
730
|
+
statement: `ALTER TABLE "${model.table}" RENAME TO "${newTableName}"`,
|
716
731
|
params: []
|
717
732
|
});
|
718
733
|
}
|
@@ -726,8 +741,16 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
726
741
|
}
|
727
742
|
if (action === "drop" && model) {
|
728
743
|
models.splice(models.indexOf(model), 1);
|
729
|
-
dependencyStatements.push({ statement
|
744
|
+
dependencyStatements.push({ statement: `DROP TABLE "${model.table}"`, params: [] });
|
730
745
|
queryTypeDetails = { with: { slug } };
|
746
|
+
models.filter(({ system }) => system?.model === model.slug).map((systemModel) => {
|
747
|
+
return composeSystemModelStatement(
|
748
|
+
models,
|
749
|
+
dependencyStatements,
|
750
|
+
"drop",
|
751
|
+
systemModel
|
752
|
+
);
|
753
|
+
});
|
731
754
|
}
|
732
755
|
const queryTypeAction = action === "create" ? "add" : action === "alter" ? "set" : "remove";
|
733
756
|
return {
|
@@ -737,7 +760,19 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
737
760
|
};
|
738
761
|
}
|
739
762
|
const existingModel = model;
|
763
|
+
const pluralType = PLURAL_MODEL_ENTITIES[entity];
|
764
|
+
const targetEntityIndex = existingModel[pluralType]?.findIndex(
|
765
|
+
(entity2) => entity2.slug === slug
|
766
|
+
);
|
767
|
+
if ((action === "alter" || action === "drop") && (typeof targetEntityIndex === "undefined" || targetEntityIndex === -1)) {
|
768
|
+
throw new RoninError({
|
769
|
+
message: `No ${entity} with slug "${slug}" defined in model "${existingModel.name}".`,
|
770
|
+
code: MODEL_ENTITY_ERROR_CODES[entity]
|
771
|
+
});
|
772
|
+
}
|
773
|
+
const existingEntity = existingModel[pluralType]?.[targetEntityIndex];
|
740
774
|
if (entity === "field") {
|
775
|
+
const statement = `ALTER TABLE "${existingModel.table}"`;
|
741
776
|
if (action === "create") {
|
742
777
|
const field2 = jsonValue;
|
743
778
|
field2.type = field2.type || "string";
|
@@ -757,17 +792,21 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
757
792
|
});
|
758
793
|
}
|
759
794
|
} else if (action === "drop") {
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
795
|
+
const existingField = existingEntity;
|
796
|
+
if (!(existingField.type === "link" && existingField.kind === "many")) {
|
797
|
+
dependencyStatements.push({
|
798
|
+
statement: `${statement} DROP COLUMN "${slug}"`,
|
799
|
+
params: []
|
800
|
+
});
|
801
|
+
}
|
764
802
|
}
|
765
803
|
}
|
804
|
+
const statementAction = action.toUpperCase();
|
766
805
|
if (entity === "index") {
|
767
806
|
const index = jsonValue;
|
768
807
|
const indexName = convertToSnakeCase(slug);
|
769
808
|
const params = [];
|
770
|
-
let
|
809
|
+
let statement = `${statementAction}${index?.unique ? " UNIQUE" : ""} INDEX "${indexName}"`;
|
771
810
|
if (action === "create") {
|
772
811
|
const columns = index.fields.map((field2) => {
|
773
812
|
let fieldSelector = "";
|
@@ -780,18 +819,18 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
780
819
|
if (field2.order) fieldSelector += ` ${field2.order}`;
|
781
820
|
return fieldSelector;
|
782
821
|
});
|
783
|
-
|
822
|
+
statement += ` ON "${existingModel.table}" (${columns.join(", ")})`;
|
784
823
|
if (index.filter) {
|
785
824
|
const withStatement = handleWith(models, existingModel, params, index.filter);
|
786
|
-
|
825
|
+
statement += ` WHERE (${withStatement})`;
|
787
826
|
}
|
788
827
|
}
|
789
|
-
dependencyStatements.push({ statement
|
828
|
+
dependencyStatements.push({ statement, params });
|
790
829
|
}
|
791
830
|
if (entity === "trigger") {
|
792
831
|
const triggerName = convertToSnakeCase(slug);
|
793
832
|
const params = [];
|
794
|
-
let
|
833
|
+
let statement = `${statementAction} TRIGGER "${triggerName}"`;
|
795
834
|
if (action === "create") {
|
796
835
|
const trigger = jsonValue;
|
797
836
|
const statementParts = [`${trigger.when} ${trigger.action}`];
|
@@ -808,7 +847,7 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
808
847
|
});
|
809
848
|
statementParts.push(`OF (${fieldSelectors.join(", ")})`);
|
810
849
|
}
|
811
|
-
statementParts.push("ON", `"${
|
850
|
+
statementParts.push("ON", `"${existingModel.table}"`);
|
812
851
|
if (trigger.filter || trigger.effects.some((query2) => findInObject(query2, RONIN_MODEL_SYMBOLS.FIELD))) {
|
813
852
|
statementParts.push("FOR EACH ROW");
|
814
853
|
}
|
@@ -831,21 +870,11 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
831
870
|
if (effectStatements.length > 1) statementParts.push("BEGIN");
|
832
871
|
statementParts.push(effectStatements.join("; "));
|
833
872
|
if (effectStatements.length > 1) statementParts.push("END");
|
834
|
-
|
873
|
+
statement += ` ${statementParts.join(" ")}`;
|
835
874
|
}
|
836
|
-
dependencyStatements.push({ statement
|
875
|
+
dependencyStatements.push({ statement, params });
|
837
876
|
}
|
838
|
-
const pluralType = PLURAL_MODEL_ENTITIES[entity];
|
839
877
|
const field = `${RONIN_MODEL_SYMBOLS.FIELD}${pluralType}`;
|
840
|
-
const targetEntityIndex = existingModel[pluralType]?.findIndex(
|
841
|
-
(entity2) => entity2.slug === slug
|
842
|
-
);
|
843
|
-
if ((action === "alter" || action === "drop") && (typeof targetEntityIndex === "undefined" || targetEntityIndex === -1)) {
|
844
|
-
throw new RoninError({
|
845
|
-
message: `No ${entity} with slug "${slug}" defined in model "${existingModel.name}".`,
|
846
|
-
code: MODEL_ENTITY_ERROR_CODES[entity]
|
847
|
-
});
|
848
|
-
}
|
849
878
|
let json;
|
850
879
|
switch (action) {
|
851
880
|
case "create": {
|
@@ -867,9 +896,23 @@ var transformMetaQuery = (models, dependencyStatements, statementParams, query)
|
|
867
896
|
case "drop": {
|
868
897
|
json = `json_remove(${field}, '$.${slug}')`;
|
869
898
|
const targetEntity = existingModel[pluralType];
|
870
|
-
|
899
|
+
targetEntity.splice(targetEntityIndex, 1);
|
871
900
|
}
|
872
901
|
}
|
902
|
+
const currentSystemModels = models.filter(({ system }) => {
|
903
|
+
return system?.model === existingModel.slug;
|
904
|
+
});
|
905
|
+
const newSystemModels = getSystemModels(models, existingModel);
|
906
|
+
for (const systemModel of currentSystemModels) {
|
907
|
+
const exists = newSystemModels.find((model2) => model2.slug === systemModel.slug);
|
908
|
+
if (exists) continue;
|
909
|
+
composeSystemModelStatement(models, dependencyStatements, "drop", systemModel);
|
910
|
+
}
|
911
|
+
for (const systemModel of newSystemModels) {
|
912
|
+
const exists = currentSystemModels.find((model2) => model2.slug === systemModel.slug);
|
913
|
+
if (exists) continue;
|
914
|
+
composeSystemModelStatement(models, dependencyStatements, "create", systemModel);
|
915
|
+
}
|
873
916
|
return {
|
874
917
|
set: {
|
875
918
|
model: {
|
@@ -1240,13 +1283,19 @@ var handleTo = (models, model, statementParams, queryType, dependencyStatements,
|
|
1240
1283
|
};
|
1241
1284
|
|
1242
1285
|
// src/utils/index.ts
|
1243
|
-
var compileQueryInput = (
|
1286
|
+
var compileQueryInput = (defaultQuery, models, statementParams, options) => {
|
1287
|
+
const dependencyStatements = [];
|
1288
|
+
const query = transformMetaQuery(
|
1289
|
+
models,
|
1290
|
+
dependencyStatements,
|
1291
|
+
statementParams,
|
1292
|
+
defaultQuery
|
1293
|
+
);
|
1244
1294
|
const parsedQuery = splitQuery(query);
|
1245
1295
|
const { queryType, queryModel, queryInstructions } = parsedQuery;
|
1246
1296
|
const model = getModelBySlug(models, queryModel);
|
1247
1297
|
const single = queryModel !== model.pluralSlug;
|
1248
1298
|
let instructions = formatIdentifiers(model, queryInstructions);
|
1249
|
-
const dependencyStatements = [];
|
1250
1299
|
const returning = options?.returning ?? true;
|
1251
1300
|
if (instructions && Object.hasOwn(instructions, "for")) {
|
1252
1301
|
instructions = handleFor(model, instructions);
|
@@ -1398,7 +1447,11 @@ var Transaction = class {
|
|
1398
1447
|
* @returns The composed SQL statements.
|
1399
1448
|
*/
|
1400
1449
|
compileQueries = (queries, models, options) => {
|
1401
|
-
const modelList =
|
1450
|
+
const modelList = [
|
1451
|
+
ROOT_MODEL,
|
1452
|
+
...models.flatMap((model) => getSystemModels(models, model)),
|
1453
|
+
...models
|
1454
|
+
].map((model) => {
|
1402
1455
|
return addDefaultModelFields(model, true);
|
1403
1456
|
});
|
1404
1457
|
const modelListWithPresets = modelList.map((model) => {
|
@@ -1407,17 +1460,10 @@ var Transaction = class {
|
|
1407
1460
|
const dependencyStatements = [];
|
1408
1461
|
const mainStatements = [];
|
1409
1462
|
for (const query of queries) {
|
1410
|
-
const statementValues = options?.inlineParams ? null : [];
|
1411
|
-
const transformedQuery = transformMetaQuery(
|
1412
|
-
modelListWithPresets,
|
1413
|
-
dependencyStatements,
|
1414
|
-
statementValues,
|
1415
|
-
query
|
1416
|
-
);
|
1417
1463
|
const result = compileQueryInput(
|
1418
|
-
|
1464
|
+
query,
|
1419
1465
|
modelListWithPresets,
|
1420
|
-
|
1466
|
+
options?.inlineParams ? null : []
|
1421
1467
|
);
|
1422
1468
|
dependencyStatements.push(...result.dependencies);
|
1423
1469
|
mainStatements.push(result.main);
|