{"version":3,"file":"functions.cjs","sources":["../../../src/query/functions.ts"],"sourcesContent":["import type { AllowedFunctionName } from \"./schema.js\"\n\n/**\n * Type for function implementations\n */\ntype FunctionImplementation = (arg: unknown) => unknown\n\n/**\n * Converts a string to uppercase\n */\nfunction upperFunction(arg: unknown): string {\n  if (typeof arg !== `string`) {\n    throw new Error(`UPPER function expects a string argument`)\n  }\n  return arg.toUpperCase()\n}\n\n/**\n * Converts a string to lowercase\n */\nfunction lowerFunction(arg: unknown): string {\n  if (typeof arg !== `string`) {\n    throw new Error(`LOWER function expects a string argument`)\n  }\n  return arg.toLowerCase()\n}\n\n/**\n * Returns the length of a string or array\n */\nfunction lengthFunction(arg: unknown): number {\n  if (typeof arg === `string` || Array.isArray(arg)) {\n    return arg.length\n  }\n\n  throw new Error(`LENGTH function expects a string or array argument`)\n}\n\n/**\n * Concatenates multiple strings\n */\nfunction concatFunction(arg: unknown): string {\n  if (!Array.isArray(arg)) {\n    throw new Error(`CONCAT function expects an array of string arguments`)\n  }\n\n  if (arg.length === 0) {\n    return ``\n  }\n\n  // Check that all arguments are strings\n  for (let i = 0; i < arg.length; i++) {\n    if (arg[i] !== null && arg[i] !== undefined && typeof arg[i] !== `string`) {\n      throw new Error(\n        `CONCAT function expects all arguments to be strings, but argument at position ${i} is ${typeof arg[i]}`\n      )\n    }\n  }\n\n  // Concatenate strings, treating null and undefined as empty strings\n  return arg\n    .map((str) => (str === null || str === undefined ? `` : str))\n    .join(``)\n}\n\n/**\n * Returns the first non-null, non-undefined value from an array\n */\nfunction coalesceFunction(arg: unknown): unknown {\n  if (!Array.isArray(arg)) {\n    throw new Error(`COALESCE function expects an array of arguments`)\n  }\n\n  if (arg.length === 0) {\n    return null\n  }\n\n  // Return the first non-null, non-undefined value\n  for (const value of arg) {\n    if (value !== null && value !== undefined) {\n      return value\n    }\n  }\n\n  // If all values were null or undefined, return null\n  return null\n}\n\n/**\n * Creates or converts a value to a Date object\n */\nfunction dateFunction(arg: unknown): Date | null {\n  // If the argument is already a Date, return it\n  if (arg instanceof Date) {\n    return arg\n  }\n\n  // If the argument is null or undefined, return null\n  if (arg === null || arg === undefined) {\n    return null\n  }\n\n  // Handle string and number conversions\n  if (typeof arg === `string` || typeof arg === `number`) {\n    const date = new Date(arg)\n\n    // Check if the date is valid\n    if (isNaN(date.getTime())) {\n      throw new Error(`DATE function could not parse \"${arg}\" as a valid date`)\n    }\n\n    return date\n  }\n\n  throw new Error(`DATE function expects a string, number, or Date argument`)\n}\n\n/**\n * Extracts a value from a JSON string or object using a path.\n * Similar to PostgreSQL's json_extract_path function.\n *\n * Usage: JSON_EXTRACT([jsonInput, 'path', 'to', 'property'])\n * Example: JSON_EXTRACT(['{\"user\": {\"name\": \"John\"}}', 'user', 'name']) returns \"John\"\n */\nfunction jsonExtractFunction(arg: unknown): unknown {\n  if (!Array.isArray(arg) || arg.length < 1) {\n    throw new Error(\n      `JSON_EXTRACT function expects an array with at least one element [jsonInput, ...pathElements]`\n    )\n  }\n\n  const [jsonInput, ...pathElements] = arg\n\n  // Handle null or undefined input\n  if (jsonInput === null || jsonInput === undefined) {\n    return null\n  }\n\n  // Parse JSON if it's a string\n  let jsonData: any\n\n  if (typeof jsonInput === `string`) {\n    try {\n      jsonData = JSON.parse(jsonInput)\n    } catch (error) {\n      throw new Error(\n        `JSON_EXTRACT function could not parse JSON string: ${error instanceof Error ? error.message : String(error)}`\n      )\n    }\n  } else if (typeof jsonInput === `object`) {\n    // If already an object, use it directly\n    jsonData = jsonInput\n  } else {\n    throw new Error(\n      `JSON_EXTRACT function expects a JSON string or object as the first argument`\n    )\n  }\n\n  // If no path elements, return the parsed JSON\n  if (pathElements.length === 0) {\n    return jsonData\n  }\n\n  // Navigate through the path elements\n  let current = jsonData\n\n  for (let i = 0; i < pathElements.length; i++) {\n    const pathElement = pathElements[i]\n\n    // Path elements should be strings\n    if (typeof pathElement !== `string`) {\n      throw new Error(\n        `JSON_EXTRACT function expects path elements to be strings, but element at position ${i + 1} is ${typeof pathElement}`\n      )\n    }\n\n    // If current node is null or undefined, or not an object, we can't navigate further\n    if (\n      current === null ||\n      current === undefined ||\n      typeof current !== `object`\n    ) {\n      return null\n    }\n\n    // Access property\n    current = current[pathElement]\n  }\n\n  // Return null instead of undefined for consistency\n  return current === undefined ? null : current\n}\n\n/**\n * Placeholder function for ORDER_INDEX\n * This function doesn't do anything when called directly, as the actual index\n * is provided by the orderBy operator during query execution.\n * The argument can be 'numeric', 'fractional', or any truthy value (defaults to 'numeric')\n */\nfunction orderIndexFunction(arg: unknown): null {\n  // This is just a placeholder - the actual index is provided by the orderBy operator\n  // The function validates that the argument is one of the expected values\n  if (\n    arg !== `numeric` &&\n    arg !== `fractional` &&\n    arg !== true &&\n    arg !== `default`\n  ) {\n    throw new Error(\n      `ORDER_INDEX function expects \"numeric\", \"fractional\", \"default\", or true as argument`\n    )\n  }\n  return null\n}\n\n/**\n * Map of function names to their implementations\n */\nconst functionImplementations: Record<\n  AllowedFunctionName,\n  FunctionImplementation\n> = {\n  // Map function names to their implementation functions\n  DATE: dateFunction,\n  JSON_EXTRACT: jsonExtractFunction,\n  JSON_EXTRACT_PATH: jsonExtractFunction, // Alias for JSON_EXTRACT\n  UPPER: upperFunction,\n  LOWER: lowerFunction,\n  COALESCE: coalesceFunction,\n  CONCAT: concatFunction,\n  LENGTH: lengthFunction,\n  ORDER_INDEX: orderIndexFunction,\n}\n\n/**\n * Evaluates a function call with the given name and arguments\n * @param functionName The name of the function to evaluate\n * @param arg The arguments to pass to the function\n * @returns The result of the function call\n */\nexport function evaluateFunction(\n  functionName: AllowedFunctionName,\n  arg: unknown\n): unknown {\n  const implementation = functionImplementations[functionName] as\n    | FunctionImplementation\n    | undefined // Double check that the implementation is defined\n\n  if (!implementation) {\n    throw new Error(`Unknown function: ${functionName}`)\n  }\n  return implementation(arg)\n}\n\n/**\n * Determines if an object is a function call\n * @param obj The object to check\n * @returns True if the object is a function call, false otherwise\n */\nexport function isFunctionCall(obj: unknown): boolean {\n  if (!obj || typeof obj !== `object`) {\n    return false\n  }\n\n  const keys = Object.keys(obj)\n  if (keys.length !== 1) {\n    return false\n  }\n\n  const functionName = keys[0] as string\n\n  // Check if the key is one of the allowed function names\n  return Object.keys(functionImplementations).includes(functionName)\n}\n\n/**\n * Extracts the function name and argument from a function call object.\n */\nexport function extractFunctionCall(obj: Record<string, unknown>): {\n  functionName: AllowedFunctionName\n  argument: unknown\n} {\n  const keys = Object.keys(obj)\n  if (keys.length !== 1) {\n    throw new Error(`Invalid function call: object must have exactly one key`)\n  }\n\n  const functionName = keys[0] as AllowedFunctionName\n  if (!Object.keys(functionImplementations).includes(functionName)) {\n    throw new Error(`Invalid function name: ${functionName}`)\n  }\n\n  return {\n    functionName,\n    argument: obj[functionName],\n  }\n}\n"],"names":[],"mappings":";;AAUA,SAAS,cAAc,KAAsB;AACvC,MAAA,OAAO,QAAQ,UAAU;AACrB,UAAA,IAAI,MAAM,0CAA0C;AAAA,EAAA;AAE5D,SAAO,IAAI,YAAY;AACzB;AAKA,SAAS,cAAc,KAAsB;AACvC,MAAA,OAAO,QAAQ,UAAU;AACrB,UAAA,IAAI,MAAM,0CAA0C;AAAA,EAAA;AAE5D,SAAO,IAAI,YAAY;AACzB;AAKA,SAAS,eAAe,KAAsB;AAC5C,MAAI,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACjD,WAAO,IAAI;AAAA,EAAA;AAGP,QAAA,IAAI,MAAM,oDAAoD;AACtE;AAKA,SAAS,eAAe,KAAsB;AAC5C,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACjB,UAAA,IAAI,MAAM,sDAAsD;AAAA,EAAA;AAGpE,MAAA,IAAI,WAAW,GAAG;AACb,WAAA;AAAA,EAAA;AAIT,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,QAAI,IAAI,CAAC,MAAM,QAAQ,IAAI,CAAC,MAAM,UAAa,OAAO,IAAI,CAAC,MAAM,UAAU;AACzE,YAAM,IAAI;AAAA,QACR,iFAAiF,CAAC,OAAO,OAAO,IAAI,CAAC,CAAC;AAAA,MACxG;AAAA,IAAA;AAAA,EACF;AAIF,SAAO,IACJ,IAAI,CAAC,QAAS,QAAQ,QAAQ,QAAQ,SAAY,KAAK,GAAI,EAC3D,KAAK,EAAE;AACZ;AAKA,SAAS,iBAAiB,KAAuB;AAC/C,MAAI,CAAC,MAAM,QAAQ,GAAG,GAAG;AACjB,UAAA,IAAI,MAAM,iDAAiD;AAAA,EAAA;AAG/D,MAAA,IAAI,WAAW,GAAG;AACb,WAAA;AAAA,EAAA;AAIT,aAAW,SAAS,KAAK;AACnB,QAAA,UAAU,QAAQ,UAAU,QAAW;AAClC,aAAA;AAAA,IAAA;AAAA,EACT;AAIK,SAAA;AACT;AAKA,SAAS,aAAa,KAA2B;AAE/C,MAAI,eAAe,MAAM;AAChB,WAAA;AAAA,EAAA;AAIL,MAAA,QAAQ,QAAQ,QAAQ,QAAW;AAC9B,WAAA;AAAA,EAAA;AAIT,MAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ,UAAU;AAChD,UAAA,OAAO,IAAI,KAAK,GAAG;AAGzB,QAAI,MAAM,KAAK,QAAQ,CAAC,GAAG;AACzB,YAAM,IAAI,MAAM,kCAAkC,GAAG,mBAAmB;AAAA,IAAA;AAGnE,WAAA;AAAA,EAAA;AAGH,QAAA,IAAI,MAAM,0DAA0D;AAC5E;AASA,SAAS,oBAAoB,KAAuB;AAClD,MAAI,CAAC,MAAM,QAAQ,GAAG,KAAK,IAAI,SAAS,GAAG;AACzC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAGF,QAAM,CAAC,WAAW,GAAG,YAAY,IAAI;AAGjC,MAAA,cAAc,QAAQ,cAAc,QAAW;AAC1C,WAAA;AAAA,EAAA;AAIL,MAAA;AAEA,MAAA,OAAO,cAAc,UAAU;AAC7B,QAAA;AACS,iBAAA,KAAK,MAAM,SAAS;AAAA,aACxB,OAAO;AACd,YAAM,IAAI;AAAA,QACR,sDAAsD,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAC9G;AAAA,IAAA;AAAA,EAEJ,WAAW,OAAO,cAAc,UAAU;AAE7B,eAAA;AAAA,EAAA,OACN;AACL,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAIE,MAAA,aAAa,WAAW,GAAG;AACtB,WAAA;AAAA,EAAA;AAIT,MAAI,UAAU;AAEd,WAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AACtC,UAAA,cAAc,aAAa,CAAC;AAG9B,QAAA,OAAO,gBAAgB,UAAU;AACnC,YAAM,IAAI;AAAA,QACR,sFAAsF,IAAI,CAAC,OAAO,OAAO,WAAW;AAAA,MACtH;AAAA,IAAA;AAIF,QACE,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,UACnB;AACO,aAAA;AAAA,IAAA;AAIT,cAAU,QAAQ,WAAW;AAAA,EAAA;AAIxB,SAAA,YAAY,SAAY,OAAO;AACxC;AAQA,SAAS,mBAAmB,KAAoB;AAG9C,MACE,QAAQ,aACR,QAAQ,gBACR,QAAQ,QACR,QAAQ,WACR;AACA,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAEK,SAAA;AACT;AAKA,MAAM,0BAGF;AAAA;AAAA,EAEF,MAAM;AAAA,EACN,cAAc;AAAA,EACd,mBAAmB;AAAA;AAAA,EACnB,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,aAAa;AACf;AAQgB,SAAA,iBACd,cACA,KACS;AACH,QAAA,iBAAiB,wBAAwB,YAAY;AAI3D,MAAI,CAAC,gBAAgB;AACnB,UAAM,IAAI,MAAM,qBAAqB,YAAY,EAAE;AAAA,EAAA;AAErD,SAAO,eAAe,GAAG;AAC3B;AAOO,SAAS,eAAe,KAAuB;AACpD,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AAC5B,WAAA;AAAA,EAAA;AAGH,QAAA,OAAO,OAAO,KAAK,GAAG;AACxB,MAAA,KAAK,WAAW,GAAG;AACd,WAAA;AAAA,EAAA;AAGH,QAAA,eAAe,KAAK,CAAC;AAG3B,SAAO,OAAO,KAAK,uBAAuB,EAAE,SAAS,YAAY;AACnE;;;"}