UNPKG

@sidekick-coder/db

Version:

Cli Tool to manipulate data from diferent sources

406 lines (399 loc) 10.4 kB
import sift from 'sift'; import * as valibot from 'valibot'; import path, { dirname, resolve } from 'path'; import fs from 'fs'; import 'url'; import { parse as parse$1, stringify as stringify$1 } from 'yaml'; import qs from 'qs'; import * as inquirer from '@inquirer/prompts'; import { pick, omit, orderBy } from 'lodash-es'; // src/core/provider/queryArray.ts // src/utils/tryCatch.ts async function tryCatch(tryer) { try { const result = await tryer(); return [result, null]; } catch (error) { return [null, error]; } } tryCatch.sync = function(tryer) { try { const result = tryer(); return [result, null]; } catch (error) { return [null, error]; } }; var parse = parse$1; var stringify = stringify$1; var YAML = { parse, stringify }; function readFileSync(path4) { const [content, error] = tryCatch.sync(() => fs.readFileSync(path4)); if (error) { return null; } return new Uint8Array(content); } readFileSync.text = function(filepath, defaultValue = "") { const content = readFileSync(filepath); if (!content) { return defaultValue; } return new TextDecoder().decode(content); }; readFileSync.json = function(path4, options) { const content = readFileSync.text(path4); if (!content) { return (options == null ? void 0 : options.default) || null; } const [json, error] = tryCatch.sync(() => JSON.parse(content, options == null ? void 0 : options.reviver)); return error ? (options == null ? void 0 : options.default) || null : json; }; readFileSync.yaml = function(path4, options) { const content = readFileSync.text(path4); if (!content) { return (options == null ? void 0 : options.default) || null; } const [yml, error] = tryCatch.sync(() => YAML.parse(content, options == null ? void 0 : options.parseOptions)); return error ? (options == null ? void 0 : options.default) || null : yml; }; var filesystem = { readSync: readFileSync}; function createReviver(folder) { return (_, value) => { if (typeof value == "string" && value.startsWith("./")) { return resolve(dirname(folder), value); } return value; }; } var schema = valibot.optional( valibot.pipe( valibot.any(), valibot.transform((value) => { if (typeof value == "object") { return value; } if (/\.yml$/.test(value)) { const file = value.replace(/^@/, ""); const folder = dirname(file); return filesystem.readSync.yaml(value.replace(/^@/, ""), { reviver: createReviver(folder) }); } if (typeof value == "string" && value.includes("=")) { const result = qs.parse(value, { allowEmptyArrays: true }); return result; } if (typeof value == "string" && value.startsWith("{")) { return JSON.parse(value); } if (typeof value == "string" && value.startsWith("[")) { return JSON.parse(value); } return value; }), valibot.record(valibot.string(), valibot.any()) ) ); function createPathNode() { return { resolve: (...args) => path.resolve(...args), join: (...args) => path.join(...args), dirname: (args) => path.dirname(args), basename: (args) => path.basename(args) }; } // src/core/validator/valibot.ts var stringList = valibot.pipe( valibot.any(), valibot.transform((value) => { if (typeof value === "string") { return value.split(","); } if (Array.isArray(value)) { return value; } }), valibot.array(valibot.string()) ); function array2(s) { return valibot.pipe( v2.union([v2.array(s), s]), valibot.transform((value) => Array.isArray(value) ? value : [value]), valibot.array(s) ); } function path3(dirname2, path4 = createPathNode()) { return valibot.pipe( valibot.string(), valibot.transform((value) => path4.resolve(dirname2, value)) ); } function uint8() { return valibot.pipe( valibot.any(), valibot.check((value) => value instanceof Uint8Array), valibot.transform((value) => value) ); } var prompts = { password: (options) => valibot.optionalAsync(valibot.string(), () => { return inquirer.password({ message: "Enter password", ...options }); }) }; var extras = { array: array2, vars: schema, stringList, path: path3, uint8, number: valibot.pipe( valibot.any(), valibot.transform(Number), valibot.check((n) => !isNaN(n)), valibot.number() ) }; var vWithExtras = { ...valibot, extras, prompts }; var v2 = vWithExtras; // src/core/database/where.ts function parseCondition(condition) { if (condition.value === "$true") { return { or: [], and: [ { field: condition.field, operator: condition.operator, value: true } ] }; } if (condition.value === "$false") { return { or: [], and: [ { field: condition.field, operator: condition.operator, value: false } ] }; } if (condition.value === "$exists") { return { or: [], and: [ { field: condition.field, operator: "exists", value: true } ] }; } if (typeof condition.value == "string" && condition.value.startsWith("$in")) { const values = condition.value.slice(4, -1).split(","); return { or: [], and: [ { field: condition.field, operator: "in", value: values } ] }; } return { and: [condition], or: [] }; } function transformWhere(where) { const { and, or, ...rest } = where; const result = { and: [], or: [] }; if ((rest == null ? void 0 : rest.field) && (rest == null ? void 0 : rest.operator)) { return { field: rest.field, operator: rest.operator, value: rest.value }; } for (const [key, value] of Object.entries(rest)) { const { and: and2, or: or2 } = parseCondition({ field: (value == null ? void 0 : value.field) || key, operator: (value == null ? void 0 : value.operator) || "eq", value: (value == null ? void 0 : value.value) || value }); if (and2) { result.and.push(...and2); } if (or2) { result.or.push(...or2); } } if (and == null ? void 0 : and.length) { and.forEach((w) => { result.and.push(transformWhere(w)); }); } if (or == null ? void 0 : or.length) { or.forEach((w) => { result.or.push(transformWhere(w)); }); } if (!result.or.length) { delete result.or; } if (!result.and.length) { delete result.and; } return result; } v2.pipe(v2.any(), v2.transform(transformWhere)); var operatorMap = { eq: "$eq", ne: "$ne", gt: "$gt", gte: "$gte", lt: "$lt", lte: "$lte", in: "$in", exists: "$exists" }; function parseCondition2(condition) { const { field, operator, value } = condition; if (!field || !operator) { console.error("Invalid condition:", condition); return {}; } const siftOperator = operatorMap[operator]; if (!siftOperator) { throw new Error(`Unsupported operator: ${operator}`); } return { [field]: { [siftOperator]: value } }; } function parseGroup(group) { const { and, or, ...rest } = group; const parsed = {}; if ((rest == null ? void 0 : rest.field) && (rest == null ? void 0 : rest.operator)) { return parseCondition2(rest); } if (and == null ? void 0 : and.length) { parsed.$and = and.map(parseGroup); } if (or == null ? void 0 : or.length) { parsed.$or = or.map(parseGroup); } return parsed; } function parseWhere(payload) { var _a, _b; if (!payload) return {}; const transformed = transformWhere(payload); const parsed = parseGroup(transformed); if (!((_a = parsed.$and) == null ? void 0 : _a.length)) { delete parsed.$and; } if (!((_b = parsed.$or) == null ? void 0 : _b.length)) { delete parsed.$or; } return parsed; } function query(data, options) { var _a; const { where, include, exclude } = options; const limit = options.limit; const offset = options.offset || 0; const siftQuery = parseWhere(where); let items = data.filter(sift(siftQuery)); if (include == null ? void 0 : include.length) { items = items.map((item) => pick(item, options.include)); } if ((exclude == null ? void 0 : exclude.length) && !(include == null ? void 0 : include.length)) { items = items.map((item) => omit(item, exclude)); } if ((_a = options.sortBy) == null ? void 0 : _a.length) { const sort = options.sortBy.map((f, i) => ({ field: f, order: options.sortDesc && options.sortDesc[i] ? "desc" : "asc" })); items = orderBy( items, sort.map((s) => s.field), sort.map((s) => s.order) ); } items = items.slice(offset, limit ? offset + limit : void 0); return items; } function count(data, options) { const items = query(data, { where: options.where }); return items.length; } // src/providers/file/list.ts async function list(payload) { const { filesystem: filesystem2, root, options, parser } = payload; const resolve3 = (...args) => filesystem2.path.resolve(root, ...args); const where = (options == null ? void 0 : options.where) || {}; const exclude = options == null ? void 0 : options.exclude; const include = options == null ? void 0 : options.include; const limit = options == null ? void 0 : options.limit; const page = (options == null ? void 0 : options.page) || 1; const sortBy = options == null ? void 0 : options.sortBy; const sortDesc = options == null ? void 0 : options.sortDesc; const files = filesystem2.readdirSync(root).filter((f) => ![".db"].includes(f)); const result = []; for (const file of files) { const filename = resolve3(file); const content = filesystem2.readSync.text(filename); const item = { id: file.replace(`.${parser.ext}`, ""), filename, raw: content }; Object.assign(item, parser.parse(content)); result.push(item); } const items = query(result, { where, exclude, include, limit, offset: page > 1 ? (page - 1) * limit : 0, sortBy, sortDesc }); const meta = { total: count(result, { where }), limit, total_pages: limit ? Math.ceil(result.length / limit) : 1 }; return { meta, data: items }; } export { list };