UNPKG

groq-builder

Version:

A **schema-aware**, strongly-typed GROQ query builder. It enables you to build GROQ queries using **auto-completion**, **type-checking**, and **runtime validation**.

103 lines 4.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../types/utils"); const groq_builder_1 = require("../groq-builder"); const validate_utils_1 = require("./validate-utils"); const conditional_types_1 = require("./conditional-types"); const simple_validation_1 = require("../validation/simple-validation"); groq_builder_1.GroqBuilder.implement({ project(projectionMapArg, ...__projectionMapTypeMismatchErrors) { // Retrieve the projectionMap: let projectionMap; if (typeof projectionMapArg === "function") { projectionMap = projectionMapArg(this.root); } else { projectionMap = projectionMapArg; } const keys = Object.keys(projectionMap); // Compile query from projection values: const fields = keys .map((key) => { const fieldConfig = projectionMap[key]; return normalizeProjectionField(key, fieldConfig); }) .filter(utils_1.notNull); if (this.internal.options.validationRequired) { // Validate that we have provided validation functions for all fields: const invalidFields = fields.filter((f) => !f.parser); if (invalidFields.length) { throw new TypeError("[groq-builder] Because 'validationRequired' is enabled, " + "every field must have validation (like `q.string()`), " + "but the following fields are missing it: " + `${invalidFields.map((f) => `"${f.key}"`)}`); } } const queries = fields.map((v) => v.query); const { newLine, space } = this.indentation; const newQuery = ` {${newLine}${space}${queries.join(`,${newLine}${space}`)}${newLine}}`; // Create a combined parser: const projectionParser = createProjectionParser(fields); return this.chain(newQuery, projectionParser); }, }); function normalizeProjectionField(key, fieldConfig) { // Analyze the field configuration: const value = fieldConfig; if (value instanceof groq_builder_1.GroqBuilder) { const query = (0, conditional_types_1.isConditional)(key) // Conditionals can ignore the key ? value.query : key === value.query // Use shorthand syntax ? key : `"${key}": ${value.query}`; return { key, query, parser: value.parser }; } else if (typeof value === "string") { const query = key === value ? key : `"${key}": ${value}`; return { key, query, parser: null }; } else if (typeof value === "boolean") { if (value === false) return null; // 'false' will be excluded from the results return { key, query: key, parser: null }; } else if (Array.isArray(value)) { const [projectionKey, parser] = value; const query = key === projectionKey ? key : `"${key}": ${projectionKey}`; return { key, query, parser: (0, validate_utils_1.normalizeValidationFunction)(parser), }; } else if ((0, validate_utils_1.isParser)(value)) { return { key, query: key, parser: (0, validate_utils_1.normalizeValidationFunction)(value), }; } else { throw new Error(`Unexpected value for projection key "${key}": "${typeof value}"`); } } function createProjectionParser(fields) { if (!fields.some((f) => f.parser)) { // No nested parsers! return null; } // Parse all normal fields: const normalFields = fields.filter((f) => !(0, conditional_types_1.isConditional)(f.key)); const objectShape = Object.fromEntries(normalFields.map((f) => [f.key, f.parser])); const objectParser = (0, simple_validation_1.simpleObjectParser)(objectShape); // Parse all conditional fields: const conditionalFields = fields.filter((f) => (0, conditional_types_1.isConditional)(f.key)); const conditionalParsers = conditionalFields .map((f) => f.parser) .filter(utils_1.notNull); // Combine normal and conditional parsers: const combinedParser = (0, simple_validation_1.combineObjectParsers)(objectParser, ...conditionalParsers); // Finally, transparently handle arrays or objects: return (0, simple_validation_1.maybeArrayParser)(combinedParser); } //# sourceMappingURL=project.js.map