UNPKG

blade

Version:
220 lines (218 loc) 7.25 kB
import { r as QUERY_SYMBOLS } from "./dist-C7NzDGd9.js"; //#region ../blade-syntax/dist/queries-CX5Cbnwt.js /** * Splits the given path into an array of so-called segments. This is done by * splitting the path on the `.` character, but only if it's not preceded by a * `\` character. This is done to allow for setting values on nested records, * such as `invoice.companyName`. * * @param path - Dot-separated path to split into segments. * * @returns Array of path segments. */ const getPathSegments = (path) => { return path.replace(/\\\./g, "​").split(/[[.]/g).map((s) => s.replace(/\u200B/g, ".")).filter((x) => !!x.trim()).map((x) => x.replaceAll("\\.", ".")); }; /** * Set the property at the given path to the given value. * * @param obj - Object to set the property on. * @param pathSegments - An array of property keys leading up to the final * property to set. * @param value - Value to set at the given path. * * @returns Object with the updated property. */ const setPropertyViaPathSegments = (obj, pathSegments, value) => { let current = obj; for (let i = 0; i < pathSegments.length; i++) { const key = pathSegments[i]; if (i === pathSegments.length - 1) current[key] = typeof value === "function" ? value(current[key]) : value; else { if (!Object.prototype.hasOwnProperty.call(current, key) || typeof current[key] !== "object") current[key] = {}; current = current[key]; } } }; const setProperty = (obj, path, value) => { if (path === ".") Object.assign(obj, value); else setPropertyViaPathSegments(obj, getPathSegments(path), value); return obj; }; /** * Determines whether an object is a plain object or not. * * @param value - The object to check. * * @returns A boolean indicating whether the object is plain, or not. */ const isPlainObject = (value) => { return Object.prototype.toString.call(value) === "[object Object]"; }; /** * Recursively iterates through an object and calls a mutation function for the value of * every property in the object. * * @param obj - The object to mutate. * @param callback - The function to call for every value in the object. * * @returns The mutated object. */ const mutateStructure = (obj, callback) => { if (Array.isArray(obj)) { obj.map((item) => mutateStructure(item, callback)); return obj; } if (isPlainObject(obj)) { for (const key in obj) if (Object.prototype.hasOwnProperty.call(obj, key)) { if (obj[key] === void 0) { delete obj[key]; continue; } if (isPlainObject(obj[key])) { mutateStructure(obj[key], callback); continue; } if (Array.isArray(obj[key])) { obj[key].map((item) => mutateStructure(item, callback)); continue; } obj[key] = callback(obj[key]); } return obj; } return callback(obj); }; /** * A utility function that creates a proxy object to handle dynamic property access and * function calls, which is used to compose the query and schema syntax. * * @param config - An object containing configuration for the composed structure. * * @returns A proxy object that intercepts property access and function calls. * * ### Usage * ```typescript * const getProxy = getSyntaxProxy<GetQuery>({ * root: `${QUERY_SYMBOLS.QUERY}.get`, * // Execute the query and return the result * callback: async (query) => {} * }); * * const result = await get.account(); * * const result = await get.account.with.email('mike@gmail.com'); * ``` */ const getSyntaxProxy = (config) => { const propertyValue = typeof config?.propertyValue === "undefined" ? {} : config.propertyValue; const shouldAllowChaining = config?.chaining ?? true; const createProxy = (path = [], targetProps, assign) => { let target; if (assign) target = { ...targetProps }; else { target = () => void 0; target(); delete target.name; } return new Proxy(target, { apply(_, __, args) { let value = args[0]; const options = args[1]; if (typeof value === "undefined") value = propertyValue; else { const shouldUseParentSymbols = Boolean(globalThis.IN_RONIN_QUERY); value = mutateStructure(value, (inner) => { const serialized = serializeValue(inner, config?.replacer); if (shouldUseParentSymbols && typeof serialized === "string") return serialized.replaceAll(QUERY_SYMBOLS.FIELD, QUERY_SYMBOLS.FIELD_PARENT); return serialized; }); } const structure = { ...targetProps }; const pathParts = config?.root ? [config.root, ...path] : path; setProperty(structure, pathParts.length > 0 ? pathParts.join(".") : ".", value); if (globalThis.IN_RONIN_BATCH || !config?.callback) { const newPath = path.slice(0, -1); const details = { ...structure }; if (options) details.options = options; return shouldAllowChaining ? createProxy(newPath, details, true) : details; } return config.callback(structure, options); }, get(target$1, nextProp, receiver) { if (Object.hasOwn(target$1, nextProp)) return Reflect.get(target$1, nextProp, receiver); if (nextProp === "toJSON") return targetProps; return createProxy(path.concat([nextProp]), targetProps); } }); }; return createProxy(); }; /** * Obtains a list of queries from a function by wrapping the queries into a context. * * @param operations - A function that contains multiple query functions. * * @returns A list of queries and their respective options. * * ### Usage * ```typescript * const queries = getBatchProxy(() => [ * get.accounts(), * get.account.with.email('mike@gmail.com') * ]); * ``` */ const getBatchProxy = (operations) => { let queries = []; globalThis.IN_RONIN_BATCH = true; try { queries = operations(); } finally { globalThis.IN_RONIN_BATCH = false; } return queries.map((details) => { if (!isPlainObject(details)) return { structure: details }; const item = { structure: details[QUERY_SYMBOLS.QUERY] }; if ("options" in details) item.options = details.options; return item; }); }; /** * Serializes a provided value to ensure that the final structure can be sent over the * network and/or passed to the query compiler. * * For example, `Date` objects will be converted into ISO strings. * * @param defaultValue - The value to serialize. * @param replacer - A function that should be used to serialize nested values. * * @returns The serialized value. */ const serializeValue = (defaultValue, replacer) => { let value = defaultValue; if (typeof value === "undefined") return value; if (typeof value === "function") { const ORIGINAL_IN_RONIN_BATCH = globalThis.IN_RONIN_BATCH; globalThis.IN_RONIN_BATCH = true; const fieldProxy = new Proxy({}, { get(_target, property) { const name = property.toString(); return { [QUERY_SYMBOLS.EXPRESSION]: `${QUERY_SYMBOLS.FIELD}${name}` }; } }); try { const ORIGINAL_IN_RONIN_QUERY = globalThis.IN_RONIN_QUERY; globalThis.IN_RONIN_QUERY = true; value = value(fieldProxy); globalThis.IN_RONIN_QUERY = ORIGINAL_IN_RONIN_QUERY; } finally { globalThis.IN_RONIN_BATCH = ORIGINAL_IN_RONIN_BATCH; } } if (replacer) { const replacedValue = replacer(value); if (typeof replacedValue !== "undefined") return replacedValue; } return JSON.parse(JSON.stringify(value)); }; //#endregion export { getSyntaxProxy as n, getBatchProxy as t };