UNPKG

@uttori/storage-provider-json-memory

Version:
76 lines (67 loc) 2.38 kB
import parseQueryToFilterFunctions from './parse-query-filter-functions.js'; import validateQuery from './validate-query.js'; import fyShuffle from './fisher-yates-shuffle.js'; let debug = (..._) => {}; /* c8 ignore next 2 */ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call try { const { default: d } = await import('debug'); debug = d('Uttori.StorageProvider.JSON.QueryTools'); } catch {} /** * Processes a query string. * @param {string} query - The SQL-like query to parse. * @param {import('./storage-provider.js').UttoriDocument[]} objects - An array of object to search within. * @returns {import('./storage-provider.js').UttoriDocument[]|number} Returns an array of all matched documents, or a count. * @example * ```js * processQuery('SELECT name FROM table WHERE age > 1 ORDER BY RANDOM LIMIT 3', [{ ... }, ...]); * ➜ [{ ... }, ...] * ``` */ const processQuery = (query, objects) => { debug('Processing Query:', query); // Filter const { fields, where, order, limit } = validateQuery(query); debug('Found fields:', fields); debug('Found where:', where); debug('Found order:', order); debug('Found limit:', limit); const whereFunctions = parseQueryToFilterFunctions(where); /** @type {import('./storage-provider.js').UttoriDocument[]} */ const filtered = objects.filter(whereFunctions); // Short circuit when we only want the counts. if (fields.includes('COUNT(*)')) { return filtered.length; } // Sort / Order let output; if (order[0].prop === 'RANDOM') { output = fyShuffle(filtered); } else { output = filtered.sort((a, b) => { for (const value of order) { const direction = value.sort === 'ASC' ? 1 : -1; if (a[value.prop] < b[value.prop]) return -1 * direction; if (a[value.prop] > b[value.prop]) return 1 * direction; } return 0; }); } // Limit if (limit > 0) { output = output.slice(0, limit); } // Select if (!fields.includes('*')) { output = output.map((item) => { /** @type {import('./storage-provider.js').UttoriDocument} */ const newItem = {}; fields.forEach((field) => { if (Object.hasOwn(item, field)) { newItem[field] = item[field]; } }); return newItem; }); } return output; }; export default processQuery;