UNPKG

@proofkit/fmodata

Version:

FileMaker OData API client

305 lines (304 loc) 10.1 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { needsFieldQuoting } from "../client/builders/select-utils.js"; import { ColumnFunction, isColumnFunction, isColumn } from "./column.js"; class FilterExpression { // biome-ignore lint/suspicious/noExplicitAny: Operands can be Column, FilterExpression, or any value type constructor(operator, operands) { __publicField(this, "operator"); // biome-ignore lint/suspicious/noExplicitAny: Operands can be Column, FilterExpression, or any value type __publicField(this, "operands"); this.operator = operator; this.operands = operands; } /** * Convert this expression to OData filter syntax. * @internal Used by QueryBuilder */ toODataFilter(useEntityIds) { switch (this.operator) { // Comparison operators case "eq": return this._binaryOp("eq", useEntityIds); case "ne": return this._binaryOp("ne", useEntityIds); case "gt": return this._binaryOp("gt", useEntityIds); case "gte": return this._binaryOp("ge", useEntityIds); case "lt": return this._binaryOp("lt", useEntityIds); case "lte": return this._binaryOp("le", useEntityIds); case "in": return this._inOp(useEntityIds); case "notIn": return this._notInOp(useEntityIds); // String operators case "contains": return this._functionOp("contains", useEntityIds); case "startsWith": return this._functionOp("startswith", useEntityIds); case "endsWith": return this._functionOp("endswith", useEntityIds); case "matchesPattern": return this._functionOp("matchesPattern", useEntityIds); // Null checks case "isNull": return this._isNullOp(useEntityIds); case "isNotNull": return this._isNotNullOp(useEntityIds); // Logical operators case "and": return this._logicalOp("and", useEntityIds); case "or": return this._logicalOp("or", useEntityIds); case "not": return this._notOp(useEntityIds); default: throw new Error(`Unknown operator: ${this.operator}`); } } _binaryOp(op, useEntityIds) { const [left, right] = this.operands; let columnForValue; if (isColumn(left) && !isColumn(right)) { columnForValue = left; } else if (isColumn(right) && !isColumn(left)) { columnForValue = right; } else { columnForValue = void 0; } const leftStr = this._operandToString(left, useEntityIds, columnForValue); const rightStr = this._operandToString(right, useEntityIds, columnForValue); return `${leftStr} ${op} ${rightStr}`; } _functionOp(fnName, useEntityIds) { const [column, value] = this.operands; const columnInstance = isColumn(column) ? column : void 0; const columnStr = this._operandToString(column, useEntityIds); const valueStr = this._operandToString(value, useEntityIds, columnInstance); return `${fnName}(${columnStr}, ${valueStr})`; } _inOp(useEntityIds) { const [column, values] = this.operands; const columnInstance = isColumn(column) ? column : void 0; const columnStr = this._operandToString(column, useEntityIds); const valuesStr = values.map((v) => this._operandToString(v, useEntityIds, columnInstance)).join(", "); return `${columnStr} in (${valuesStr})`; } _notInOp(useEntityIds) { const [column, values] = this.operands; const columnInstance = isColumn(column) ? column : void 0; const columnStr = this._operandToString(column, useEntityIds); const valuesStr = values.map((v) => this._operandToString(v, useEntityIds, columnInstance)).join(", "); return `not (${columnStr} in (${valuesStr}))`; } _isNullOp(useEntityIds) { const [column] = this.operands; const columnStr = this._operandToString(column, useEntityIds); return `${columnStr} eq null`; } _isNotNullOp(useEntityIds) { const [column] = this.operands; const columnStr = this._operandToString(column, useEntityIds); return `${columnStr} ne null`; } _logicalOp(op, useEntityIds) { const expressions = this.operands.map((expr) => { if (expr instanceof FilterExpression) { const innerExpr = expr.toODataFilter(useEntityIds); if (expr.operator === "and" || expr.operator === "or") { return `(${innerExpr})`; } return innerExpr; } throw new Error("Logical operators require FilterExpression operands"); }); return expressions.join(` ${op} `); } _notOp(useEntityIds) { const [expr] = this.operands; if (expr instanceof FilterExpression) { return `not (${expr.toODataFilter(useEntityIds)})`; } throw new Error("NOT operator requires a FilterExpression operand"); } _formatTemporalValue(value, fieldType) { if (!(value instanceof Date)) { return String(value); } if (fieldType === "date") { return value.toISOString().slice(0, 10); } if (fieldType === "time") { return value.toISOString().slice(11, 19); } return value.toISOString(); } _operandToString(operand, useEntityIds, column) { var _a; if (isColumnFunction(operand)) { return operand.toFilterString(useEntityIds); } if (isColumn(operand)) { const fieldIdentifier = operand.getFieldIdentifier(useEntityIds); return needsFieldQuoting(fieldIdentifier) ? `"${fieldIdentifier}"` : fieldIdentifier; } let value = operand; if (column == null ? void 0 : column.inputValidator) { try { const result = column.inputValidator["~standard"].validate(value); if (result instanceof Promise) { value = operand; } else if ("issues" in result && result.issues) { value = operand; } else if ("value" in result) { value = result.value; } } catch (_error) { value = operand; } } const ft = column == null ? void 0 : column.fieldType; if (ft === "date" || ft === "time" || ft === "timestamp") { return this._formatTemporalValue(value, ft); } if (typeof value === "string") { return `'${value.replace(/'/g, "''")}'`; } if (value === null || value === void 0) { return "null"; } if (value instanceof Date) { return value.toISOString(); } if (typeof value === "object") { const valueType = ((_a = value == null ? void 0 : value.constructor) == null ? void 0 : _a.name) ?? "Object"; throw new Error( `Unsupported filter operand: received ${valueType}. Pass a table column or a primitive filter value.` ); } return String(value); } } function eq(column, value) { return new FilterExpression("eq", [column, value]); } function ne(column, value) { return new FilterExpression("ne", [column, value]); } function gt(column, value) { return new FilterExpression("gt", [column, value]); } function gte(column, value) { return new FilterExpression("gte", [column, value]); } function lt(column, value) { return new FilterExpression("lt", [column, value]); } function lte(column, value) { return new FilterExpression("lte", [column, value]); } function contains(column, value) { return new FilterExpression("contains", [column, value]); } function startsWith(column, value) { return new FilterExpression("startsWith", [column, value]); } function endsWith(column, value) { return new FilterExpression("endsWith", [column, value]); } function matchesPattern(column, pattern) { return new FilterExpression("matchesPattern", [column, pattern]); } function tolower(column) { return new ColumnFunction("tolower", column); } function toupper(column) { return new ColumnFunction("toupper", column); } function trim(column) { return new ColumnFunction("trim", column); } function inArray(column, values) { return new FilterExpression("in", [column, values]); } function notInArray(column, values) { return new FilterExpression("notIn", [column, values]); } function isNull(column) { return new FilterExpression("isNull", [column]); } function isNotNull(column) { return new FilterExpression("isNotNull", [column]); } function and(...expressions) { if (expressions.length === 0) { throw new Error("AND operator requires at least one expression"); } if (expressions.length === 1 && expressions[0] !== void 0) { return expressions[0]; } return new FilterExpression("and", expressions); } function or(...expressions) { if (expressions.length === 0) { throw new Error("OR operator requires at least one expression"); } if (expressions.length === 1 && expressions[0] !== void 0) { return expressions[0]; } return new FilterExpression("or", expressions); } function not(expression) { return new FilterExpression("not", [expression]); } class OrderByExpression { // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration constructor(column, direction) { // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any Column configuration __publicField(this, "column"); __publicField(this, "direction"); this.column = column; this.direction = direction; } } function isOrderByExpression(value) { return value instanceof OrderByExpression; } function asc(column) { return new OrderByExpression(column, "asc"); } function desc(column) { return new OrderByExpression(column, "desc"); } export { FilterExpression, OrderByExpression, and, asc, contains, desc, endsWith, eq, gt, gte, inArray, isNotNull, isNull, isOrderByExpression, lt, lte, matchesPattern, ne, not, notInArray, or, startsWith, tolower, toupper, trim }; //# sourceMappingURL=operators.js.map