@ronin/compiler
Advanced tools
Comparing version 0.8.3 to 0.8.4
@@ -321,2 +321,147 @@ // src/utils/helpers.ts | ||
// src/utils/meta.ts | ||
var PLURAL_MODEL_ENTITIES = { | ||
field: "fields", | ||
index: "indexes", | ||
trigger: "triggers", | ||
preset: "presets" | ||
}; | ||
var transformMetaQuery = (models, dependencyStatements, statementParams, query) => { | ||
if (query.create) { | ||
const init = query.create.model; | ||
const details = "to" in query.create ? { slug: init, ...query.create.to } : init; | ||
const modelWithFields = addDefaultModelFields(details, true); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const instructions = { | ||
to: modelWithPresets | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "add", | ||
queryModel: "model", | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
add: { | ||
model: instructions | ||
} | ||
}; | ||
} | ||
if (query.drop) { | ||
const slug = query.drop.model; | ||
const instructions = { | ||
with: { slug } | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "remove", | ||
queryModel: "model", | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
remove: { | ||
model: instructions | ||
} | ||
}; | ||
} | ||
if (query.alter) { | ||
const slug = query.alter.model; | ||
if ("to" in query.alter) { | ||
const modelWithFields = addDefaultModelFields(query.alter.to, false); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const instructions = { | ||
with: { slug }, | ||
to: modelWithPresets | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "set", | ||
queryModel: "model", | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
set: { | ||
model: instructions | ||
} | ||
}; | ||
} | ||
if ("create" in query.alter) { | ||
const type2 = Object.keys(query.alter.create)[0]; | ||
const pluralType2 = PLURAL_MODEL_ENTITIES[type2]; | ||
const item = query.alter.create[type2]; | ||
const completeItem = { slug: item.slug || `${type2}Slug`, ...item }; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "add", | ||
queryModel: type2, | ||
queryInstructions: { | ||
to: { | ||
model: { slug }, | ||
...completeItem | ||
} | ||
} | ||
}); | ||
const value = prepareStatementValue(statementParams, completeItem); | ||
const json2 = `json_insert(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType2}, '$.${completeItem.slug}', ${value})`; | ||
const expression2 = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json2 }; | ||
return { | ||
set: { | ||
model: { | ||
with: { slug }, | ||
to: { | ||
[pluralType2]: expression2 | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
if ("alter" in query.alter) { | ||
const type2 = Object.keys(query.alter.alter)[0]; | ||
const pluralType2 = PLURAL_MODEL_ENTITIES[type2]; | ||
const itemSlug2 = query.alter.alter[type2]; | ||
const newItem = query.alter.alter.to; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "set", | ||
queryModel: type2, | ||
queryInstructions: { | ||
with: { model: { slug }, slug: itemSlug2 }, | ||
to: newItem | ||
} | ||
}); | ||
const value = prepareStatementValue(statementParams, newItem); | ||
const json2 = `json_patch(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType2}, '$.${itemSlug2}', ${value})`; | ||
const expression2 = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json2 }; | ||
return { | ||
set: { | ||
model: { | ||
with: { slug }, | ||
to: { | ||
[pluralType2]: expression2 | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
const type = Object.keys(query.alter.drop)[0]; | ||
const pluralType = PLURAL_MODEL_ENTITIES[type]; | ||
const itemSlug = query.alter.drop[type]; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "remove", | ||
queryModel: type, | ||
queryInstructions: { | ||
with: { model: { slug }, slug: itemSlug } | ||
} | ||
}); | ||
const json = `json_insert(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType}, '$.${itemSlug}')`; | ||
const expression = { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json }; | ||
return { | ||
set: { | ||
model: { | ||
with: { slug }, | ||
to: { | ||
[pluralType]: expression | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
return query; | ||
}; | ||
// src/utils/model.ts | ||
@@ -469,2 +614,4 @@ import title from "title"; | ||
}, | ||
// This name mimics the `sqlite_schema` table in SQLite. | ||
table: "ronin_schema", | ||
fields: [ | ||
@@ -480,94 +627,12 @@ { slug: "name", type: "string" }, | ||
{ slug: "identifiers.slug", type: "string" }, | ||
{ slug: "fields", type: "json" }, | ||
{ slug: "indexes", type: "json" }, | ||
{ slug: "triggers", type: "json" }, | ||
{ slug: "presets", type: "json" } | ||
// Providing an empty object as a default value allows us to use `json_insert` | ||
// without needing to fall back to an empty object in the insertion statement, | ||
// which makes the statement shorter. | ||
{ slug: "fields", type: "json", defaultValue: "{}" }, | ||
{ slug: "indexes", type: "json", defaultValue: "{}" }, | ||
{ slug: "triggers", type: "json", defaultValue: "{}" }, | ||
{ slug: "presets", type: "json", defaultValue: "{}" } | ||
] | ||
}, | ||
{ | ||
slug: "field", | ||
identifiers: { | ||
name: "name", | ||
slug: "slug" | ||
}, | ||
fields: [ | ||
{ slug: "name", type: "string" }, | ||
{ slug: "slug", type: "string", required: true }, | ||
{ slug: "type", type: "string", required: true }, | ||
{ | ||
slug: "model", | ||
type: "link", | ||
target: "model", | ||
required: true | ||
}, | ||
{ slug: "required", type: "boolean" }, | ||
{ slug: "defaultValue", type: "string" }, | ||
{ slug: "unique", type: "boolean" }, | ||
{ slug: "autoIncrement", type: "boolean" }, | ||
// Only allowed for fields of type "link". | ||
{ slug: "target", type: "string" }, | ||
{ slug: "kind", type: "string" }, | ||
{ slug: "actions", type: "group" }, | ||
{ slug: "actions.onDelete", type: "string" }, | ||
{ slug: "actions.onUpdate", type: "string" } | ||
] | ||
}, | ||
{ | ||
slug: "index", | ||
identifiers: { | ||
name: "slug", | ||
slug: "slug" | ||
}, | ||
fields: [ | ||
{ slug: "slug", type: "string", required: true }, | ||
{ | ||
slug: "model", | ||
type: "link", | ||
target: "model", | ||
required: true | ||
}, | ||
{ slug: "unique", type: "boolean" }, | ||
{ slug: "filter", type: "json" }, | ||
{ slug: "fields", type: "json", required: true } | ||
] | ||
}, | ||
{ | ||
slug: "trigger", | ||
identifiers: { | ||
name: "slug", | ||
slug: "slug" | ||
}, | ||
fields: [ | ||
{ slug: "slug", type: "string", required: true }, | ||
{ | ||
slug: "model", | ||
type: "link", | ||
target: "model", | ||
required: true | ||
}, | ||
{ slug: "when", type: "string", required: true }, | ||
{ slug: "action", type: "string", required: true }, | ||
{ slug: "filter", type: "json" }, | ||
{ slug: "effects", type: "json", required: true }, | ||
{ slug: "fields", type: "json" } | ||
] | ||
}, | ||
{ | ||
slug: "preset", | ||
fields: [ | ||
{ slug: "slug", type: "string", required: true }, | ||
{ | ||
slug: "model", | ||
type: "link", | ||
target: "model", | ||
required: true | ||
}, | ||
{ slug: "instructions", type: "json", required: true } | ||
] | ||
} | ||
].map((model) => addDefaultModelFields(model, true)); | ||
var SYSTEM_MODEL_SLUGS = SYSTEM_MODELS.flatMap(({ slug, pluralSlug }) => [ | ||
slug, | ||
pluralSlug | ||
]); | ||
]; | ||
var addSystemModels = (models) => { | ||
@@ -721,6 +786,5 @@ const associativeModels = models.flatMap((model) => { | ||
if (!["add", "set", "remove"].includes(queryType)) return; | ||
if (!SYSTEM_MODEL_SLUGS.includes(queryModel)) return; | ||
if (!["model", "field", "index", "trigger", "preset"].includes(queryModel)) return; | ||
const instructionName = mappedInstructions[queryType]; | ||
const instructionList = queryInstructions[instructionName]; | ||
const kind = getModelBySlug(SYSTEM_MODELS, queryModel).pluralSlug; | ||
let tableAction = "ALTER"; | ||
@@ -730,3 +794,3 @@ let queryTypeReadable = null; | ||
case "add": { | ||
if (kind === "models" || kind === "indexes" || kind === "triggers") { | ||
if (queryModel === "model" || queryModel === "index" || queryModel === "trigger") { | ||
tableAction = "CREATE"; | ||
@@ -738,3 +802,3 @@ } | ||
case "set": { | ||
if (kind === "models") tableAction = "ALTER"; | ||
if (queryModel === "model") tableAction = "ALTER"; | ||
queryTypeReadable = "updating"; | ||
@@ -744,3 +808,3 @@ break; | ||
case "remove": { | ||
if (kind === "models" || kind === "indexes" || kind === "triggers") { | ||
if (queryModel === "model" || queryModel === "index" || queryModel === "trigger") { | ||
tableAction = "DROP"; | ||
@@ -755,6 +819,6 @@ } | ||
const modelSlug = modelInstruction?.slug?.being || modelInstruction?.slug; | ||
const usableSlug = kind === "models" ? slug : modelSlug; | ||
const usableSlug = queryModel === "model" ? slug : modelSlug; | ||
const tableName = convertToSnakeCase(pluralize(usableSlug)); | ||
const targetModel = kind === "models" && queryType === "add" ? null : getModelBySlug(models, usableSlug); | ||
if (kind === "indexes") { | ||
const targetModel = queryModel === "model" && queryType === "add" ? null : getModelBySlug(models, usableSlug); | ||
if (queryModel === "index") { | ||
const indexName = convertToSnakeCase(slug); | ||
@@ -793,3 +857,3 @@ const unique = instructionList?.unique; | ||
} | ||
if (kind === "triggers") { | ||
if (queryModel === "trigger") { | ||
const triggerName = convertToSnakeCase(slug); | ||
@@ -808,3 +872,3 @@ const params = []; | ||
throw new RoninError({ | ||
message: `When ${queryTypeReadable} ${kind}, targeting specific fields requires the \`UPDATE\` action.`, | ||
message: `When ${queryTypeReadable} ${PLURAL_MODEL_ENTITIES[queryModel]}, targeting specific fields requires the \`UPDATE\` action.`, | ||
code: "INVALID_MODEL_VALUE", | ||
@@ -848,3 +912,3 @@ fields: ["action"] | ||
const statement = `${tableAction} TABLE "${tableName}"`; | ||
if (kind === "models") { | ||
if (queryModel === "model") { | ||
if (queryType === "add") { | ||
@@ -875,3 +939,3 @@ const newModel = queryInstructions.to; | ||
} | ||
if (kind === "fields") { | ||
if (queryModel === "field") { | ||
if (queryType === "add") { | ||
@@ -1396,118 +1460,2 @@ if (!instructionList.type) instructionList.type = "string"; | ||
// src/utils/meta.ts | ||
var transformMetaQuery = (models, dependencyStatements, query) => { | ||
if (query.create) { | ||
const init = query.create.model; | ||
const details = "to" in query.create ? { slug: init, ...query.create.to } : init; | ||
const modelWithFields = addDefaultModelFields(details, true); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const instructions = { | ||
to: modelWithPresets | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "add", | ||
queryModel: "model", | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
add: { | ||
model: instructions | ||
} | ||
}; | ||
} | ||
if (query.drop) { | ||
const slug = query.drop.model; | ||
const instructions = { | ||
with: { slug } | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "remove", | ||
queryModel: "model", | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
remove: { | ||
model: instructions | ||
} | ||
}; | ||
} | ||
if (query.alter) { | ||
const slug = query.alter.model; | ||
if ("to" in query.alter) { | ||
const modelWithFields = addDefaultModelFields(query.alter.to, false); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const instructions2 = { | ||
with: { slug }, | ||
to: modelWithPresets | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "set", | ||
queryModel: "model", | ||
queryInstructions: instructions2 | ||
}); | ||
return { | ||
set: { | ||
model: instructions2 | ||
} | ||
}; | ||
} | ||
if ("create" in query.alter) { | ||
const type2 = Object.keys(query.alter.create)[0]; | ||
const item = query.alter.create[type2]; | ||
const completeItem = { slug: item.slug || `${type2}_slug`, ...item }; | ||
const instructions2 = { | ||
to: { | ||
model: { slug }, | ||
...completeItem | ||
} | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "add", | ||
queryModel: type2, | ||
queryInstructions: instructions2 | ||
}); | ||
return { | ||
add: { | ||
[type2]: instructions2 | ||
} | ||
}; | ||
} | ||
if ("alter" in query.alter) { | ||
const type2 = Object.keys(query.alter.alter)[0]; | ||
const itemSlug2 = query.alter.alter[type2]; | ||
const newItem = query.alter.alter.to; | ||
const instructions2 = { | ||
with: { model: { slug }, slug: itemSlug2 }, | ||
to: newItem | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "set", | ||
queryModel: type2, | ||
queryInstructions: instructions2 | ||
}); | ||
return { | ||
set: { | ||
[type2]: instructions2 | ||
} | ||
}; | ||
} | ||
const type = Object.keys(query.alter.drop)[0]; | ||
const itemSlug = query.alter.drop[type]; | ||
const instructions = { | ||
with: { model: { slug }, slug: itemSlug } | ||
}; | ||
addModelQueries(models, dependencyStatements, { | ||
queryType: "remove", | ||
queryModel: type, | ||
queryInstructions: instructions | ||
}); | ||
return { | ||
remove: { | ||
[type]: instructions | ||
} | ||
}; | ||
} | ||
return query; | ||
}; | ||
// src/index.ts | ||
@@ -1524,5 +1472,7 @@ var compileQueries = (queries, models, options) => { | ||
for (const query of queries) { | ||
const statementValues = options?.inlineParams ? null : []; | ||
const transformedQuery = transformMetaQuery( | ||
modelListWithPresets, | ||
dependencyStatements, | ||
statementValues, | ||
query | ||
@@ -1533,3 +1483,3 @@ ); | ||
modelListWithPresets, | ||
options?.inlineParams ? null : [] | ||
statementValues | ||
); | ||
@@ -1536,0 +1486,0 @@ dependencyStatements.push(...result.dependencies); |
{ | ||
"name": "@ronin/compiler", | ||
"version": "0.8.3", | ||
"version": "0.8.4", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "description": "Compiles RONIN queries to SQL statements.", |
444208
7454