@ronin/compiler
Advanced tools
Comparing version 0.8.3 to 0.8.4-leo-ron-1083-experimental-160
@@ -468,2 +468,4 @@ // src/utils/helpers.ts | ||
}, | ||
// This name mimics the `sqlite_schema` table in SQLite. | ||
table: "ronin_schema", | ||
fields: [ | ||
@@ -479,94 +481,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) => { | ||
@@ -673,5 +593,5 @@ const associativeModels = models.flatMap((model) => { | ||
var mappedInstructions = { | ||
add: "to", | ||
set: "with", | ||
remove: "with" | ||
create: "to", | ||
alter: "with", | ||
drop: "with" | ||
}; | ||
@@ -718,29 +638,88 @@ var typesInSQLite = { | ||
}; | ||
var addModelQueries = (models, dependencyStatements, queryDetails) => { | ||
const { queryType, queryModel, queryInstructions } = queryDetails; | ||
if (!["add", "set", "remove"].includes(queryType)) return; | ||
if (!SYSTEM_MODEL_SLUGS.includes(queryModel)) return; | ||
const instructionName = mappedInstructions[queryType]; | ||
var PLURAL_MODEL_ENTITIES = { | ||
field: "fields", | ||
index: "indexes", | ||
trigger: "triggers", | ||
preset: "presets" | ||
}; | ||
var addModelStatements = (models, dependencyStatements, statementParams, query) => { | ||
const { queryType } = splitQuery(query); | ||
let action = queryType; | ||
let entity = "model"; | ||
let queryInstructions; | ||
if (query.create) { | ||
const init = query.create.model; | ||
const details = "to" in query.create ? { slug: init, ...query.create.to } : init; | ||
queryInstructions = { | ||
to: details | ||
}; | ||
} | ||
if (query.drop) { | ||
queryInstructions = { | ||
with: { slug: query.drop.model } | ||
}; | ||
} | ||
if (query.alter) { | ||
const modelSlugTest = query.alter.model; | ||
if ("to" in query.alter) { | ||
queryInstructions = { | ||
with: { slug: modelSlugTest }, | ||
to: query.alter.to | ||
}; | ||
} else { | ||
action = Object.keys(query.alter).filter( | ||
(key) => key !== "model" | ||
)[0]; | ||
const details = query.alter[action]; | ||
entity = Object.keys(details)[0]; | ||
let jsonSlug = details[entity]; | ||
let jsonValue2; | ||
if ("create" in query.alter) { | ||
const item = query.alter.create[entity]; | ||
jsonSlug = item.slug || `${entity}Slug`; | ||
jsonValue2 = { slug: jsonSlug, ...item }; | ||
queryInstructions = { | ||
to: { | ||
model: { slug: modelSlugTest }, | ||
...jsonValue2 | ||
} | ||
}; | ||
} | ||
if ("alter" in query.alter) { | ||
jsonValue2 = query.alter.alter.to; | ||
queryInstructions = { | ||
with: { model: { slug: modelSlugTest }, slug: jsonSlug }, | ||
to: jsonValue2 | ||
}; | ||
} | ||
if ("drop" in query.alter) { | ||
queryInstructions = { | ||
with: { model: { slug: modelSlugTest }, slug: jsonSlug } | ||
}; | ||
} | ||
} | ||
} | ||
if (!queryInstructions) return query; | ||
const instructionName = mappedInstructions[action]; | ||
const instructionList = queryInstructions[instructionName]; | ||
const kind = getModelBySlug(SYSTEM_MODELS, queryModel).pluralSlug; | ||
let tableAction = "ALTER"; | ||
let queryTypeReadable = null; | ||
switch (queryType) { | ||
case "add": { | ||
if (kind === "models" || kind === "indexes" || kind === "triggers") { | ||
let actionReadable = null; | ||
switch (action) { | ||
case "create": { | ||
if (entity === "model" || entity === "index" || entity === "trigger") { | ||
tableAction = "CREATE"; | ||
} | ||
queryTypeReadable = "creating"; | ||
actionReadable = "creating"; | ||
break; | ||
} | ||
case "set": { | ||
if (kind === "models") tableAction = "ALTER"; | ||
queryTypeReadable = "updating"; | ||
case "alter": { | ||
if (entity === "model") tableAction = "ALTER"; | ||
actionReadable = "updating"; | ||
break; | ||
} | ||
case "remove": { | ||
if (kind === "models" || kind === "indexes" || kind === "triggers") { | ||
case "drop": { | ||
if (entity === "model" || entity === "index" || entity === "trigger") { | ||
tableAction = "DROP"; | ||
} | ||
queryTypeReadable = "deleting"; | ||
actionReadable = "deleting"; | ||
break; | ||
@@ -752,6 +731,76 @@ } | ||
const modelSlug = modelInstruction?.slug?.being || modelInstruction?.slug; | ||
const usableSlug = kind === "models" ? slug : modelSlug; | ||
const usableSlug = entity === "model" ? slug : modelSlug; | ||
const tableName = convertToSnakeCase(pluralize(usableSlug)); | ||
const targetModel = kind === "models" && queryType === "add" ? null : getModelBySlug(models, usableSlug); | ||
if (kind === "indexes") { | ||
const targetModel = entity === "model" && action === "create" ? null : getModelBySlug(models, usableSlug); | ||
const statement = `${tableAction} TABLE "${tableName}"`; | ||
if (entity === "model") { | ||
let queryTypeDetails; | ||
if (action === "create") { | ||
const modelWithFields = addDefaultModelFields(queryInstructions.to, true); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const { fields } = modelWithPresets; | ||
const columns = fields.map((field) => getFieldStatement(models, modelWithPresets, field)).filter(Boolean); | ||
dependencyStatements.push({ | ||
statement: `${statement} (${columns.join(", ")})`, | ||
params: [] | ||
}); | ||
models.push(modelWithPresets); | ||
queryTypeDetails = { to: modelWithPresets }; | ||
} | ||
if (action === "alter") { | ||
const modelWithFields = addDefaultModelFields(queryInstructions.to, false); | ||
const modelWithPresets = addDefaultModelPresets(models, modelWithFields); | ||
const newSlug = modelWithPresets.pluralSlug; | ||
if (newSlug) { | ||
const newTable = convertToSnakeCase(newSlug); | ||
dependencyStatements.push({ | ||
statement: `${statement} RENAME TO "${newTable}"`, | ||
params: [] | ||
}); | ||
} | ||
Object.assign(targetModel, modelWithPresets); | ||
queryTypeDetails = { | ||
with: { | ||
slug: usableSlug | ||
}, | ||
to: modelWithPresets | ||
}; | ||
} | ||
if (action === "drop") { | ||
models.splice(models.indexOf(targetModel), 1); | ||
dependencyStatements.push({ statement, params: [] }); | ||
queryTypeDetails = { | ||
with: { slug: usableSlug } | ||
}; | ||
} | ||
const queryTypeAction = action === "create" ? "add" : action === "alter" ? "set" : "remove"; | ||
return { | ||
[queryTypeAction]: { | ||
model: queryTypeDetails | ||
} | ||
}; | ||
} | ||
if (entity === "field") { | ||
if (action === "create") { | ||
if (!instructionList.type) instructionList.type = "string"; | ||
dependencyStatements.push({ | ||
statement: `${statement} ADD COLUMN ${getFieldStatement(models, targetModel, instructionList)}`, | ||
params: [] | ||
}); | ||
} else if (action === "alter") { | ||
const newSlug = queryInstructions.to?.slug; | ||
if (newSlug) { | ||
dependencyStatements.push({ | ||
statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`, | ||
params: [] | ||
}); | ||
} | ||
} else if (action === "drop") { | ||
dependencyStatements.push({ | ||
statement: `${statement} DROP COLUMN "${slug}"`, | ||
params: [] | ||
}); | ||
} | ||
} | ||
if (entity === "index") { | ||
const indexName = convertToSnakeCase(slug); | ||
@@ -763,3 +812,3 @@ const unique = instructionList?.unique; | ||
let statement2 = `${tableAction}${unique ? " UNIQUE" : ""} INDEX "${indexName}"`; | ||
if (queryType === "add") { | ||
if (action === "create") { | ||
const model = targetModel; | ||
@@ -789,12 +838,11 @@ const columns = fields.map((field) => { | ||
dependencyStatements.push({ statement: statement2, params }); | ||
return; | ||
} | ||
if (kind === "triggers") { | ||
if (entity === "trigger") { | ||
const triggerName = convertToSnakeCase(slug); | ||
const params = []; | ||
let statement2 = `${tableAction} TRIGGER "${triggerName}"`; | ||
if (queryType === "add") { | ||
if (action === "create") { | ||
const currentModel = targetModel; | ||
const { when, action } = instructionList; | ||
const statementParts = [`${when} ${action}`]; | ||
const { when, action: action2 } = instructionList; | ||
const statementParts = [`${when} ${action2}`]; | ||
const effectQueries = instructionList?.effects; | ||
@@ -804,5 +852,5 @@ const filterQuery = instructionList?.filter; | ||
if (fields) { | ||
if (action !== "UPDATE") { | ||
if (action2 !== "UPDATE") { | ||
throw new RoninError({ | ||
message: `When ${queryTypeReadable} ${kind}, targeting specific fields requires the \`UPDATE\` action.`, | ||
message: `When ${actionReadable} ${PLURAL_MODEL_ENTITIES[entity]}, targeting specific fields requires the \`UPDATE\` action.`, | ||
code: "INVALID_MODEL_VALUE", | ||
@@ -818,7 +866,7 @@ fields: ["action"] | ||
statementParts.push("ON", `"${tableName}"`); | ||
if (filterQuery || effectQueries.some((query) => findInObject(query, RONIN_MODEL_SYMBOLS.FIELD))) { | ||
if (filterQuery || effectQueries.some((query2) => findInObject(query2, RONIN_MODEL_SYMBOLS.FIELD))) { | ||
statementParts.push("FOR EACH ROW"); | ||
} | ||
if (filterQuery) { | ||
const tableAlias = action === "DELETE" ? RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD : RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW; | ||
const tableAlias = action2 === "DELETE" ? RONIN_MODEL_SYMBOLS.FIELD_PARENT_OLD : RONIN_MODEL_SYMBOLS.FIELD_PARENT_NEW; | ||
const withStatement = handleWith( | ||
@@ -844,53 +892,19 @@ models, | ||
dependencyStatements.push({ statement: statement2, params }); | ||
return; | ||
} | ||
const statement = `${tableAction} TABLE "${tableName}"`; | ||
if (kind === "models") { | ||
if (queryType === "add") { | ||
const newModel = queryInstructions.to; | ||
const { fields } = newModel; | ||
const columns = fields.map((field) => getFieldStatement(models, newModel, field)).filter(Boolean); | ||
dependencyStatements.push({ | ||
statement: `${statement} (${columns.join(", ")})`, | ||
params: [] | ||
}); | ||
models.push(newModel); | ||
} else if (queryType === "set") { | ||
const newSlug = queryInstructions.to?.pluralSlug; | ||
if (newSlug) { | ||
const newTable = convertToSnakeCase(newSlug); | ||
dependencyStatements.push({ | ||
statement: `${statement} RENAME TO "${newTable}"`, | ||
params: [] | ||
}); | ||
const pluralType = PLURAL_MODEL_ENTITIES[entity]; | ||
const jsonAction = action === "create" ? "insert" : action === "alter" ? "patch" : "remove"; | ||
const jsonValue = action === "create" ? { ...instructionList, model: void 0 } : action === "alter" ? queryInstructions.to : null; | ||
let json = `json_${jsonAction}(${RONIN_MODEL_SYMBOLS.FIELD}${pluralType}, '$.${slug}'`; | ||
if (jsonValue) json += `, ${prepareStatementValue(statementParams, jsonValue)}`; | ||
json += ")"; | ||
return { | ||
set: { | ||
model: { | ||
with: { slug: usableSlug }, | ||
to: { | ||
[pluralType]: { [RONIN_MODEL_SYMBOLS.EXPRESSION]: json } | ||
} | ||
} | ||
Object.assign(targetModel, queryInstructions.to); | ||
} else if (queryType === "remove") { | ||
models.splice(models.indexOf(targetModel), 1); | ||
dependencyStatements.push({ statement, params: [] }); | ||
} | ||
return; | ||
} | ||
if (kind === "fields") { | ||
if (queryType === "add") { | ||
if (!instructionList.type) instructionList.type = "string"; | ||
dependencyStatements.push({ | ||
statement: `${statement} ADD COLUMN ${getFieldStatement(models, targetModel, instructionList)}`, | ||
params: [] | ||
}); | ||
} else if (queryType === "set") { | ||
const newSlug = queryInstructions.to?.slug; | ||
if (newSlug) { | ||
dependencyStatements.push({ | ||
statement: `${statement} RENAME COLUMN "${slug}" TO "${newSlug}"`, | ||
params: [] | ||
}); | ||
} | ||
} else if (queryType === "remove") { | ||
dependencyStatements.push({ | ||
statement: `${statement} DROP COLUMN "${slug}"`, | ||
params: [] | ||
}); | ||
} | ||
} | ||
}; | ||
}; | ||
@@ -1394,118 +1408,2 @@ | ||
// 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 | ||
@@ -1522,5 +1420,7 @@ var compileQueries = (queries, models, options) => { | ||
for (const query of queries) { | ||
const transformedQuery = transformMetaQuery( | ||
const statementValues = options?.inlineParams ? null : []; | ||
const transformedQuery = addModelStatements( | ||
modelListWithPresets, | ||
dependencyStatements, | ||
statementValues, | ||
query | ||
@@ -1531,3 +1431,3 @@ ); | ||
modelListWithPresets, | ||
options?.inlineParams ? null : [] | ||
statementValues | ||
); | ||
@@ -1534,0 +1434,0 @@ dependencyStatements.push(...result.dependencies); |
{ | ||
"name": "@ronin/compiler", | ||
"version": "0.8.3", | ||
"version": "0.8.4-leo-ron-1083-experimental-160", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "description": "Compiles RONIN queries to SQL statements.", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Unpublished package
Supply chain riskPackage version was not found on the registry. It may exist on a different registry and need to be configured to pull from that registry.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Unpopular package
QualityThis package is not very popular.
Found 1 instance in 1 package
0
442798
7405
1