@ronin/compiler 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +17 -2
- package/dist/index.d.ts +10 -7
- package/dist/index.js +76 -33
- package/package.json +1 -1
package/README.md
CHANGED
@@ -39,7 +39,7 @@ You will just need to make sure that, once you [create a pull request](https://d
|
|
39
39
|
The programmatic API of the RONIN compiler looks like this:
|
40
40
|
|
41
41
|
```typescript
|
42
|
-
import {
|
42
|
+
import { compileQuery } from '@ronin/compiler';
|
43
43
|
|
44
44
|
const query = {
|
45
45
|
get: {
|
@@ -53,12 +53,27 @@ const schemas = [
|
|
53
53
|
},
|
54
54
|
];
|
55
55
|
|
56
|
-
const { writeStatements, readStatement } =
|
56
|
+
const { writeStatements, readStatement } = compileQuery(query, schemas);
|
57
57
|
|
58
58
|
console.log(readStatement);
|
59
59
|
// SELECT * FROM "accounts" ORDER BY "ronin.createdAt" DESC LIMIT 101
|
60
60
|
```
|
61
61
|
|
62
|
+
#### Options
|
63
|
+
|
64
|
+
To fine-tune the behavior of the compiler, you can pass the following options:
|
65
|
+
|
66
|
+
```typescript
|
67
|
+
compileQuery(query, schemas, {
|
68
|
+
// Instead of returning an array of values for every statement (which allows for
|
69
|
+
// preventing SQL injections), all values are inlined directly into the SQL strings.
|
70
|
+
// This option should only be used if the generated SQL will be manually verified.
|
71
|
+
inlineValues: true
|
72
|
+
});
|
73
|
+
```
|
74
|
+
|
75
|
+
#### Transpilation
|
76
|
+
|
62
77
|
In order to be compatible with a wide range of projects, the source code of the `compiler` repo needs to be compiled (transpiled) whenever you make changes to it. To automate this, you can keep this command running in your terminal:
|
63
78
|
|
64
79
|
```bash
|
package/dist/index.d.ts
CHANGED
@@ -18940,9 +18940,9 @@ interface Schema {
|
|
18940
18940
|
pluralName?: string;
|
18941
18941
|
slug: string;
|
18942
18942
|
pluralSlug?: string;
|
18943
|
-
identifiers
|
18944
|
-
|
18945
|
-
slug
|
18943
|
+
identifiers: {
|
18944
|
+
name: string;
|
18945
|
+
slug: string;
|
18946
18946
|
};
|
18947
18947
|
idPrefix?: string;
|
18948
18948
|
including?: Record<string, Query>;
|
@@ -18951,6 +18951,10 @@ interface Schema {
|
|
18951
18951
|
indexes?: Array<SchemaIndex>;
|
18952
18952
|
triggers?: Array<SchemaTrigger>;
|
18953
18953
|
}
|
18954
|
+
type PublicSchema = Omit<Partial<Schema>, 'slug' | 'identifiers'> & {
|
18955
|
+
slug: Required<Schema['slug']>;
|
18956
|
+
identifiers?: Partial<Schema['identifiers']>;
|
18957
|
+
};
|
18954
18958
|
|
18955
18959
|
/**
|
18956
18960
|
* Composes an SQL statement for a provided RONIN query.
|
@@ -18961,13 +18965,12 @@ interface Schema {
|
|
18961
18965
|
*
|
18962
18966
|
* @returns The composed SQL statement.
|
18963
18967
|
*/
|
18964
|
-
declare const
|
18965
|
-
|
18966
|
-
disableReturning?: boolean;
|
18968
|
+
declare const compileQuery: (query: Query, schemas: Array<PublicSchema>, options?: {
|
18969
|
+
inlineValues?: boolean;
|
18967
18970
|
}) => {
|
18968
18971
|
writeStatements: Array<string>;
|
18969
18972
|
readStatement: string;
|
18970
18973
|
values: Array<unknown>;
|
18971
18974
|
};
|
18972
18975
|
|
18973
|
-
export { type CombinedInstructions, type CountInstructions, type CountQuery, type CreateInstructions, type CreateQuery, type DropInstructions, type DropQuery, type GetInstructions, type GetQuery, type IncludingInstruction, type Instructions, type OrderedByInstrucion, type Query, type QueryInstructionType, type QueryPaginationOptions, type QuerySchemaType, type QueryType, type Schema, type SchemaField, type
|
18976
|
+
export { type CombinedInstructions, type CountInstructions, type CountQuery, type CreateInstructions, type CreateQuery, type DropInstructions, type DropQuery, type GetInstructions, type GetQuery, type IncludingInstruction, type Instructions, type OrderedByInstrucion, type Query, type QueryInstructionType, type QueryPaginationOptions, type QuerySchemaType, type QueryType, type PublicSchema as Schema, type SchemaField, type SchemaIndex, type SchemaTrigger, type SetInstructions, type SetQuery, type WithInstruction, compileQuery };
|
package/dist/index.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
// src/utils/
|
1
|
+
// src/utils/helpers.ts
|
2
2
|
import { init as cuid } from "@paralleldrive/cuid2";
|
3
3
|
var RONIN_SCHEMA_SYMBOLS = {
|
4
4
|
// Represents a sub query.
|
@@ -33,7 +33,7 @@ var DOUBLE_QUOTE_REGEX = /"/g;
|
|
33
33
|
var AMPERSAND_REGEX = /\s*&+\s*/g;
|
34
34
|
var SPECIAL_CHARACTERS_REGEX = /[^\w\s-]+/g;
|
35
35
|
var SPLIT_REGEX = /(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|[\s.\-_]+/;
|
36
|
-
var generateRecordId = (prefix) => `${prefix
|
36
|
+
var generateRecordId = (prefix) => `${prefix}_${cuid({ length: 16 })()}`;
|
37
37
|
var capitalize = (str) => {
|
38
38
|
if (!str || str.length === 0) return "";
|
39
39
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
@@ -96,8 +96,9 @@ var splitQuery = (query) => {
|
|
96
96
|
};
|
97
97
|
|
98
98
|
// src/utils/statement.ts
|
99
|
-
var prepareStatementValue = (statementValues, value
|
100
|
-
if (
|
99
|
+
var prepareStatementValue = (statementValues, value) => {
|
100
|
+
if (value === null) return "NULL";
|
101
|
+
if (!statementValues) return JSON.stringify(value);
|
101
102
|
let formattedValue = value;
|
102
103
|
if (Array.isArray(value) || isObject(value)) {
|
103
104
|
formattedValue = JSON.stringify(value);
|
@@ -122,7 +123,7 @@ var composeFieldValues = (schemas, schema, statementValues, instructionName, val
|
|
122
123
|
conditionValue = `(${compileQueryInput(
|
123
124
|
value[RONIN_SCHEMA_SYMBOLS.QUERY],
|
124
125
|
schemas,
|
125
|
-
|
126
|
+
statementValues
|
126
127
|
).readStatement})`;
|
127
128
|
} else if (typeof value === "string" && value.startsWith(RONIN_SCHEMA_SYMBOLS.FIELD)) {
|
128
129
|
let targetTable = `"${options.rootTable}"`;
|
@@ -139,11 +140,11 @@ var composeFieldValues = (schemas, schema, statementValues, instructionName, val
|
|
139
140
|
} else if (schemaField.type === "json" && instructionName === "to") {
|
140
141
|
conditionSelector = `"${schemaField.slug}"`;
|
141
142
|
if (collectStatementValue) {
|
142
|
-
const preparedValue = prepareStatementValue(statementValues, value
|
143
|
+
const preparedValue = prepareStatementValue(statementValues, value);
|
143
144
|
conditionValue = `IIF(${conditionSelector} IS NULL, ${preparedValue}, json_patch(${conditionSelector}, ${preparedValue}))`;
|
144
145
|
}
|
145
146
|
} else if (collectStatementValue) {
|
146
|
-
conditionValue = prepareStatementValue(statementValues, value
|
147
|
+
conditionValue = prepareStatementValue(statementValues, value);
|
147
148
|
}
|
148
149
|
if (options.type === "fields") return conditionSelector;
|
149
150
|
if (options.type === "values") return conditionValue;
|
@@ -250,10 +251,10 @@ var formatIdentifiers = ({ identifiers }, queryInstructions) => {
|
|
250
251
|
return queryInstructions;
|
251
252
|
const newNestedInstructions = { ...nestedInstructions };
|
252
253
|
for (const oldKey of Object.keys(newNestedInstructions)) {
|
253
|
-
if (oldKey !== "
|
254
|
-
const identifierName = oldKey === "
|
254
|
+
if (oldKey !== "nameIdentifier" && oldKey !== "slugIdentifier") continue;
|
255
|
+
const identifierName = oldKey === "nameIdentifier" ? "name" : "slug";
|
255
256
|
const value = newNestedInstructions[oldKey];
|
256
|
-
const newKey = identifiers
|
257
|
+
const newKey = identifiers[identifierName];
|
257
258
|
newNestedInstructions[newKey] = value;
|
258
259
|
delete newNestedInstructions[oldKey];
|
259
260
|
}
|
@@ -395,6 +396,10 @@ var SYSTEM_SCHEMAS = [
|
|
395
396
|
pluralName: "Schemas",
|
396
397
|
slug: "schema",
|
397
398
|
pluralSlug: "schemas",
|
399
|
+
identifiers: {
|
400
|
+
name: "name",
|
401
|
+
slug: "slug"
|
402
|
+
},
|
398
403
|
fields: [
|
399
404
|
...SYSTEM_FIELDS,
|
400
405
|
{ slug: "name", type: "string" },
|
@@ -403,7 +408,7 @@ var SYSTEM_SCHEMAS = [
|
|
403
408
|
{ slug: "pluralSlug", type: "string" },
|
404
409
|
{ slug: "idPrefix", type: "string" },
|
405
410
|
{ slug: "identifiers", type: "group" },
|
406
|
-
{ slug: "identifiers.
|
411
|
+
{ slug: "identifiers.name", type: "string" },
|
407
412
|
{ slug: "identifiers.slug", type: "string" },
|
408
413
|
{ slug: "fields", type: "json" },
|
409
414
|
{ slug: "indexes", type: "json" },
|
@@ -415,6 +420,10 @@ var SYSTEM_SCHEMAS = [
|
|
415
420
|
pluralName: "Fields",
|
416
421
|
slug: "field",
|
417
422
|
pluralSlug: "fields",
|
423
|
+
identifiers: {
|
424
|
+
name: "name",
|
425
|
+
slug: "slug"
|
426
|
+
},
|
418
427
|
fields: [
|
419
428
|
...SYSTEM_FIELDS,
|
420
429
|
{ slug: "name", type: "string" },
|
@@ -443,6 +452,10 @@ var SYSTEM_SCHEMAS = [
|
|
443
452
|
pluralName: "Indexes",
|
444
453
|
slug: "index",
|
445
454
|
pluralSlug: "indexes",
|
455
|
+
identifiers: {
|
456
|
+
name: "slug",
|
457
|
+
slug: "slug"
|
458
|
+
},
|
446
459
|
fields: [
|
447
460
|
...SYSTEM_FIELDS,
|
448
461
|
{ slug: "slug", type: "string", required: true },
|
@@ -461,6 +474,10 @@ var SYSTEM_SCHEMAS = [
|
|
461
474
|
pluralName: "Triggers",
|
462
475
|
slug: "trigger",
|
463
476
|
pluralSlug: "triggers",
|
477
|
+
identifiers: {
|
478
|
+
name: "slug",
|
479
|
+
slug: "slug"
|
480
|
+
},
|
464
481
|
fields: [
|
465
482
|
...SYSTEM_FIELDS,
|
466
483
|
{ slug: "slug", type: "string", required: true },
|
@@ -481,6 +498,10 @@ var prepareSchema = (schema) => {
|
|
481
498
|
if (!copiedSchema.name) copiedSchema.name = slugToName(copiedSchema.slug);
|
482
499
|
if (!copiedSchema.pluralName)
|
483
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";
|
484
505
|
return copiedSchema;
|
485
506
|
};
|
486
507
|
var addSystemSchemas = (schemas) => {
|
@@ -496,6 +517,10 @@ var addSystemSchemas = (schemas) => {
|
|
496
517
|
list.push({
|
497
518
|
pluralSlug: fieldSlug,
|
498
519
|
slug: fieldSlug,
|
520
|
+
identifiers: {
|
521
|
+
name: "id",
|
522
|
+
slug: "id"
|
523
|
+
},
|
499
524
|
fields: [
|
500
525
|
{
|
501
526
|
slug: "source",
|
@@ -577,9 +602,14 @@ var getFieldStatement = (field) => {
|
|
577
602
|
return statement;
|
578
603
|
};
|
579
604
|
var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements) => {
|
580
|
-
const {
|
581
|
-
|
582
|
-
|
605
|
+
const {
|
606
|
+
queryType,
|
607
|
+
querySchema,
|
608
|
+
queryInstructions: queryInstructionsRaw
|
609
|
+
} = queryDetails;
|
610
|
+
const queryInstructions = queryInstructionsRaw;
|
611
|
+
if (!["create", "set", "drop"].includes(queryType)) return queryInstructions;
|
612
|
+
if (!SYSTEM_SCHEMA_SLUGS.includes(querySchema)) return queryInstructions;
|
583
613
|
const instructionName = mappedInstructions[queryType];
|
584
614
|
const instructionList = queryInstructions[instructionName];
|
585
615
|
const kind = getSchemaBySlug(SYSTEM_SCHEMAS, querySchema).pluralSlug;
|
@@ -643,7 +673,7 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
|
|
643
673
|
}
|
644
674
|
}
|
645
675
|
writeStatements.push(statement2);
|
646
|
-
return;
|
676
|
+
return queryInstructions;
|
647
677
|
}
|
648
678
|
if (kind === "triggers") {
|
649
679
|
const triggerName = convertToSnakeCase(slug);
|
@@ -669,8 +699,7 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
|
|
669
699
|
statementParts.push("WHEN", `(${withStatement})`);
|
670
700
|
}
|
671
701
|
const effectStatements = effectQueries.map((effectQuery) => {
|
672
|
-
return compileQueryInput(effectQuery, schemas, {
|
673
|
-
statementValues,
|
702
|
+
return compileQueryInput(effectQuery, schemas, statementValues, {
|
674
703
|
disableReturning: true
|
675
704
|
}).readStatement;
|
676
705
|
});
|
@@ -680,23 +709,27 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
|
|
680
709
|
statement2 += ` ${statementParts.join(" ")}`;
|
681
710
|
}
|
682
711
|
writeStatements.push(statement2);
|
683
|
-
return;
|
712
|
+
return queryInstructions;
|
684
713
|
}
|
685
714
|
let statement = `${tableAction} TABLE "${tableName}"`;
|
686
715
|
if (kind === "schemas") {
|
687
|
-
const
|
716
|
+
const providedFields = instructionList?.fields || [];
|
717
|
+
const fields = [...SYSTEM_FIELDS, ...providedFields];
|
718
|
+
if (queryType === "create" || queryType === "set") {
|
719
|
+
queryInstructions.to = prepareSchema(queryInstructions.to);
|
720
|
+
}
|
688
721
|
if (queryType === "create") {
|
689
722
|
const columns = fields.map(getFieldStatement).filter(Boolean);
|
690
723
|
statement += ` (${columns.join(", ")})`;
|
691
724
|
} else if (queryType === "set") {
|
692
|
-
const newSlug = queryInstructions.to?.
|
725
|
+
const newSlug = queryInstructions.to?.pluralSlug;
|
693
726
|
if (newSlug) {
|
694
|
-
const newTable = convertToSnakeCase(
|
727
|
+
const newTable = convertToSnakeCase(newSlug);
|
695
728
|
statement += ` RENAME TO "${newTable}"`;
|
696
729
|
}
|
697
730
|
}
|
698
731
|
writeStatements.push(statement);
|
699
|
-
return;
|
732
|
+
return queryInstructions;
|
700
733
|
}
|
701
734
|
if (kind === "fields") {
|
702
735
|
if (queryType === "create") {
|
@@ -718,6 +751,7 @@ var addSchemaQueries = (schemas, statementValues, queryDetails, writeStatements)
|
|
718
751
|
}
|
719
752
|
writeStatements.push(statement);
|
720
753
|
}
|
754
|
+
return queryInstructions;
|
721
755
|
};
|
722
756
|
var slugToName = (slug) => {
|
723
757
|
const name = slug.replace(/([a-z])([A-Z])/g, "$1 $2");
|
@@ -882,7 +916,7 @@ var handleIncluding = (schemas, statementValues, schema, instruction, rootTable)
|
|
882
916
|
}
|
883
917
|
},
|
884
918
|
schemas,
|
885
|
-
|
919
|
+
statementValues
|
886
920
|
);
|
887
921
|
relatedTableSelector = `(${subSelect.readStatement})`;
|
888
922
|
}
|
@@ -1009,9 +1043,7 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
|
|
1009
1043
|
...subQueryInstructions.including
|
1010
1044
|
};
|
1011
1045
|
}
|
1012
|
-
return compileQueryInput(subQuery, schemas,
|
1013
|
-
statementValues
|
1014
|
-
}).readStatement;
|
1046
|
+
return compileQueryInput(subQuery, schemas, statementValues).readStatement;
|
1015
1047
|
}
|
1016
1048
|
Object.assign(toInstruction, defaultFields);
|
1017
1049
|
for (const fieldSlug in toInstruction) {
|
@@ -1034,7 +1066,8 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
|
|
1034
1066
|
}
|
1035
1067
|
},
|
1036
1068
|
schemas,
|
1037
|
-
|
1069
|
+
statementValues,
|
1070
|
+
{ disableReturning: true }
|
1038
1071
|
);
|
1039
1072
|
return readStatement;
|
1040
1073
|
};
|
@@ -1083,8 +1116,8 @@ var handleTo = (schemas, schema, statementValues, queryType, writeStatements, in
|
|
1083
1116
|
return statement;
|
1084
1117
|
};
|
1085
1118
|
|
1086
|
-
// src/index.ts
|
1087
|
-
var compileQueryInput = (query, defaultSchemas, options) => {
|
1119
|
+
// src/utils/index.ts
|
1120
|
+
var compileQueryInput = (query, defaultSchemas, statementValues, options) => {
|
1088
1121
|
const parsedQuery = splitQuery(query);
|
1089
1122
|
const { queryType, querySchema, queryInstructions } = parsedQuery;
|
1090
1123
|
const schemas = addSystemSchemas(defaultSchemas);
|
@@ -1092,9 +1125,13 @@ var compileQueryInput = (query, defaultSchemas, options) => {
|
|
1092
1125
|
const single = querySchema !== schema.pluralSlug;
|
1093
1126
|
let instructions = formatIdentifiers(schema, queryInstructions);
|
1094
1127
|
let table = getTableForSchema(schema);
|
1095
|
-
const statementValues = options?.statementValues || [];
|
1096
1128
|
const writeStatements = [];
|
1097
|
-
addSchemaQueries(
|
1129
|
+
instructions = addSchemaQueries(
|
1130
|
+
schemas,
|
1131
|
+
statementValues,
|
1132
|
+
{ queryType, querySchema, queryInstructions: instructions },
|
1133
|
+
writeStatements
|
1134
|
+
);
|
1098
1135
|
const columns = handleSelecting(schema, statementValues, {
|
1099
1136
|
selecting: instructions?.selecting,
|
1100
1137
|
including: instructions?.including
|
@@ -1234,9 +1271,15 @@ var compileQueryInput = (query, defaultSchemas, options) => {
|
|
1234
1271
|
return {
|
1235
1272
|
writeStatements,
|
1236
1273
|
readStatement: finalStatement,
|
1237
|
-
values: statementValues
|
1274
|
+
values: statementValues || []
|
1238
1275
|
};
|
1239
1276
|
};
|
1277
|
+
|
1278
|
+
// src/index.ts
|
1279
|
+
var compileQuery = (query, schemas, options) => {
|
1280
|
+
const statementValues = options?.inlineValues ? null : [];
|
1281
|
+
return compileQueryInput(query, schemas, statementValues);
|
1282
|
+
};
|
1240
1283
|
export {
|
1241
|
-
|
1284
|
+
compileQuery
|
1242
1285
|
};
|