- isQueue table option adds queue columns and a (status, available_at) index; BunSQLite.queue exposes add, claim, complete, fail and release_stale with atomic claims - Set busy_timeout on connections so workers in separate processes wait instead of failing with SQLITE_BUSY - Quote table and column names with backticks in generated SQL, so reserved words (to, order, group) work and unknown columns error instead of matching as string literals - Tests for queue ops, multi-process claims and reserved-word names Co-Authored-By: Claude Opus 5.5 <[email protected]>
106 lines
2.7 KiB
TypeScript
106 lines
2.7 KiB
TypeScript
import type {
|
|
ServerQueryParamsJoin,
|
|
ServerQueryParamsJoinMatchObject,
|
|
SQLInsertGenValueType,
|
|
} from "../types";
|
|
import { sqlName, sqlOperator, sqlRawEquality } from "./sql-safe";
|
|
|
|
type Param = {
|
|
mtch: ServerQueryParamsJoinMatchObject;
|
|
join: ServerQueryParamsJoin;
|
|
table_name: string;
|
|
};
|
|
|
|
export default function sqlGenGenJoinStr({ join, mtch, table_name }: Param) {
|
|
let values: SQLInsertGenValueType[] = [];
|
|
|
|
if (mtch.__batch) {
|
|
let btch_mtch = ``;
|
|
btch_mtch += `(`;
|
|
|
|
for (let i = 0; i < mtch.__batch.matches.length; i++) {
|
|
const __mtch = mtch.__batch.matches[
|
|
i
|
|
] as ServerQueryParamsJoinMatchObject;
|
|
|
|
const { str, values: batch_values } = sqlGenGenJoinStr({
|
|
join,
|
|
mtch: __mtch,
|
|
table_name,
|
|
});
|
|
|
|
btch_mtch += str;
|
|
|
|
values.push(...batch_values);
|
|
|
|
if (i < mtch.__batch.matches.length - 1) {
|
|
btch_mtch += ` ${sqlOperator(mtch.__batch.operator, "OR")} `;
|
|
}
|
|
}
|
|
|
|
btch_mtch += `)`;
|
|
|
|
return {
|
|
str: btch_mtch,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const equality = mtch.raw_equality ? sqlRawEquality(mtch.raw_equality) : "=";
|
|
|
|
// `table_name` is already validated and quoted by `sqlGenerator`
|
|
const lhs = `${
|
|
typeof mtch.source == "object"
|
|
? sqlName(mtch.source.tableName, "table name")
|
|
: table_name
|
|
}.${sqlName(
|
|
typeof mtch.source == "object" ? mtch.source.fieldName : mtch.source,
|
|
"field name",
|
|
)}`;
|
|
|
|
if (mtch.between) {
|
|
values.push(mtch.between.min, mtch.between.max);
|
|
|
|
return {
|
|
str: `${lhs} BETWEEN ? AND ?`,
|
|
values,
|
|
};
|
|
}
|
|
|
|
if (mtch.not_between) {
|
|
values.push(mtch.not_between.min, mtch.not_between.max);
|
|
|
|
return {
|
|
str: `${lhs} NOT BETWEEN ? AND ?`,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const rhs = (() => {
|
|
if (mtch.targetLiteral !== undefined && mtch.targetLiteral !== null) {
|
|
values.push(mtch.targetLiteral);
|
|
return `?`;
|
|
}
|
|
|
|
const targetTable =
|
|
typeof mtch.target == "object"
|
|
? mtch.target.tableName
|
|
: join.alias || join.tableName;
|
|
|
|
const targetField =
|
|
typeof mtch.target == "object"
|
|
? mtch.target.fieldName
|
|
: mtch.target;
|
|
|
|
return `${sqlName(targetTable, "table name")}.${sqlName(
|
|
targetField,
|
|
"field name",
|
|
)}`;
|
|
})();
|
|
|
|
return {
|
|
str: `${lhs} ${equality} ${rhs}`,
|
|
values,
|
|
};
|
|
}
|