@nuxt/content
Version:
Write your content inside your Nuxt app
154 lines (153 loc) • 4.85 kB
JavaScript
import { withoutTrailingSlash } from "ufo";
import { tables } from "#content/manifest";
const buildGroup = (group, type) => {
const conditions = group._conditions;
return conditions.length > 0 ? `(${conditions.join(` ${type} `)})` : "";
};
export const collectionQueryGroup = (collection) => {
const conditions = [];
const query = {
// @ts-expect-error -- internal
_conditions: conditions,
where(field, operator, value) {
let condition;
switch (operator.toUpperCase()) {
case "IN":
case "NOT IN":
if (Array.isArray(value)) {
const values = value.map((val) => singleQuote(val)).join(", ");
condition = `"${String(field)}" ${operator.toUpperCase()} (${values})`;
} else {
throw new TypeError(`Value for ${operator} must be an array`);
}
break;
case "BETWEEN":
case "NOT BETWEEN":
if (Array.isArray(value) && value.length === 2) {
condition = `"${String(field)}" ${operator.toUpperCase()} ${singleQuote(value[0])} AND ${singleQuote(value[1])}`;
} else {
throw new Error(`Value for ${operator} must be an array with two elements`);
}
break;
case "IS NULL":
case "IS NOT NULL":
condition = `"${String(field)}" ${operator.toUpperCase()}`;
break;
case "LIKE":
case "NOT LIKE":
condition = `"${String(field)}" ${operator.toUpperCase()} ${singleQuote(value)}`;
break;
default:
condition = `"${String(field)}" ${operator} ${singleQuote(typeof value === "boolean" ? Number(value) : value)}`;
}
conditions.push(`${condition}`);
return query;
},
andWhere(groupFactory) {
const group = groupFactory(collectionQueryGroup(collection));
conditions.push(buildGroup(group, "AND"));
return query;
},
orWhere(groupFactory) {
const group = groupFactory(collectionQueryGroup(collection));
conditions.push(buildGroup(group, "OR"));
return query;
}
};
return query;
};
export const collectionQueryBuilder = (collection, fetch) => {
const params = {
conditions: [],
selectedFields: [],
offset: 0,
limit: 0,
orderBy: [],
// Count query
count: {
field: "",
distinct: false
}
};
const query = {
// @ts-expect-error -- internal
__params: params,
andWhere(groupFactory) {
const group = groupFactory(collectionQueryGroup(collection));
params.conditions.push(buildGroup(group, "AND"));
return query;
},
orWhere(groupFactory) {
const group = groupFactory(collectionQueryGroup(collection));
params.conditions.push(buildGroup(group, "OR"));
return query;
},
path(path) {
return query.where("path", "=", withoutTrailingSlash(path));
},
skip(skip) {
params.offset = skip;
return query;
},
where(field, operator, value) {
query.andWhere((group) => group.where(String(field), operator, value));
return query;
},
limit(limit) {
params.limit = limit;
return query;
},
select(...fields) {
if (fields.length) {
params.selectedFields.push(...fields);
}
return query;
},
order(field, direction) {
params.orderBy.push(`"${String(field)}" ${direction}`);
return query;
},
async all() {
return fetch(collection, buildQuery()).then((res) => res || []);
},
async first() {
return fetch(collection, buildQuery({ limit: 1 })).then((res) => res[0] || null);
},
async count(field = "*", distinct = false) {
return fetch(collection, buildQuery({
count: { field: String(field), distinct }
})).then((m) => m[0].count);
}
};
function buildQuery(opts = {}) {
let query2 = "SELECT ";
if (opts?.count) {
query2 += `COUNT(${opts.count.distinct ? "DISTINCT " : ""}${opts.count.field}) as count`;
} else {
const fields = Array.from(new Set(params.selectedFields));
query2 += fields.length > 0 ? fields.map((f) => `"${String(f)}"`).join(", ") : "*";
}
query2 += ` FROM ${tables[String(collection)]}`;
if (params.conditions.length > 0) {
query2 += ` WHERE ${params.conditions.join(" AND ")}`;
}
if (params.orderBy.length > 0) {
query2 += ` ORDER BY ${params.orderBy.join(", ")}`;
} else {
query2 += ` ORDER BY stem ASC`;
}
const limit = opts?.limit || params.limit;
if (limit > 0) {
if (params.offset > 0) {
query2 += ` LIMIT ${limit} OFFSET ${params.offset}`;
} else {
query2 += ` LIMIT ${limit}`;
}
}
return query2;
}
return query;
};
function singleQuote(value) {
return `'${String(value).replace(/'/g, "''")}'`;
}