@lbu/code-gen
Version:
Generate various boring parts of your server
182 lines (164 loc) • 5.13 kB
JavaScript
import { js } from "../tag/index.js";
import { getInsertPartial, getUpdatePartial } from "./partial-type.js";
import {
getPrimaryKeyWithType,
getQueryEnabledObjects,
getSortedKeysForType,
} from "./utils.js";
import { getWhereFieldSet, getWherePartial } from "./where-type.js";
/**
* Generate all usefull query partials
*
* @param {CodeGenContext} context
*/
export function generateQueryPartials(context) {
const partials = [];
// Generate field sets and the check function
partials.push(knownFieldsCheckFunction());
for (const type of getQueryEnabledObjects(context)) {
partials.push(getWhereFieldSet(context, type));
if (!type.queryOptions.isView) {
partials.push(getFieldSet(context, type));
}
}
// Generate the query partials
for (const type of getQueryEnabledObjects(context)) {
partials.push(getFieldsPartial(context, type));
partials.push(getWherePartial(context, type));
partials.push(getOrderPartial(context, type));
if (!type.queryOptions.isView) {
partials.push(getInsertPartial(context, type));
partials.push(getUpdatePartial(context, type));
}
}
const file = js`
import { AppError, isStaging } from "@lbu/stdlib";
import { query, isQueryObject } from "@lbu/store";
${partials}
`;
context.outputFiles.push({
contents: file,
relativePath: `./query-partials${context.extension}`,
});
context.rootExports.push(
`export * from "./query-partials${context.importExtension}";`,
);
}
/**
* Static field in set check function
*
* @returns {string}
*/
export function knownFieldsCheckFunction() {
// We create a copy of the Set & convert to array before throwing, in case someone
// tries to mutate it. We can also safely skip 'undefined' values, since they will
// never be used in queries.
return js`
/**
*
* @param {string} entity
* @param {string} subType
* @param {Set} set
* @param {*} value
*/
function checkFieldsInSet(entity, subType, set, value) {
if (isStaging()) {
for (const key of Object.keys(value)) {
if (!set.has(key) && value[key] !== undefined) {
throw new AppError(\`query.$\{entity}.$\{subType}Fields\`, 500, {
unknownKey: key, knownKeys: [ ...set ],
});
}
}
}
}
`;
}
/**
*
* @param {CodeGenContext} context
* @param {CodeGenObjectType} type
*/
export function getFieldSet(context, type) {
return `const ${type.name}FieldSet = new Set(["${Object.keys(type.keys).join(
`", "`,
)}"]);`;
}
/**
* A list of fields for the provided type, with dynamic tableName
* @property {CodeGenContext} context
* @property {CodeGenObjectType} type
* @return {string}
*/
export function getFieldsPartial(context, type) {
const { key: primaryKey } = getPrimaryKeyWithType(type);
return js`
/**
* Get all fields for ${type.name}
* @param {string} [tableName="${type.shortName}."]
* @param {{ excludePrimaryKey: boolean }} [options={}]
* @returns {QueryPart}
*/
export function ${type.name}Fields(tableName = "${
type.shortName
}.", options = {}) {
if (tableName.length > 0 && !tableName.endsWith(".")) {
tableName = \`$\{tableName}.\`;
}
if (options.excludePrimaryKey) {
return query([
\`${getSortedKeysForType(type)
.filter((it) => it !== primaryKey)
.map((it) => `$\{tableName}"${it}"`)
.join(", ")}\`
]);
}
return query([
\`${getSortedKeysForType(type)
.map((it) => `$\{tableName}"${it}"`)
.join(", ")}\`
]);
}
`;
}
/**
* A default ordering partial
* Working correctly, with or without dates
*
* @property {CodeGenContext} context
* @property {CodeGenObjectType} type
* @return {string}
*/
export function getOrderPartial(context, type) {
const { key: primaryKey } = getPrimaryKeyWithType(type);
if (type.queryOptions.withSoftDeletes || type.queryOptions.withDates) {
return js`
/**
* Get 'ORDER BY ' for ${type.name}
* @param {string} [tableName="${type.shortName}."]
* @returns {QueryPart}
*/
export function ${type.name}OrderBy(tableName = "${type.shortName}.") {
if (tableName.length > 0 && !tableName.endsWith(".")) {
tableName = \`$\{tableName}.\`;
}
const strings = [ \`$\{tableName}"createdAt", $\{tableName}"updatedAt", $\{tableName}"${primaryKey}" \` ];
return query(strings);
}
`;
}
return js`
/**
* Get 'ORDER BY ' for ${type.name}
* @param {string} [tableName="${type.shortName}."]
* @returns {QueryPart}
*/
export function ${type.name}OrderBy(tableName = "${type.shortName}.") {
if (tableName.length > 0 && !tableName.endsWith(".")) {
tableName = \`$\{tableName}.\`;
}
const strings = [ \`$\{tableName}"id" \` ];
return query(strings);
}
`;
}