@ronin/compiler
Advanced tools
Comparing version 0.10.2 to 0.10.3-leo-ron-1083-experimental-215
@@ -68,2 +68,19 @@ // src/utils/helpers.ts | ||
var isObject = (value) => value != null && typeof value === "object" && Array.isArray(value) === false; | ||
var getSymbol = (value) => { | ||
if (!isObject(value)) return null; | ||
const objectValue = value; | ||
if (RONIN_MODEL_SYMBOLS.QUERY in objectValue) { | ||
return { | ||
type: "query", | ||
value: objectValue[RONIN_MODEL_SYMBOLS.QUERY] | ||
}; | ||
} | ||
if (RONIN_MODEL_SYMBOLS.EXPRESSION in objectValue) { | ||
return { | ||
type: "expression", | ||
value: objectValue[RONIN_MODEL_SYMBOLS.EXPRESSION] | ||
}; | ||
} | ||
return null; | ||
}; | ||
var findInObject = (obj, pattern, replacer) => { | ||
@@ -89,6 +106,7 @@ let found = false; | ||
const path = prefix ? `${prefix}.${key}` : key; | ||
if (typeof obj[key] === "object" && obj[key] !== null) { | ||
flatten(obj[key], path, res); | ||
const value = obj[key]; | ||
if (typeof value === "object" && value !== null && !getSymbol(value)) { | ||
flatten(value, path, res); | ||
} else { | ||
res[path] = obj[key]; | ||
res[path] = value; | ||
} | ||
@@ -98,2 +116,5 @@ } | ||
}; | ||
var omit = (obj, properties) => Object.fromEntries( | ||
Object.entries(obj).filter(([key]) => !properties.includes(key)) | ||
); | ||
var expand = (obj) => { | ||
@@ -281,19 +302,2 @@ return Object.entries(obj).reduce((res, [key, val]) => { | ||
}; | ||
var getSymbol = (value) => { | ||
if (!isObject(value)) return null; | ||
const objectValue = value; | ||
if (RONIN_MODEL_SYMBOLS.QUERY in objectValue) { | ||
return { | ||
type: "query", | ||
value: objectValue[RONIN_MODEL_SYMBOLS.QUERY] | ||
}; | ||
} | ||
if (RONIN_MODEL_SYMBOLS.EXPRESSION in objectValue) { | ||
return { | ||
type: "expression", | ||
value: objectValue[RONIN_MODEL_SYMBOLS.EXPRESSION] | ||
}; | ||
} | ||
return null; | ||
}; | ||
@@ -700,3 +704,3 @@ // src/instructions/with.ts | ||
if (entity === "model") { | ||
let queryTypeDetails; | ||
let queryTypeDetails = {}; | ||
if (action === "create") { | ||
@@ -757,2 +761,4 @@ const newModel = jsonValue; | ||
} | ||
const modelSlug2 = "to" in queryTypeDetails ? queryTypeDetails?.to?.slug : "with" in queryTypeDetails ? queryTypeDetails?.with?.slug : void 0; | ||
if (modelSlug2 === "model") return null; | ||
const queryTypeAction = action === "create" ? "add" : action === "alter" ? "set" : "remove"; | ||
@@ -1187,3 +1193,3 @@ return { | ||
// src/instructions/selecting.ts | ||
var handleSelecting = (model, statementParams, instructions) => { | ||
var handleSelecting = (models, model, statementParams, instructions, options) => { | ||
let isJoining = false; | ||
@@ -1194,15 +1200,23 @@ let statement = instructions.selecting ? instructions.selecting.map((slug) => { | ||
if (instructions.including) { | ||
const filteredObject = Object.entries(instructions.including).map(([key, value]) => { | ||
const filteredObject = Object.entries(instructions.including).flatMap(([key, value]) => { | ||
const symbol = getSymbol(value); | ||
if (symbol) { | ||
if (symbol.type === "query") { | ||
isJoining = true; | ||
return null; | ||
} | ||
if (symbol.type === "expression") { | ||
value = parseFieldExpression(model, "including", symbol.value); | ||
} | ||
if (symbol?.type === "query") { | ||
isJoining = true; | ||
if (!options?.expandColumns) return null; | ||
const { queryModel: queryModelSlug } = splitQuery(symbol.value); | ||
const queryModel = getModelBySlug(models, queryModelSlug); | ||
const tableName = `including_${key}`; | ||
const duplicatedFields = queryModel.fields.filter((field) => { | ||
if (field.type === "group") return null; | ||
return model.fields.some((modelField) => modelField.slug === field.slug); | ||
}).filter((item) => item !== null); | ||
return duplicatedFields.map((field) => ({ | ||
key: `${tableName}.${field.slug}`, | ||
value: { | ||
[RONIN_MODEL_SYMBOLS.EXPRESSION]: `${RONIN_MODEL_SYMBOLS.FIELD}${field.slug}` | ||
} | ||
})); | ||
} | ||
return [key, value]; | ||
}).filter((entry) => entry !== null); | ||
return { key, value }; | ||
}).filter((entry) => entry !== null).map((entry) => [entry.key, entry.value]); | ||
const newObjectEntries = Object.entries(flatten(Object.fromEntries(filteredObject))); | ||
@@ -1212,5 +1226,9 @@ if (newObjectEntries.length > 0) { | ||
statement += newObjectEntries.map(([key, value]) => { | ||
if (typeof value === "string" && value.startsWith('"')) | ||
return `(${value}) as "${key}"`; | ||
return `${prepareStatementValue(statementParams, value)} as "${key}"`; | ||
const symbol = getSymbol(value); | ||
if (symbol?.type === "expression") { | ||
value = `(${parseFieldExpression(model, "including", symbol.value)})`; | ||
} else { | ||
value = prepareStatementValue(statementParams, value); | ||
} | ||
return `${value} as "${key}"`; | ||
}).join(", "); | ||
@@ -1352,2 +1370,3 @@ } | ||
); | ||
if (query === null) return { dependencies: [], main: dependencyStatements[0] }; | ||
const parsedQuery = splitQuery(query); | ||
@@ -1362,6 +1381,12 @@ const { queryType, queryModel, queryInstructions } = parsedQuery; | ||
} | ||
const { columns, isJoining } = handleSelecting(model, statementParams, { | ||
selecting: instructions?.selecting, | ||
including: instructions?.including | ||
}); | ||
const { columns, isJoining } = handleSelecting( | ||
models, | ||
model, | ||
statementParams, | ||
{ | ||
selecting: instructions?.selecting, | ||
including: instructions?.including | ||
}, | ||
options | ||
); | ||
let statement = ""; | ||
@@ -1526,3 +1551,4 @@ switch (queryType) { | ||
modelListWithPresets, | ||
options?.inlineParams ? null : [] | ||
options?.inlineParams ? null : [], | ||
{ expandColumns: options?.expandColumns } | ||
); | ||
@@ -1592,4 +1618,6 @@ dependencyStatements.push(...result.dependencies); | ||
}; | ||
var CLEAN_ROOT_MODEL = omit(ROOT_MODEL, ["system"]); | ||
export { | ||
CLEAN_ROOT_MODEL as ROOT_MODEL, | ||
Transaction | ||
}; |
{ | ||
"name": "@ronin/compiler", | ||
"version": "0.10.2", | ||
"version": "0.10.3-leo-ron-1083-experimental-215", | ||
"type": "module", | ||
@@ -5,0 +5,0 @@ "description": "Compiles RONIN queries to SQL statements.", |
@@ -73,2 +73,20 @@ # RONIN Compiler | ||
#### Root Model | ||
Before you can run any statements generated by the compiler that are altering the database schema, you need to create the table of the so-called "root model", which is used to store metadata for all other models. | ||
This table is called `ronin_schema`, which mimics the default `sqlite_schema` table provided by SQLite. You can generate its respective SQL statements like so: | ||
```typescript | ||
import { Transaction, ROOT_MODEL } from '@ronin/compiler'; | ||
const transaction = new Transaction([ | ||
{ | ||
create: { model: ROOT_MODEL } | ||
} | ||
]); | ||
``` | ||
Afterward, run the statements located in `transaction.statements` to create the table for the root model. Once that is done, your database is prepared to run any statements generated by the compiler. | ||
#### Types | ||
@@ -107,3 +125,21 @@ | ||
// This option should only be used if the generated SQL will be manually verified. | ||
inlineParams: true | ||
inlineParams: true, | ||
// By default, in the generated SQL statements, the compiler does not alias columns if | ||
// multiple different tables with the same column names are being joined. Only the table | ||
// names themselves are aliased. | ||
// | ||
// This ensures the cleanest possible SQL statements in conjunction with the default | ||
// behavior of SQL databases, where the result of a statement is a list (array) of | ||
// values, which are inherently not prone to conflicts. | ||
// | ||
// If the driver being used instead returns an object for every row, the driver must | ||
// ensure the uniqueness of every key in that object, which means prefixing duplicated | ||
// column names with the name of the respective table, if multiple tables are joined. | ||
// | ||
// Drivers that return objects for rows offer this behavior as an option that is | ||
// usually called "expand columns". If the driver being used does not offer such an | ||
// option, you can instead activate the option in the compiler, which results in longer | ||
// SQL statements because any duplicated column name is aliased. | ||
expandColumns: true | ||
}); | ||
@@ -122,3 +158,3 @@ ``` | ||
### Mental Model | ||
### Architecture | ||
@@ -125,0 +161,0 @@ The interface of creating new `Transaction` instances (thereby creating new transactions) was chosen in order to define the smallest workload unit that the compiler can operate on. |
Sorry, the diff of this file is too big to display
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
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
456232
7636
179