@cran/pg.q
Version:
Cranberry Postgres Queue
64 lines (63 loc) • 2.31 kB
JavaScript
import format from "pg-format";
export function createQueryNames(names) {
const queryNames = {
table: "queue",
field_id: "id",
field_attempts: "attempts",
field_payload: "payload",
...names,
};
if (!queryNames.order) {
queryNames.order = ([
`${queryNames.field_attempts} asc`,
`${queryNames.field_id} asc`,
]).join(",");
}
queryNames.order = queryNames.order.split(",")
.map(function mapOrder(order) {
const match = (/^(.+?)\s*(asc|desc)?$/u).exec(order.trim().toLowerCase());
if (null === match) {
throw new Error(`Invalid order statement "${order}"`);
}
return format("%1$I %2$s", match[1], match[2] || "asc");
}).join(",");
return queryNames;
}
function createQualifiedTableName({ schema, table, }) {
return schema ? format("%1$I.%2$I", schema, table) : format("%1$I", table);
}
function createQueryGetNext(names, target) {
const formatter = [
"update %1$s set %3$I = %3$I + 1 where %2$I = (",
"select %2$I from %1$s where %3$I < 3",
// and %5$I = %6$L
"order by %4$s for no key update skip locked limit 1",
") returning %2$I as id",
];
const args = [
createQualifiedTableName(names),
names.field_id,
names.field_attempts,
names.order,
];
if (names.field_target || target) {
formatter.splice(2, 0, "and %5$I = %6$L");
args.push(names.field_target || "target", target || "default");
}
return format(formatter.join(" "), ...args);
}
export function createQueries(names, target) {
const rule = ([
"z",
...(names.schema?.split(/[^\w]/gu) || []),
...(names.table.split(/[^\w]/gu)),
]).join("_");
const qualifiedTableName = createQualifiedTableName(names);
return {
next: createQueryGetNext(names, target),
deq: format("delete from %1$s where %2$I = $1 returning %3$I as payload", ...([qualifiedTableName, names.field_id, names.field_payload,])),
setup: format("create or replace rule %2$I as on insert to %1$s do also notify %2$I", ...([qualifiedTableName, rule,])),
listen: format("listen %1$I", rule),
unlisten: format("unlisten %1$I", rule),
};
}