UNPKG

fql-toolkit

Version:
160 lines 6.19 kB
import FQLQueryBuilder from './builders.js'; import FQLError from './errors.js'; import { buildCondition, mergeConditions } from './conditions.js'; // --------------------------------------------------------------------------- // FormQuery // --------------------------------------------------------------------------- /** * A chainable query builder for case (record) operations on a specific form. * Returned by `client.form('name').labels()` or `.with()`. * * @example * await client.form('customers').labels('name', 'email').with('age', '>', 18).get(); * await client.form('customers').with('name', '=', 'John').remove(); * await client.form('customers').with('name', '=', 'John').modify({ name: 'Jane', email: 'jane@example.com', age: 31 }); */ class FormQuery { constructor(formName, httpClient) { this._formName = formName; this._http = httpClient; this._fields = []; this._conditions = []; } /** * Specifies which fields to return. * May be called multiple times; fields accumulate. */ labels(...fields) { this._fields.push(...fields.flat()); return this; } /** * Adds a filter condition. * Multiple calls are combined with AND. * * @param field - Field path, e.g. `'age'` or `'owner.name'` * @param operator - One of: `=` `!=` `<>` `<` `>` `<=` `>=` * @param value - Value to compare against */ with(field, operator, value) { this._conditions.push(buildCondition(field, operator, value)); return this; } _condition() { return mergeConditions(this._conditions); } /** Executes the query and returns matching records. */ async get() { const query = FQLQueryBuilder.buildGetCaseQuery(this._formName, this._fields, this._condition()); return this._http.executeFQL(query); } /** * Modifies all records matching the current conditions. * * Internally this method: * 1. Fetches matching records to obtain their `fql_token`(s). * 2. Calls `modify case` for each record. * * ⚠️ Values must be provided in the same order as the form's field definitions. * Include ALL fields, not just the ones changing. * * @param newValues - `{ fieldName: newValue, ... }` in form-field order */ async modify(newValues = {}) { if (this._conditions.length === 0) { throw new FQLError('modify() requires at least one .with() condition'); } const getQuery = FQLQueryBuilder.buildGetCaseQuery(this._formName, [], this._condition()); const getResult = await this._http.executeFQL(getQuery); if (!getResult.ok) return getResult; const fqlToken = getResult.fqlToken; if (!fqlToken) return getResult; const values = Object.values(newValues); const modifyQuery = FQLQueryBuilder.buildModifyCaseQuery(this._formName, values); return this._http.executeFQL(modifyQuery, fqlToken); } /** * Removes all records matching the current conditions. * At least one `.with()` condition is required. * * Internally this method: * 1. Fetches matching records to obtain their `fql_token`. * 2. Calls `remove case` for the matched record using its token. */ async remove() { if (this._conditions.length === 0) { throw new FQLError('remove() requires at least one .with() condition'); } const getQuery = FQLQueryBuilder.buildGetCaseQuery(this._formName, [], this._condition()); const getResult = await this._http.executeFQL(getQuery); if (!getResult.ok) return getResult; const fqlToken = getResult.fqlToken; if (!fqlToken) return getResult; const removeQuery = FQLQueryBuilder.buildRemoveCaseQuery(this._formName); return this._http.executeFQL(removeQuery, fqlToken); } } // --------------------------------------------------------------------------- // FormContext // --------------------------------------------------------------------------- /** * Entry point for case (record) operations on a single form. * Accessed via `client.form('formName')`. * * @example * await client.form('customers').create({ name: 'John', email: 'john@example.com', age: 30 }); * await client.form('customers').labels('name', 'email').with('age', '>', 18).get(); * await client.form('customers').with('name', '=', 'John').remove(); * await client.form('customers').with('name', '=', 'John').modify({ name: 'Jane', email: 'jane@example.com', age: 31 }); */ export default class FormContext { constructor(formName, httpClient) { if (!formName || typeof formName !== 'string') { throw new FQLError('Form name is required and must be a string'); } this._formName = formName; this._http = httpClient; } /** * Inserts a new record. * Values are taken from the object in insertion order and must match * the form's field definition order. */ async create(data = {}) { const values = Object.values(data); if (values.length === 0) { throw new FQLError('create() requires at least one field value'); } const query = FQLQueryBuilder.buildCreateNewQuery(this._formName, values); return this._http.executeFQL(query); } /** * Fetches all records from the form without any conditions or label filters. * * @example * await client.form('Boards').get(); */ get() { const code = `get ${this._formName}`; return this._http.executeFQL(code); } /** * Starts a query and specifies which fields to return. * @returns {FormQuery} */ labels(...fields) { return new FormQuery(this._formName, this._http).labels(...fields); } /** * Starts a query with a filter condition. * @returns {FormQuery} */ with(field, operator, value) { return new FormQuery(this._formName, this._http).with(field, operator, value); } } //# sourceMappingURL=FormContext.js.map