UNPKG

@nuxt/content

Version:

Write your content inside your Nuxt app

154 lines (153 loc) 4.85 kB
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, "''")}'`; }