UNPKG

puddysql

Version:

🍮 Powerful SQL toolkit for Node.js, built with flexibility and structure in mind. Easily manage SQLite3/PostgreSQL, advanced queries, smart tag systems, and full JSON-friendly filters.

1,132 lines (1,131 loc) 50.6 kB
export default PuddySqlQuery; /** * Defines the schema structure used to create or modify SQL tables programmatically. * * Each entry in the array represents a single column definition as a 4-item tuple: * [columnName, columnType, columnOptions, columnMeta] * * - `columnName` (`string`) – The name of the column (e.g., `"id"`, `"username"`). * - `columnType` (`string`) – The SQL data type (e.g., `"TEXT"`, `"INTEGER"`, `"BOOLEAN"`). * - `columnOptions` (`string`) – SQL options like `NOT NULL`, `PRIMARY KEY`, `DEFAULT`, etc. * - `columnMeta` (`any`) – Arbitrary metadata related to the column (e.g., for UI, descriptions, tags). */ export type SqlTableConfig = Array<[string, string, string, string]>; /** * Represents the result of a paginated SQL query to locate the exact position of a specific item. */ export type FindResult = { /** * - The current page number where the item is located (starting from 1). */ page: number; /** * - The total number of pages available in the dataset. */ pages: number; /** * - The total number of items in the dataset. */ total: number; /** * - The exact index position of the item in the entire dataset (starting from 0). */ position: number; /** * - The actual item found, if included in the result. */ item?: FreeObj | undefined; }; /** * - Tag group definition to build the clause from. */ export type TagCriteria = { /** * - SQL column name for tag data (defaults to `this.getColumnName()`). */ column?: string | undefined; /** * - Optional table name used (defaults to `this.defaultTableName`). */ tableName?: string | undefined; /** * - Whether wildcards are allowed in matching. */ allowWildcards?: boolean | undefined; /** * - Tag values or grouped OR conditions to include. */ include?: (string | string[])[] | undefined; }; /** * Represents the result of a paginated query. */ export type PaginationResult = { /** * - Array of items returned for the current page. */ items: any[]; /** * - Total number of available pages based on the query and per-page limit. */ totalPages: number; /** * - Total number of items matching the query without pagination. */ totalItems: number; }; /** * Represents a flexible select query input, allowing for different forms. */ export type SelectQuery = (string | string[] | { aliases?: Record<string, string>; values?: string[]; boost?: { alias?: string; value?: BoostValue[]; }; } | null); /** * - Parameter cache used to build the WHERE clause. */ export type Pcache = { /** * - Starting parameter index for SQL placeholders (e.g., `$1`, `$2`...). */ index?: number | undefined; /** * - Collected values for SQL query binding. */ values?: any[] | undefined; }; /** * An object type where keys can be strings, numbers, or symbols, and values can be any unknown type. * Useful for generic data containers where the structure is not strictly defined. */ export type FreeObj = Record<string | number | symbol, any>; /** * Represents conditions used in a SQL WHERE clause. */ export type WhereConditions = { /** * - Logical operator to combine conditions (`AND`/`OR`). Case-insensitive. * Only used when `conditions` is provided. */ group?: "AND" | "OR" | "and" | "or" | undefined; /** * - Array of grouped `WhereConditions` or `QueryGroup` entries. * Used for nesting logical clauses. */ conditions?: QueryGroup[] | undefined; /** * - Optional function name applied to the column (e.g., UPPER, LOWER). */ funcName?: string | null | undefined; /** * - Comparison operator (e.g., '=', 'LIKE', 'IN'). */ operator?: string | null | undefined; /** * - Value to compare against. */ value?: string | null | undefined; /** * - Custom function for value transformation (e.g., for SOUNDEX). */ valType?: string | null | undefined; /** * - Logical position indicator (e.g., 'left', 'right') for chaining. */ lPos?: "left" | "right" | null | undefined; /** * - Replacement operator, used to override the main one. */ newOp?: string | null | undefined; /** * - Name of the column to apply the condition on. */ column?: string | null | undefined; }; /** * Represents a flexible condition group used in dynamic SQL WHERE clause generation. * * A `QueryGroup` can take two forms: * * 1. **Single condition object** — represents a single `WhereConditions` instance: * ```js * { * column: 'name', * operator: '=', * value: 'pudding' * } * ``` * * 2. **Named group of conditions** — an object mapping condition names or keys * to individual `WhereConditions` objects: * ```js * { * searchByName: { * column: 'name', * operator: 'ILIKE', * value: '%fluttershy%' * }, * searchByType: { * column: 'type', * operator: '=', * value: 'pegasus' * } * } * ``` * * This structure allows dynamic grouping of multiple WHERE conditions * (useful for advanced filters, tag clauses, or scoped searches). */ export type QueryGroup = WhereConditions | Record<string, WhereConditions>; /** * Represents a boosting rule for weighted query ranking. */ export type BoostValue = { /** * - List of columns to apply the boost on. */ columns?: string[] | undefined; /** * - Operator used in the condition (e.g., '=', 'LIKE'). */ operator?: string | undefined; /** * - Value to match in the condition. */ value?: string | string[] | undefined; /** * - Weight factor to boost results matching the condition. */ weight?: number | undefined; }; /** * Each join object must contain: * - `table`: The name of the table to join. * - `compare`: The ON clause condition. * - `type` (optional): One of the supported JOIN types (e.g., 'left', 'inner'). Defaults to 'left'. */ export type JoinObj = { table: string; compare: string; type?: string; }; export type TableSettings = { name?: string | undefined; /** * - SELECT clause configuration. Can be simplified; complex expressions are auto-formatted. */ select?: SelectQuery | undefined; /** * - Optional JOIN table name. */ join?: string | null | undefined; /** * - Condition used to match JOIN tables. */ joinCompare?: string | null | undefined; /** * - Optional ORDER BY clause. */ order?: string | null | undefined; /** * - Primary key column name. */ id?: string | undefined; /** * - Optional secondary key column name. */ subId?: string | null | undefined; }; /** * Configuration settings for a SQL entity, defining how it should be queried and joined. */ export type Settings = { /** * - The default columns to select in a query (e.g., `"*"`, or `"id, name"`). */ select: string; /** * - The name of the main table or view. */ name: string; /** * - The primary key column name. */ id: string; /** * - Optional column used to match in JOIN conditions (e.g., `"main.id = sub.fk_id"`). */ joinCompare: string | null; /** * - Default column used to order results (e.g., `"created_at DESC"`). */ order: string | null; /** * - Secondary identifier column name (for composite keys or scoped tables). */ subId: string | null; /** * - SQL JOIN clause to apply (e.g., `"LEFT JOIN profiles ON users.id = profiles.user_id"`). */ join: string | null; }; /** * A function that takes a WhereConditions object and returns a modified WhereConditions object. * Typically used to append or transform SQL WHERE clauses. */ export type WhereConditionsFunc = (conditions: WhereConditions) => WhereConditions; /** * A map of condition identifiers to their associated transformation functions. * Each key represents a named SQL condition function. */ export type SqlConditions = Record<string, WhereConditionsFunc>; /** * Defines the schema structure used to create or modify SQL tables programmatically. * * Each entry in the array represents a single column definition as a 4-item tuple: * [columnName, columnType, columnOptions, columnMeta] * * - `columnName` (`string`) – The name of the column (e.g., `"id"`, `"username"`). * - `columnType` (`string`) – The SQL data type (e.g., `"TEXT"`, `"INTEGER"`, `"BOOLEAN"`). * - `columnOptions` (`string`) – SQL options like `NOT NULL`, `PRIMARY KEY`, `DEFAULT`, etc. * - `columnMeta` (`any`) – Arbitrary metadata related to the column (e.g., for UI, descriptions, tags). * * @typedef {Array<[string, string, string, string]>} SqlTableConfig */ /** * Represents the result of a paginated SQL query to locate the exact position of a specific item. * * @typedef {Object} FindResult * @property {number} page - The current page number where the item is located (starting from 1). * @property {number} pages - The total number of pages available in the dataset. * @property {number} total - The total number of items in the dataset. * @property {number} position - The exact index position of the item in the entire dataset (starting from 0). * @property {FreeObj} [item] - The actual item found, if included in the result. */ /** * Tag group definition used to build dynamic SQL clauses for tag filtering. * * @typedef {Object} TagCriteria - Tag group definition to build the clause from. * @property {string} [group.column] - SQL column name for tag data (defaults to `this.getColumnName()`). * @property {string} [group.tableName] - Optional table name used (defaults to `this.defaultTableName`). * @property {boolean} [group.allowWildcards=false] - Whether wildcards are allowed in matching. * @property {Array<string|string[]>} [group.include=[]] - Tag values or grouped OR conditions to include. */ /** * Represents the result of a paginated query. * * @typedef {Object} PaginationResult * @property {any[]} items - Array of items returned for the current page. * @property {number} totalPages - Total number of available pages based on the query and per-page limit. * @property {number} totalItems - Total number of items matching the query without pagination. */ /** * Represents a flexible select query input, allowing for different forms. * * @typedef {( * string | * string[] | * { * aliases?: Record<string, string>; // Mapping of display names to real column names. * values?: string[]; // List of column names to select. * boost?: { // Boost configuration for weighted ranking. * alias?: string; // The alias to associate with the boost configuration. * value?: BoostValue[]; // List of boost rules to apply. * }; * } | * null * )} SelectQuery */ /** * Parameter cache used to build the WHERE clause. * * @typedef {Object} Pcache - Parameter cache used to build the WHERE clause. * @property {number} [pCache.index=1] - Starting parameter index for SQL placeholders (e.g., `$1`, `$2`...). * @property {any[]} [pCache.values=[]] - Collected values for SQL query binding. */ /** * Represents a free-form object with unknown values and arbitrary keys. * * @typedef {Record<string | number | symbol, any>} FreeObj * * An object type where keys can be strings, numbers, or symbols, and values can be any unknown type. * Useful for generic data containers where the structure is not strictly defined. */ /** * Represents conditions used in a SQL WHERE clause. * * @typedef {Object} WhereConditions * @property {'OR'|'AND'|'or'|'and'} [group] - Logical operator to combine conditions (`AND`/`OR`). Case-insensitive. * Only used when `conditions` is provided. * @property {QueryGroup[]} [conditions] - Array of grouped `WhereConditions` or `QueryGroup` entries. * Used for nesting logical clauses. * * @property {string|null|undefined} [funcName] - Optional function name applied to the column (e.g., UPPER, LOWER). * @property {string|null|undefined} [operator] - Comparison operator (e.g., '=', 'LIKE', 'IN'). * @property {string|null|undefined} [value] - Value to compare against. * @property {string|null|undefined} [valType] - Custom function for value transformation (e.g., for SOUNDEX). * @property {'left'|'right'|null|undefined} [lPos] - Logical position indicator (e.g., 'left', 'right') for chaining. * @property {string|null|undefined} [newOp] - Replacement operator, used to override the main one. * @property {string|null|undefined} [column] - Name of the column to apply the condition on. */ /** * Represents a flexible condition group used in dynamic SQL WHERE clause generation. * * A `QueryGroup` can take two forms: * * 1. **Single condition object** — represents a single `WhereConditions` instance: * ```js * { * column: 'name', * operator: '=', * value: 'pudding' * } * ``` * * 2. **Named group of conditions** — an object mapping condition names or keys * to individual `WhereConditions` objects: * ```js * { * searchByName: { * column: 'name', * operator: 'ILIKE', * value: '%fluttershy%' * }, * searchByType: { * column: 'type', * operator: '=', * value: 'pegasus' * } * } * ``` * * This structure allows dynamic grouping of multiple WHERE conditions * (useful for advanced filters, tag clauses, or scoped searches). * * @typedef {WhereConditions | Record<string, WhereConditions>} QueryGroup */ /** * Represents a boosting rule for weighted query ranking. * * @typedef {Object} BoostValue * @property {string[]} [columns] - List of columns to apply the boost on. * @property {string} [operator='LIKE'] - Operator used in the condition (e.g., '=', 'LIKE'). * @property {string|string[]} [value] - Value to match in the condition. * @property {number} [weight=1] - Weight factor to boost results matching the condition. */ /** * Each join object must contain: * - `table`: The name of the table to join. * - `compare`: The ON clause condition. * - `type` (optional): One of the supported JOIN types (e.g., 'left', 'inner'). Defaults to 'left'. * * @typedef {{ table: string; compare: string; type?: string; }} JoinObj */ /** * @typedef {Object} TableSettings * @property {string} [name] * @property {SelectQuery} [select='*'] - SELECT clause configuration. Can be simplified; complex expressions are auto-formatted. * @property {string|null} [join=null] - Optional JOIN table name. * @property {string|null} [joinCompare='t.key = j.key'] - Condition used to match JOIN tables. * @property {string|null} [order=null] - Optional ORDER BY clause. * @property {string} [id='key'] - Primary key column name. * @property {string|null} [subId=null] - Optional secondary key column name. */ /** * Configuration settings for a SQL entity, defining how it should be queried and joined. * * @typedef {Object} Settings * @property {string} select - The default columns to select in a query (e.g., `"*"`, or `"id, name"`). * @property {string} name - The name of the main table or view. * @property {string} id - The primary key column name. * @property {string|null} joinCompare - Optional column used to match in JOIN conditions (e.g., `"main.id = sub.fk_id"`). * @property {string|null} order - Default column used to order results (e.g., `"created_at DESC"`). * @property {string|null} subId - Secondary identifier column name (for composite keys or scoped tables). * @property {string|null} join - SQL JOIN clause to apply (e.g., `"LEFT JOIN profiles ON users.id = profiles.user_id"`). */ /** * A function that takes a WhereConditions object and returns a modified WhereConditions object. * Typically used to append or transform SQL WHERE clauses. * * @typedef {(conditions: WhereConditions) => WhereConditions} WhereConditionsFunc */ /** * A map of condition identifiers to their associated transformation functions. * Each key represents a named SQL condition function. * * @typedef {Record<string, WhereConditionsFunc>} SqlConditions */ /** * TinySQLQuery is a queries operating system developed to operate in a specific table. */ declare class PuddySqlQuery { /** * Safely retrieves the internal database instance. * * This method ensures that the current internal `#db` is a valid instance of `PuddySqlEngine`. * If the internal value is invalid or was not properly initialized, an error is thrown. * * @returns {PuddySqlEngine} The internal database instance. * @throws {Error} If the internal database is not a valid `PuddySqlEngine`. */ getDb(): PuddySqlEngine; /** * Checks whether a specific SQL condition function is registered. * * @param {string} key - The condition identifier to look up. * @returns {boolean} - Returns true if the condition exists, otherwise false. */ hasCondition(key: string): boolean; /** * Retrieves a registered SQL condition function by its identifier. * * @param {string} key - The condition identifier to retrieve. * @returns {WhereConditionsFunc} - The associated condition function. * @throws {Error} If the condition does not exist. */ getCondition(key: string): WhereConditionsFunc; /** * Returns a shallow copy of all registered SQL condition functions. * * @returns {SqlConditions} - An object containing all condition functions mapped by key. */ getConditions(): SqlConditions; /** * Registers a new condition under a unique key to be used in query generation. * * The `conditionHandler` determines how the condition will behave. It can be: * - A **string**, representing a SQL operator (e.g., '=', '!=', 'LIKE'); * - An **object**, which must include an `operator` key (e.g., { operator: '>=' }); * - A **function**, which receives a `condition` object and returns a full condition definition. * * If a `valueHandler` is provided, it must be a function that handles value transformation, * and will be stored under the same key in the internal value function map. * * This method does not allow overwriting an existing key in either condition or value handlers. * * @param {string} key - Unique identifier for the new condition type. * @param {string|WhereConditions|WhereConditionsFunc} conditionHandler - Defines the logic or operator of the condition. * @param {(function(string): string)|null} [valueHandler=null] - Optional custom function for value transformation (e.g., for SOUNDEX). * * @throws {Error} If the key is not a non-empty string. * @throws {Error} If the key already exists in either conditions or value handlers. * @throws {Error} If conditionHandler is not a string, object with `operator`, or function. * @throws {Error} If valueHandler is provided but is not a function. */ addCondition(key: string, conditionHandler: string | WhereConditions | WhereConditionsFunc, valueHandler?: ((arg0: string) => string) | null): void; /** * Registers a SQL function-based condition with optional operator and value transformation. * * This helper wraps a SQL column in a function (e.g., `LOWER(column)`) and optionally * transforms the parameter using the same function (e.g., `LOWER($1)`), depending on config. * * It integrates with the dynamic condition system that uses: * - `#conditions[name]` for SQL structure generation * - `#customValFunc[valType]` for optional value transformations * * @param {string} funcName - SQL function name to wrap around the column (e.g., `LOWER`, `SOUNDEX`). * @param {boolean} [editParamByDefault=false] - If true, also applies the SQL function to the parameter by default. * @param {string} [operator='='] - Default SQL comparison operator (e.g., `=`, `!=`, `>`, `<`). * * ----------------------------------------------------- * * Runtime Behavior: * - Uses `group.newOp` (if provided) to override the default operator. * - Uses `group.funcName` (if string) to override the default function name used in `valType`. * - If `funcName !== null` and `editParamByDefault === true`, the function will also apply to the param. * - The final SQL looks like: FUNC(column) OP FUNC($n), if both sides use the same function. * * * The `group` object passed at runtime may include: * @param {Object} group * @param {string} group.column - The column name to apply the function on. * @param {string} [group.newOp] - Optional override for the comparison operator. * @param {string|null} [group.funcName] - Optional override for the SQL function name * (affects both SQL column and valType used in `#customValFunc`). * * @throws {TypeError} If `funcName` is not a non-empty string. * @throws {TypeError} If `editParamByDefault` is provided and is not a boolean. * @throws {TypeError} If `operator` is not a non-empty string. * * -------------------------------------------------------------------------------- * How it's used in the system: * * ```js * const result = this.#conditions[group.operator](group); * const param = typeof this.#customValFunc[result.valType] === 'function' * ? this.#customValFunc[result.valType](`$1`) * : `$1`; * const sql = `${result.column} ${result.operator} ${param}`; * ``` * * ----------------------------------------------------- * @example * // Registers a ROUND() comparison with "!=" * addConditionV2('ROUND', false, '!='); * * ----------------------------------------------------- * @example * // Registers LOWER() with editParamByDefault * addConditionV2('LOWER', true); * * // Parses as: LOWER(username) = LOWER($1) * parse({ column: 'username', value: 'fluttershy', operator: 'LOWER' }); * * ----------------------------------------------------- * @example * // Registers UPPER() = ? without editParamByDefault * addConditionV2('UPPER'); * * // Parses as: UPPER(username) = $1 * parse({ column: 'username', value: 'rarity', operator: 'UPPER' }); * * ----------------------------------------------------- * @example * // Can be overridden at runtime: * addConditionV2('CEIL', true); * * parse({ * column: 'price', * value: 3, * newOp: '>', * operator: 'CEIL', * funcName: null * }); * * // Result: CEIL(price) > 3 */ addConditionV2: (funcName: string, editParamByDefault?: boolean, operator?: string) => void; /** * Generates a SELECT clause based on the input, supporting SQL expressions, aliases, * and boosts using CASE statements. * * This method supports the following input formats: * * - `null` or `undefined`: returns '*' * - `string`: returns the parsed column/expression (with optional aliasing if `AS` is present) * - `string[]`: returns a comma-separated list of parsed columns * - `object`: supports structured input with: * - `aliases`: key-value pairs of column names and aliases * - `values`: array of column names or expressions * - `boost`: object describing a weighted relevance score using CASE statements * - Must include `alias` (string) and `value` (array of boost rules) * - Each boost rule supports: * - `columns` (string|string[]): target columns to apply the condition on (optional) * - `value` (string|array): value(s) to compare, or a raw SQL condition if `columns` is omitted * - `operator` (string): SQL comparison operator (default: 'LIKE', supports 'IN', '=', etc.) * - `weight` (number): numeric weight applied when condition matches (default: 1) * - If `columns` is omitted, the `value` is treated as a raw SQL condition inserted directly into the CASE. * * Escaping of all values is handled by `pg.escapeLiteral()` for SQL safety (PostgreSQL). * * @param {SelectQuery} [input = '*'] - Select clause definition. * @returns {string} - A valid SQL SELECT clause string. * * @throws {TypeError} If the input is of an invalid type. * @throws {Error} If `boost.alias` is missing or not a string. * @throws {Error} If `boost.value` is present but not an array. * * @example * this.selectGenerator(); * // returns '*' * * this.selectGenerator('COUNT(*) AS total'); * // returns 'COUNT(*) AS total' * * this.selectGenerator(['id', 'username']); * // returns 'id, username' * * this.selectGenerator({ * aliases: { * id: 'image_id', * uploader: 'user_name' * }, * values: ['created_at', 'score'] * }); * // returns 'id AS image_id, uploader AS user_name, created_at, score' * * this.selectGenerator({ * aliases: { * id: 'image_id', * uploader: 'user_name' * }, * values: ['created_at'], * boost: { * alias: 'relevance', * value: [ * { * columns: ['tags', 'description'], * value: 'fluttershy', * weight: 2 * }, * { * columns: 'tags', * value: 'pinkie pie', * operator: 'LIKE', * weight: 1.5 * }, * { * columns: 'tags', * value: 'oc', * weight: -1 * }, * { * value: "score > 100 AND views < 1000", * weight: 5 * } * ] * } * }); * // returns something like: * // CASE * // WHEN tags LIKE '%fluttershy%' OR description LIKE '%fluttershy%' THEN 2 * // WHEN tags LIKE '%pinkie pie%' THEN 1.5 * // WHEN tags LIKE '%oc%' THEN -1 * // WHEN score > 100 AND views < 1000 THEN 5 * // ELSE 0 * // END AS relevance, id AS image_id, uploader AS user_name, created_at */ selectGenerator(input?: SelectQuery): string; /** * Helper function to parse individual columns or SQL expressions. * Supports aliasing and complex expressions. * * @param {string} column - Column name or SQL expression. * @param {string} [alias] - Alias for the column (optional). * @returns {string} - A valid SQL expression for SELECT clause. */ parseColumn(column: string, alias?: string): string; /** * Extracts the value of a key from a JSON object using SQLite's json_extract function. * @param {string} where - The JSON column to extract from. * @param {string} name - The key or path to extract (dot notation). * @returns {string} SQL snippet to extract a value from JSON. */ getJsonExtract: (where?: string, name?: string) => string; /** * Expands each element in a JSON array or each property in a JSON object into separate rows. * Intended for use in the FROM clause. * @param {string} source - JSON column or expression to expand. * @returns {string} SQL snippet calling json_each. */ getJsonEach: (source?: string) => string; /** * Unrolls a JSON array from a specific key inside a JSON column using json_each. * Ideal for iterating over array elements in a FROM clause. * @param {string} where - The JSON column containing the array. * @param {string} name - The key of the JSON array. * @returns {string} SQL snippet to extract and expand a JSON array. */ getArrayExtract: (where?: string, name?: string) => string; /** * Extracts a key from a JSON object and casts it to a given SQLite type (INTEGER, TEXT, REAL, etc.). * @param {string} where - The JSON column to extract from. * @param {string} name - The key or path to extract. * @param {string} type - The type to cast to (e.g., 'INTEGER', 'TEXT', 'REAL'). * @returns {string} SQL snippet with cast applied. */ getJsonCast: (where?: string, name?: string, type?: string) => string; /** * Updates the table by adding, removing, modifying or renaming columns. * @param {SqlTableConfig} changes - An array of changes to be made to the table. * Each change is defined by an array, where: * - To add a column: ['ADD', 'columnName', 'columnType', 'columnOptions'] * - To remove a column: ['REMOVE', 'columnName'] * - To modify a column: ['MODIFY', 'columnName', 'newColumnType', 'newOptions'] * - To rename a column: ['RENAME', 'oldColumnName', 'newColumnName'] * @returns {Promise<void>} * * @throws {TypeError} If `changes` is not an array of arrays. * @throws {Error} If any change has missing or invalid parameters. */ updateTable(changes: SqlTableConfig): Promise<void>; /** * Drops the current table if it exists. * * This method executes a `DROP TABLE` query using the table name defined in `this.#settings.name`. * It's useful for resetting or cleaning up the database schema dynamically. * If the query fails due to connection issues (like `SQLITE_CANTOPEN` or `ECONNREFUSED`), * it rejects with the error; otherwise, it resolves with `false` to indicate failure. * On success, it resolves with `true`. * * @returns {Promise<boolean>} Resolves with `true` if the table was dropped, or `false` if there was an issue (other than connection errors). * @throws {Error} If there is an issue with the database or settings, or if the table can't be dropped. */ dropTable(): Promise<boolean>; /** * Creates a table in the database based on provided column definitions. * Also stores the column structure in this.#table as an object keyed by column name. * If a column type is "TAGS", it will be replaced with "JSON" for SQL purposes, * and registered in #tagColumns using a PuddySqlTags instance, * but the original "TAGS" value will be preserved in this.#table. * @param {SqlTableConfig} columns - An array of column definitions. * Each column is defined by an array containing the column name, type, and optional configurations. * @returns {Promise<void>} * * @throws {TypeError} If any column definition is malformed. * @throws {Error} If table name is not defined in settings. */ createTable(columns: SqlTableConfig): Promise<void>; /** * Checks whether a column is associated with a tag editor. * Tag editors are used for managing tag-based columns in SQL. * * @param {string} name - The column name to check. * @returns {boolean} - Returns true if the column has an associated tag editor. */ hasTagEditor(name: string): boolean; /** * Retrieves the PuddySqlTags instance associated with a specific column. * Used when the column was defined as a "TAGS" column in the SQL table definition. * * @param {string} name - The column name to retrieve the tag editor for. * @returns {PuddySqlTags} - The tag editor instance. * @throws {Error} If the column is not associated with a tag editor. */ getTagEditor(name: string): PuddySqlTags; /** * Returns a shallow copy of all column-to-tag-editor mappings. * * @returns {Record<string, PuddySqlTags>} - All tag editor instances mapped by column name. */ getTagEditors(): Record<string, PuddySqlTags>; /** * Parses and validates fields from result rows based on SQL types in this.#table. * Converts known SQL types to native JS types. * * Supported types: BOOLEAN, INTEGER, BIGINT, FLOAT, TEXT, JSON, DATE, TIMESTAMP, etc. * * @param {any} result - The result row to check. * @returns {FreeObj} */ resultChecker(result: any): FreeObj; /** * Escapes values inside the valueObj using type definitions from this.#table. * Only modifies the values that have a matching column in the table. * Uses the appropriate parser from #jsonEscapeAlias. * @param {FreeObj} valueObj - The object containing values to be escaped. * @returns {FreeObj} The same valueObj with its values escaped according to table definitions. */ escapeValues(valueObj?: FreeObj): FreeObj; /** * Set or update database settings by merging with existing ones. * This function ensures safe fallback values and formats the SELECT clause. * * @param {TableSettings} [settings={}] - Partial configuration to apply. Will be merged with current settings. * @param {PuddySqlEngine} [db] - PuddySql Instance. */ setDb(settings?: TableSettings, db?: PuddySqlEngine): void; /** * Retrieves the number of affected rows from a database operation result. * * This method abstracts differences between database engines, such as: * - SQLite: returns `result.changes` * - PostgreSQL: returns `result.rowCount` * - Fallback: `result.rowsAffected`, if defined * * @param {FreeObj|null} result - The result object returned by the database driver. * @returns {number} The number of affected rows, or null if it can't be determined. */ getResultCount(result: FreeObj | null): number; /** * Check if a row with the given ID (and optional subId) exists. * @param {string|number} id - Primary key value. * @param {string|number} [subId] - Optional sub-ID for composite key. * @returns {Promise<boolean>} */ has(id: string | number, subId?: string | number): Promise<boolean>; /** * Applies type-specific escaping to a single value based on the table's column definition. * @param {any} v - The raw value to be escaped. * @param {string} name - The column name associated with the value. * @returns {any} The escaped value if a valid type and handler exist; otherwise, the original value. */ escapeValuesFix(v: any, name: string): any; /** * Updates records based on a complex WHERE clause defined by a filter object. * Instead of relying solely on an ID (or subId), this method uses parseWhere to * generate the conditions, and updates the given fields in valueObj. * * @param {FreeObj} valueObj - An object representing the columns and new values for the update. * @param {QueryGroup} filter - An object containing the conditions for the WHERE clause. * @returns {Promise<number>} - Count of rows that were updated. */ advancedUpdate(valueObj?: FreeObj, filter?: QueryGroup): Promise<number>; /** * Update an existing record with given data. * Will not insert if the record doesn't exist. * @param {string|number} id - Primary key value. * @param {FreeObj} valueObj - Data to update. * @returns {Promise<number>} Count of rows were updated. */ update(id: string | number, valueObj?: FreeObj): Promise<number>; /** * Insert or update one or more records with given data. * * If `valueObj` is an array, `id` must also be an array of the same length. * All objects inside the array must have identical keys. * * @param {string|number|Array<string|number>} id - Primary key value(s) for each record. * @param {FreeObj|FreeObj[]} valueObj - A single object or an array of objects containing the data to store. * @param {boolean} [onlyIfNew=false] - If true, only insert if the record(s) do not already exist. * @returns {Promise<FreeObj|FreeObj[]|null>} - Generated values will be returned, or null if nothing was generated. * @throws {Error} If `valueObj` is an array and `id` is not an array of the same length, * or if objects in `valueObj` array have mismatched keys. */ set(id: string | number | Array<string | number>, valueObj?: FreeObj | FreeObj[], onlyIfNew?: boolean): Promise<FreeObj | FreeObj[] | null>; /** * Get a record by its ID (and optional subId). * @param {string|number} id - Primary key value. * @param {string|number} [subId] - Optional sub-ID for composite key. * @returns {Promise<FreeObj|null>} */ get(id: string | number, subId?: string | number): Promise<FreeObj | null>; /** * Delete records based on a complex WHERE clause using a filter object. * * Uses the internal parseWhere method to build a flexible condition set. * * @param {QueryGroup} filter - An object containing the WHERE condition(s). * @returns {Promise<number>} - Number of rows deleted. */ advancedDelete(filter?: QueryGroup): Promise<number>; /** * Delete a record by its ID (and optional subId). * @param {string|number} id - Primary key value. * @param {string|number} [subId] - Optional sub-ID for composite key. * @returns {Promise<number>} - Count of rows were updated. */ delete(id: string | number, subId?: string | number): Promise<number>; /** * Get a limited number of rows from the database. * If an ID is provided, returns only the matching record(s) up to the specified count. * @param {number} count - Number of rows to retrieve. * @param {string|number|null} [filterId=null] - Optional ID to filter by. * @param {SelectQuery} [selectValue='*'] - Defines which columns or expressions should be selected in the query. * @returns {Promise<FreeObj[]>} */ getAmount(count: number, filterId?: string | number | null, selectValue?: SelectQuery): Promise<FreeObj[]>; /** * Get all records from the table. * If an ID is provided, returns only the matching record(s). * @param {string|number|null} [filterId=null] - Optional ID to filter by. * @param {SelectQuery} [selectValue='*'] - Defines which columns or expressions should be selected in the query. * @returns {Promise<FreeObj[]>} */ getAll(filterId?: string | number | null, selectValue?: SelectQuery): Promise<FreeObj[]>; /** * Executes a paginated query and returns results, total pages, and total item count. * * @param {string} query - The base SQL query (should not include LIMIT or OFFSET). * @param {any[]} params - The parameters for the SQL query. * @param {number} perPage - The number of items per page. * @param {number} page - The current page number (starting from 1). * @param {string} queryName - The query name to insert into the sql debug. * @returns {Promise<PaginationResult>} */ execPagination(query: string, params: any[], perPage: number, page: number, queryName?: string): Promise<PaginationResult>; /** * Builds a SQL WHERE clause from a nested or flat condition structure. * * This internal helper method parses logical groupings (AND/OR) and formats the conditions into * SQL syntax, while managing parameter placeholders and values. * * It supports: * - Nested condition groups via `group` and `conditions`. * - Flat object-based filtering (legacy/fallback support). * - Single-condition objects. * - Dynamic operators through the internal `#conditions` handler. * * @param {Pcache} [pCache={ index: 1, values: [] }] - Placeholder cache object. * @param {QueryGroup} [group={}] - Grouped or single filter condition. * @returns {string} SQL-formatted WHERE clause (without the "WHERE" keyword). * * @example * const pCache = { index: 1, values: [] }; * const clause = this.parseWhere(pCache, { * group: 'OR', * conditions: [ * { column: 'status', value: 'active' }, * { column: 'role', value: 'admin', operator: '=' } * ] * }); * // clause: "(status = $1) OR (role = $2)" * // pCache.values: ['active', 'admin'] */ parseWhere(pCache?: Pcache, group?: QueryGroup): string; /** * Generates a default LEFT JOIN clause based on internal settings. * * This method is used as a fallback when no custom join is provided. * It expects `this.#settings.join` to be a string containing the table name, * and `this.#settings.joinCompare` to be the ON condition. * * @returns {string} The default LEFT JOIN SQL snippet, or an empty string if no join is configured. */ insertJoin(): string; /** * Parses and generates JOIN clauses based on the provided configuration. * * Supports multiple formats: * - If `join` is a single object: returns a single JOIN clause. * - If `join` is an array of objects: generates multiple JOINs with aliases (`j1`, `j2`, ...). * - If `join` is invalid or empty: falls back to `insertJoin()` using internal settings. * * @param {JoinObj|JoinObj[]|string|null} [join] - The join configuration(s). * @returns {string} One or more JOIN SQL snippets. */ parseJoin(join?: JoinObj | JoinObj[] | string | null): string; /** * Finds the first item matching the filter, along with its position, page, and total info. * Uses a single SQL query to calculate everything efficiently. * * If selectValue is null, it only returns the pagination/position data, not the item itself. * * @param {Object} [searchData={}] - Main search configuration. * @param {QueryGroup} [searchData.q={}] - Nested criteria object. * @param {TagCriteria[]|TagCriteria|null} [searchData.tagCriteria] - One or multiple tag criteria groups. * @param {string[]} [searchData.tagCriteriaOps] - Optional logical operators between tag groups (e.g., ['AND', 'OR']). * @param {number} [searchData.perPage] - Number of items per page. * @param {SelectQuery} [searchData.select='*'] - Which columns to select. Set to null to skip item data. * @param {string} [searchData.order] - SQL ORDER BY clause. Defaults to configured order. * @param {string|JoinObj|JoinObj[]} [searchData.join] - JOIN definitions with table, compare, and optional type. * @returns {{ query: string; values: any[] | undefined; perPage: number; selectValue: SelectQuery; }} * @throws {Error} If searchData has invalid structure or values. */ findQuery(searchData?: { q?: QueryGroup | undefined; tagCriteria?: TagCriteria | TagCriteria[] | null | undefined; tagCriteriaOps?: string[] | undefined; perPage?: number | undefined; select?: SelectQuery | undefined; order?: string | undefined; join?: string | JoinObj | JoinObj[] | undefined; }): { query: string; values: any[] | undefined; perPage: number; selectValue: SelectQuery; }; /** * Finds the first item matching the filter, along with its position, page, and total info. * Uses a single SQL query to calculate everything efficiently. * * If selectValue is null, it only returns the pagination/position data, not the item itself. * * @param {Object} [searchData={}] - Main search configuration. * @param {QueryGroup} [searchData.q={}] - Nested criteria object. * @param {TagCriteria[]|TagCriteria|null} [searchData.tagCriteria] - One or multiple tag criteria groups. * @param {string[]} [searchData.tagCriteriaOps] - Optional logical operators between tag groups (e.g., ['AND', 'OR']). * @param {number} [searchData.perPage] - Number of items per page. * @param {SelectQuery} [searchData.select='*'] - Which columns to select. Set to null to skip item data. * @param {string} [searchData.order] - SQL ORDER BY clause. Defaults to configured order. * @param {string|JoinObj|JoinObj[]} [searchData.join] - JOIN definitions with table, compare, and optional type. * @returns {Promise<FindResult | null>} * @throws {Error} If searchData has invalid structure or values. */ find(searchData?: { q?: QueryGroup | undefined; tagCriteria?: TagCriteria | TagCriteria[] | null | undefined; tagCriteriaOps?: string[] | undefined; perPage?: number | undefined; select?: SelectQuery | undefined; order?: string | undefined; join?: string | JoinObj | JoinObj[] | undefined; }): Promise<FindResult | null>; /** * Perform a filtered search with advanced nested criteria, pagination, and customizable settings. * * Supports complex logical groupings (AND/OR), flat condition style, custom ordering, and single or multiple joins. * Pagination can be enabled using `perPage`, and additional settings like `order`, `join`, and `limit` can be passed inside `searchData`. * * @param {Object} [searchData={}] - Main search configuration. * @param {QueryGroup} [searchData.q={}] - Nested criteria object. * Can be a flat object style or grouped with `{ group: 'AND'|'OR', conditions: [...] }`. * @param {TagCriteria[]|TagCriteria|null} [searchData.tagsQ] - One or multiple tag criteria groups. * @param {string[]} [searchData.tagsOpsQ] - Optional logical operators between tag groups (e.g., ['AND', 'OR']). * @param {SelectQuery} [searchData.select='*'] - Defines which columns or expressions should be selected in the query. * @param {number|null} [searchData.perPage=null] - Number of results per page. If set, pagination is applied. * @param {number} [searchData.page=1] - Page number to retrieve when `perPage` is used. * @param {string} [searchData.order] - Custom `ORDER BY` clause (e.g. `'created_at DESC'`). * @param {string|JoinObj|JoinObj[]} [searchData.join] - A string for single join or array of objects for multiple joins. * Each object should contain `{ table: 'name', compare: 'ON clause' }`. * @param {number} [searchData.limit] - Max number of results to return (ignored when `perPage` is used). * @returns {{ query: string; perPage: number | null; values: any[]; page: number; }} * @throws {Error} If searchData has invalid structure or values. * * @example * // Flat search: * await table.search({ q: { status: { value: 'active' } } }); * * // Grouped search: * await table.search({ * q: { * group: 'AND', * conditions: [ * { column: 'status', value: 'active' }, * { * group: 'OR', * conditions: [ * { column: 'role', value: 'admin' }, * { column: 'role', value: 'mod' } * ] * } * ] * } * }); * * // With pagination and custom joins: * await table.search({ * q: { status: { value: 'active' } }, * select: '*', * perPage: 10, * page: 2, * join: [ * { type: 'left', table: 'profiles', compare: 't.profile_id = j1.id' }, * { type: 'left', table: 'roles', compare: 'j1.role_id = j2.id' } * ], * order: 'created_at DESC' * }); */ searchQuery(searchData?: { q?: QueryGroup | undefined; tagsQ?: TagCriteria | TagCriteria[] | null | undefined; tagsOpsQ?: string[] | undefined; select?: SelectQuery | undefined; perPage?: number | null | undefined; page?: number | undefined; order?: string | undefined; join?: string | JoinObj | JoinObj[] | undefined; limit?: number | undefined; }): { query: string; perPage: number | null; values: any[]; page: number; }; /** * Perform a filtered search with advanced nested criteria, pagination, and customizable settings. * * Supports complex logical groupings (AND/OR), flat condition style, custom ordering, and single or multiple joins. * Pagination can be enabled using `perPage`, and additional settings like `order`, `join`, and `limit` can be passed inside `searchData`. * * @param {Object} [searchData={}] - Main search configuration. * @param {QueryGroup} [searchData.q={}] - Nested criteria object. * Can be a flat object style or grouped with `{ group: 'AND'|'OR', conditions: [...] }`. * @param {TagCriteria[]|TagCriteria|null} [searchData.tagsQ] - One or multiple tag criteria groups. * @param {string[]} [searchData.tagsOpsQ] - Optional logical operators between tag groups (e.g., ['AND', 'OR']). * @param {SelectQuery} [searchData.select='*'] - Defines which columns or expressions should be selected in the query. * @param {number|null} [searchData.perPage=null] - Number of results per page. If set, pagination is applied. * @param {number} [searchData.page=1] - Page number to retrieve when `perPage` is used. * @param {string} [searchData.order] - Custom `ORDER BY` clause (e.g. `'created_at DESC'`). * @param {string|JoinObj|JoinObj[]} [searchData.join] - A string for single join or array of objects for multiple joins. * Each object should contain `{ table: 'name', compare: 'ON clause' }`. * @param {number} [searchData.limit] - Max number of results to return (ignored when `perPage` is used). * @returns {Promise<FreeObj[]|PaginationResult>} - Result rows matching the query. * @throws {Error} If searchData has invalid structure or values. */ search(searchData?: {