@sergio9929/pb-query
Version:
A type-safe PocketBase query builder
204 lines (201 loc) • 4.81 kB
JavaScript
// src/constants.ts
var OPERATORS = {
equal: "=",
notEqual: "!=",
greaterThan: ">",
greaterThanOrEqual: ">=",
lessThan: "<",
lessThanOrEqual: "<=",
like: "~",
notLike: "!~",
anyEqual: "?=",
anyNotEqual: "?!=",
anyGreaterThan: "?>",
anyGreaterThanOrEqual: "?>=",
anyLessThan: "?<",
anyLessThanOrEqual: "?<=",
anyLike: "?~",
anyNotLike: "?!~"
};
var DATETIME_MACROS = [
"@now",
"@second",
"@minute",
"@hour",
"@weekday",
"@day",
"@month",
"@year",
"@yesterday",
"@tomorrow",
"@todayStart",
"@todayEnd",
"@monthStart",
"@monthEnd",
"@yearStart",
"@yearEnd"
];
// src/utils.ts
function filter(raw, params) {
if (!params) {
return raw;
}
let sanitizedQuery = raw;
for (const key in params) {
let val = params[key];
switch (typeof val) {
case "boolean":
case "number":
val = `${val}`;
break;
case "string":
val = `'${val.replace(/'/g, "\\'")}'`;
break;
default:
if (val === null) {
val = "null";
} else if (val instanceof Date) {
val = `'${val.toISOString().replace("T", " ")}'`;
} else {
val = `'${JSON.stringify(val).replace(/'/g, "\\'")}'`;
}
}
sanitizedQuery = sanitizedQuery.replaceAll(`{:${key}}`, val);
}
return sanitizedQuery;
}
function isDateMacro(value) {
if (!isMacro(value)) {
return false;
}
return DATETIME_MACROS.includes(value);
}
function isMacro(value) {
if (typeof value !== "string") {
return false;
}
return value.length > 1 && value.startsWith("@");
}
// src/query.ts
function pbQuery() {
let query = "";
const keyCounter = /* @__PURE__ */ new Map();
const valueMap = /* @__PURE__ */ new Map();
const incrementKeyCounter = (key) => {
const count = keyCounter.get(key) || 0;
const newCount = count + 1;
keyCounter.set(key, newCount);
return newCount;
};
const saveValue = (key, value) => {
const count = incrementKeyCounter(key);
const newName = `${String(key)}${count}`;
valueMap.set(newName, value);
return newName;
};
const expression = (key, operator, value) => {
if (isDateMacro(value)) {
query += `${String(key)}${operator}${value}`;
} else {
const newName = saveValue(key, value);
query += `${String(key)}${operator}{:${newName}}`;
}
};
const builderFunctions = {};
for (const [name, operator] of Object.entries(OPERATORS)) {
const key = name;
builderFunctions[key] = (key2, value) => {
expression(key2, operator, value);
return restrictedQueryBuilder;
};
}
function build(filter2) {
if (typeof filter2 === "function") {
return filter2(query, Object.fromEntries(valueMap));
}
return { raw: query, values: Object.fromEntries(valueMap) };
}
const queryBuilder = {
...builderFunctions,
search(keys, value) {
query += "(";
const cleanedPaths = keys.filter((key) => key);
cleanedPaths.forEach((key, index) => {
expression(key, "~", value);
query += index < cleanedPaths.length - 1 ? " || " : "";
});
query += ")";
return restrictedQueryBuilder;
},
in(key, values) {
query += "(";
values.forEach((value, index) => {
expression(key, "=", value);
query += index < values.length - 1 ? " || " : "";
});
query += ")";
return restrictedQueryBuilder;
},
notIn(key, values) {
query += "(";
values.forEach((value, index) => {
expression(key, "!=", value);
query += index < values.length - 1 ? " && " : "";
});
query += ")";
return restrictedQueryBuilder;
},
between(key, from, to) {
query += "(";
expression(key, ">=", from);
query += " && ";
expression(key, "<=", to);
query += ")";
return restrictedQueryBuilder;
},
notBetween(key, from, to) {
query += "(";
expression(key, "<", from);
query += " || ";
expression(key, ">", to);
query += ")";
return restrictedQueryBuilder;
},
isNull(key) {
query += `${String(key)}=''`;
return restrictedQueryBuilder;
},
isNotNull(key) {
query += `${String(key)}!=''`;
return restrictedQueryBuilder;
},
custom(raw) {
query += raw;
return restrictedQueryBuilder;
},
group(callback) {
query += "(";
callback(queryBuilder);
query += ")";
return restrictedQueryBuilder;
},
build
};
const restrictedQueryBuilder = {
and() {
query += " && ";
return queryBuilder;
},
or() {
query += " || ";
return queryBuilder;
},
build
};
return queryBuilder;
}
export {
OPERATORS,
filter,
pbQuery
};