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.
954 lines (664 loc) โข 27 kB
Markdown
# ๐ PuddySqlQuery
`PuddySqlQuery` is a high-level query builder class for managing SQL tables using flexible filters, tag-based conditions, JOINs, pagination, and result validation.
It supports complex nested logic (AND/OR), dynamic tag filtering, composable JOIN structures, and automatic SQL clause generation โ all while keeping the API intuitive and extensible.
Perfect for advanced search interfaces, dashboards, data exploration tools, or any project that needs powerful yet readable SQL control.
---
## ๐๏ธ Core Types & Initialization
### ๐งฉ SqlTableConfig
Defines the schema structure for programmatic SQL table creation or modification.
Each array entry represents a single column with this 4-item tuple format:
`[columnName, columnType, columnOptions, columnMeta]`
- **columnName** (`string`): Name of the column, e.g., `"id"`, `"username"`.
- **columnType** (`string`): SQL data type, e.g., `"TEXT"`, `"INTEGER"`.
- **columnOptions** (`string`): SQL options like `NOT NULL`, `PRIMARY KEY`, `DEFAULT`.
- **columnMeta** (`any`): Arbitrary metadata (UI hints, descriptions, tags).
---
### ๐ FindResult
Result of a paginated SQL query locating a specific item:
- **page** (`number`): Current page number (starting at 1).
- **pages** (`number`): Total pages available.
- **total** (`number`): Total items in dataset.
- **position** (`number`): Exact item index (starting at 0).
- **item** (`FreeObj` | optional): The actual found item, if returned.
---
### ๐ท๏ธ TagCriteria
Definition for tag group filtering in SQL clauses:
- **group.column** (`string` | optional): SQL column for tag data (default: `this.getColumnName()`).
- **group.tableName** (`string` | optional): Table name used (default: `this.defaultTableName`).
- **group.allowWildcards** (`boolean` | optional): Allow wildcards in matching (default: `false`).
- **group.include** (`Array<string|string[]>`): Tag values or OR-groups to include in filtering.
---
### ๐ PaginationResult
Result object for paginated queries:
- **items** (`any[]`): Array of items returned for current page.
- **totalPages** (`number`): Total available pages.
- **totalItems** (`number`): Total matching items without pagination.
---
### ๐ฏ SelectQuery
Flexible input for SELECT clause:
Can be a `string`, array of strings, or object with:
- `aliases` (mapping display names to real columns)
- `values` (array of columns to select)
- `boost` (weighted ranking configuration with alias and boost rules)
Can also be `null` for defaults.
---
### ๐งฐ Pcache
Parameter cache for building WHERE clauses:
- `index` (`number`): Starting index for SQL placeholders (`$1`, `$2`, ...). Defaults to `1`.
- `values` (`any[]`): Values collected for parameter binding.
---
### ๐ฆ FreeObj
Generic object with arbitrary keys and unknown values:
- Keys can be `string`, `number`, or `symbol`.
- Values are of unknown type. Useful for flexible data containers.
---
### โ๏ธ WhereConditions
Conditions used in SQL WHERE clause:
- `group` (`'AND'|'OR'|'and'|'or'` | optional): Logical operator for condition groups.
- `conditions` (array of `WhereConditions` or `QueryGroup` | optional): Nested logical conditions.
- `funcName`, `operator`, `value`, `valType`, `lPos`, `newOp`, `column` (various optional fields for SQL expressions and chaining).
---
### ๐งฉ QueryGroup
Flexible group of WHERE conditions, supporting either:
1. Single condition object:
```js
{ column: 'name', operator: '=', value: 'pudding' }
````
2. Named group of conditions:
```js
{
searchByName: { column: 'name', operator: 'ILIKE', value: '%fluttershy%' },
searchByType: { column: 'type', operator: '=', value: 'pegasus' }
}
```
Enables dynamic grouping for advanced filters and scoped searches.
---
### ๐ BoostValue
Rule for weighted query boosting:
* `columns` (optional array): Columns to apply boost on.
* `operator`: Condition operator, e.g., `'='`, `'LIKE'`.
* `value`: Value or array of values to match.
* `weight`: Numeric factor to boost matched results.
---
### ๐ JoinObj
Object defining SQL JOIN clauses:
* `table` (`string`): Table name to join.
* `compare` (`string`): ON clause condition.
* `type` (`string` | optional): JOIN type, defaults to `'left'`.
---
### ๐๏ธ TableSettings
Settings for SQL table/entity configuration:
* `name` (optional string): Table or view name.
* `select` (`SelectQuery`): SELECT clause config. Defaults to `"*"`.
* `join` (optional string): JOIN table name.
* `joinCompare` (optional string): JOIN condition, e.g. `'t.key = j.key'`.
* `order` (optional string): ORDER BY clause.
* `id` (`string`): Primary key column. Defaults to `'key'`.
* `subId` (optional string): Secondary key column (composite key or scope).
---
### โ๏ธ Settings
Configuration for SQL entity querying and joining:
* `select` (`string`): Default columns to select.
* `name` (`string`): Main table/view name.
* `id` (`string`): Primary key column name.
* `joinCompare` (optional string): JOIN matching condition.
* `order` (optional string): Default ordering clause.
* `subId` (optional string): Secondary ID column.
* `join` (optional string): JOIN clause (e.g., `"LEFT JOIN profiles ON ..."`).
---
### ๐ง WhereConditionsFunc
Function type that takes and returns a `WhereConditions` object.
Used for SQL WHERE clause transformations or appends.
---
### ๐๏ธ SqlConditions
Map of named condition identifiers to their transformation functions (`WhereConditionsFunc`).
---
### ๐๏ธ PuddySqlQuery Class Overview
The main query engine for operating on a specific SQL table with support for dynamic conditions, tags, joins, and advanced query building.
#### Private fields:
* `#conditions`: Registered SQL conditions map.
* `#customValFunc`: Custom value transformation functions.
* `#db`: The internal `PuddySqlEngine` database instance.
* `#settings`: Current table/query settings.
* `#table`: Table schema and column metadata.
* `#tagColumns`: Tag filtering helpers per column.
---
#### Method: `getDb()`
Safely retrieves the internal database instance.
Throws if the internal DB is not a valid `PuddySqlEngine` instance.
```js
const db = instance.getDb();
```
**Throws:**
`Error` if DB is invalid or uninitialized.
---
## โ๏ธ Constructor & Condition Management
### ๐ Constructor: Initial Condition Setup
Initializes the query instance with a set of predefined SQL condition operators and function-based conditions.
- Adds common operators like `'LIKE'`, `'NOT'`, `'='`, `'!='`, `'>='`, `'<='`, `'>'`, `'<'`.
- Registers advanced SQL functions using `addConditionV2` for phonetic, string, math, and date/time functions:
- Phonetic: `SOUNDEX`
- Case conversion: `LOWER`, `UPPER`
- Trim whitespace: `TRIM`, `LTRIM`, `RTRIM`
- String length: `LENGTH`
- Math: `ABS`, `ROUND`, `CEIL`, `FLOOR`
- Null handling: `COALESCE`
- String formatting: `HEX`, `QUOTE`
- Unicode: `UNICODE`, `CHAR`
- Type inspection: `TYPEOF`
- Date/time extraction: `DATE`, `TIME`, `DATETIME`, `JULIANDAY`
---
### ๐ Method: `hasCondition(key)`
Checks if a condition is registered under the given key.
- **Parameters:**
- `key` (`string`): Condition identifier.
- **Returns:**
- `boolean`: `true` if condition exists, else `false`.
---
### ๐ ๏ธ Method: `getCondition(key)`
Retrieves the condition function registered with the given key.
- **Parameters:**
- `key` (`string`): Condition identifier.
- **Returns:**
- `WhereConditionsFunc`: The condition function.
- **Throws:**
- `Error` if condition key is not found.
---
### ๐ Method: `getConditions()`
Returns a shallow copy of all registered condition functions.
- **Returns:**
- `SqlConditions` โ Object mapping keys to condition functions.
---
### โ Method: `addCondition(key, conditionHandler, valueHandler = null)`
Registers a new condition type for query generation.
- **Parameters:**
- `key` (`string`): Unique identifier for the condition.
- `conditionHandler` (`string` | `WhereConditions` | `WhereConditionsFunc`):
Defines the condition logic.
- String: SQL operator (e.g., `'='`, `'LIKE'`)
- Object: Must include `.operator` (e.g., `{ operator: '>=' }`)
- Function: Custom condition builder function.
- `valueHandler` (`function(string): string` | `null`): Optional function transforming parameter values (e.g., for `SOUNDEX`).
- **Validation:**
- Throws if `key` is not a non-empty string.
- Throws if `key` already exists in conditions or value handlers.
- Throws if `conditionHandler` is not valid type.
- Throws if `valueHandler` is provided but not a function.
- **Behavior:**
- Stores `conditionHandler` internally (function wrapped if string or object).
- Stores `valueHandler` if provided.
---
### ๐ฏ Method: `addConditionV2(funcName, editParamByDefault = false, operator = '=')`
Registers a SQL function-based condition with optional parameter transformation.
- **Purpose:**
Wraps a SQL column in a function (e.g., `LOWER(column)`) and optionally applies the same function to the parameter (`LOWER($1)`).
- **Parameters:**
- `funcName` (`string`): SQL function name (must be non-empty).
- `editParamByDefault` (`boolean`, default `false`): If `true`, applies function to the query parameter by default.
- `operator` (`string`, default `'='`): SQL comparison operator.
- **Runtime Behavior:**
- Uses `group.newOp` if provided to override operator.
- Uses `group.funcName` if provided to override function name in SQL and value transformation.
- Final SQL resembles: `FUNC(column) OP FUNC($n)` or `FUNC(column) OP $n` depending on `editParamByDefault`.
- **Throws:**
- `TypeError` if parameters are invalid types or empty strings.
- **Example Usages:**
- Registering ROUND with operator `!=`:
```js
addConditionV2('ROUND', false, '!=');
```
- Registering LOWER with parameter function:
```js
addConditionV2('LOWER', true);
// Parses: LOWER(username) = LOWER($1)
```
- Registering UPPER without parameter function:
```js
addConditionV2('UPPER');
// Parses: UPPER(username) = $1
```
- Overriding operator at runtime:
```js
addConditionV2('CEIL', true);
parse({
column: 'price',
value: 3,
newOp: '>',
operator: 'CEIL',
funcName: null
});
// Result: CEIL(price) > 3
```
---
## ๐งฉ selectGenerator & JSON Helpers
### ๐ฏ Method: `selectGenerator(input = '*')`
Generates a SQL SELECT clause from flexible input formats, supporting aliases, complex expressions, and weighted boosts via CASE statements.
#### Supported input types:
- `null` / `undefined`: returns `'*'`
- `string`: returns the parsed column or SQL expression (supports aliases with `AS`)
- `string[]`: returns a comma-separated list of parsed columns
- `object`: supports structured input with:
- `aliases`: key-value pairs for columns and aliases
- `values`: array of column names or expressions
- `boost`: weighted relevance using CASE, with rules for columns, operators, values, and weights
#### Boost rules support:
- `columns` (optional): single string or array of strings (target columns)
- `value`: string or array (value(s) to compare) or raw SQL condition if `columns` omitted
- `operator`: SQL operator (default `'LIKE'`, supports `'IN'`, `'='`, etc.)
- `weight`: numeric weight applied on match (default `1`)
> All values are escaped using `pg.escapeLiteral()` for PostgreSQL safety.
#### Throws:
- `TypeError` for invalid input types
- `Error` if `boost.alias` is missing or invalid
- `Error` if `boost.value` exists but is not an array
#### Examples:
```js
selectGenerator();
// returns '*'
selectGenerator('COUNT(*) AS total');
// returns 'COUNT(*) AS total'
selectGenerator(['id', 'username']);
// returns 'id, username'
selectGenerator({
aliases: { id: 'image_id', uploader: 'user_name' },
values: ['created_at', 'score']
});
// returns 'id AS image_id, uploader AS user_name, created_at, score'
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 CASE statement boosting relevance + other columns
```
---
### ๐งฉ Method: `parseColumn(column, alias)`
Parses an individual column or SQL expression, optionally applying an alias.
* `column` (`string`): Column name or SQL expression
* `alias` (`string`, optional): Alias name
**Returns:** SQL snippet like `"column"` or `"column AS alias"`
**Throws:**
* `TypeError` if inputs are not strings
---
### ๐ง JSON SQL Helpers
These methods help generate SQLite-compatible JSON queries:
#### `#sqlOpStringVal(value)`
Internal helper that asserts the input is a string and returns it.
---
#### `getJsonExtract(where, name)`
Generates SQLite JSON extraction snippet:
```sql
json_extract(where, '$.name')
```
* `where` (`string`): JSON column or expression
* `name` (`string`): Key or JSON path
---
#### `getJsonEach(source)`
Generates SQLite `json_each` call to expand JSON arrays or objects into rows:
```sql
json_each(source)
```
* `source` (`string`): JSON column or expression
---
#### `getArrayExtract(where, name)`
Combines `getJsonExtract` and `getJsonEach` to expand a JSON array from a specific key:
```sql
json_each(json_extract(where, '$.name'))
```
* `where` (`string`): JSON column
* `name` (`string`): Key containing array
---
#### `getJsonCast(where, name, type)`
Extracts a JSON value and casts it to a specified SQLite type:
```sql
CAST(json_extract(where, '$.name') AS TYPE)
```
* `where` (`string`): JSON column
* `name` (`string`): Key to extract
* `type` (`string`): SQLite type to cast to (e.g., `'INTEGER'`, `'TEXT'`, `'REAL'`)
---
## ๐ ๏ธ Table Schema Management & Tag Editors
### ๐ Method: `async updateTable(changes)`
Updates a SQL table schema by adding, removing, modifying, or renaming columns.
#### Parameters:
- `changes` (`SqlTableConfig`): Array of change commands, each an array:
- `['ADD', columnName, columnType, columnOptions?]`
- `['REMOVE', columnName]`
- `['MODIFY', columnName, newColumnType, newOptions?]`
- `['RENAME', oldColumnName, newColumnName]`
#### Behavior:
- Executes corresponding `ALTER TABLE` SQL statements.
- Uses `this.getDb()` for DB access.
- Throws on invalid input.
- Logs errors if DB operations fail but continues.
#### Throws:
- `TypeError` if `changes` is not an array of arrays or invalid action.
- `Error` if required parameters for each action are missing or invalid.
---
### ๐ฅ Method: `async dropTable()`
Drops the current table if it exists.
#### Returns:
- `Promise<boolean>`: resolves `true` on success, `false` on failure (except connection errors, which reject).
#### Behavior:
- Runs `DROP TABLE {tableName}`.
- Uses connection error detection to reject or resolve accordingly.
---
### ๐๏ธ Method: `async createTable(columns)`
Creates a SQL table based on column definitions.
#### Parameters:
- `columns` (`SqlTableConfig`): Array of column definitions, each an array:
- `[name, type, options?]`
- Custom type `"TAGS"` is converted internally to `"JSON"` and registered for tag management.
#### Behavior:
- Builds a `CREATE TABLE IF NOT EXISTS` statement.
- Stores the column schema in `this.#table` with uppercase types and options.
- Creates `PuddySqlTags` instances for `"TAGS"` columns stored in `this.#tagColumns`.
- Throws on invalid definitions or missing table name.
---
### ๐ Method: `hasTagEditor(name)`
Checks if a column has an associated tag editor (`PuddySqlTags` instance).
#### Parameters:
- `name` (`string`): Column name.
#### Returns:
- `boolean` โ `true` if tag editor exists, `false` otherwise.
---
### ๐ Method: `getTagEditor(name)`
Retrieves the `PuddySqlTags` instance for a specific tag column.
#### Parameters:
- `name` (`string`): Column name.
#### Returns:
- `PuddySqlTags` instance.
#### Throws:
- `Error` if the column has no associated tag editor or invalid input.
---
### ๐ Method: `getTagEditors()`
Returns all tag editors as a shallow copy object mapping column names to their `PuddySqlTags`.
#### Returns:
- `Record<string, PuddySqlTags>` โ All tag editors by column.
---
## ๐งช Data Conversion, Escaping & Settings
### ๐ `#jsonEscape` โ Type Conversion Utilities
A private map of functions that convert raw SQL values into native JavaScript types.
| Key | Description |
|----------|-------------|
| `boolean` | Returns `true` for: `true`, `"true"`, `1`, `"1"`. |
| `bigInt` | Converts values to `BigInt`. Returns `null` on failure. |
| `int` | Parses to integer (`parseInt`). Returns `null` if NaN. |
| `float` | Parses to float (`parseFloat`). Returns `null` if NaN. |
| `json` | Parses JSON strings. Returns original if already object/array. |
| `tags` | Parses strings to arrays of strings. Invalid elements become `null`. |
| `text` | Returns the string if it's valid. Otherwise `null`. |
| `date` | Converts to valid `Date` object. Returns `null` if invalid. |
---
### ๐งฌ `#jsonEscapeAlias` โ SQL Type Mappings
Maps SQL types (e.g., `INTEGER`, `TEXT`, `TAGS`) to their corresponding `#jsonEscape` functions.
Supported aliases include:
- `BOOLEAN`, `BOOL`
- `BIGINT`, `DECIMAL`, `NUMERIC`
- `INTEGER`, `INT`, `SMALLINT`, `TINYINT`
- `REAL`, `FLOAT`, `DOUBLE`
- `TEXT`, `CHAR`, `VARCHAR`, `CLOB`
- `JSON`, `TAGS`
- `DATE`, `DATETIME`, `TIMESTAMP`, `TIME`
---
### โ
Method: `resultChecker(result)`
Converts result rows from raw SQL types into properly typed JavaScript values based on `this.#table`.
#### Parameters:
- `result` (`object`) โ A result row from the database.
#### Returns:
- `FreeObj` โ The same object, converted.
---
### ๐ก๏ธ Method: `escapeValues(valueObj)`
Converts values for writing back to the database using type definitions from `this.#table`.
#### Parameters:
- `valueObj` (`FreeObj`) โ Object of raw input values.
#### Returns:
- `FreeObj` โ The same object, with values sanitized or transformed.
---
### โ๏ธ Method: `setDb(settings, db)`
Merges new settings with existing internal config and sets the database instance.
#### Parameters:
- `settings` (`Partial<TableSettings>`) โ Any new values to apply.
- `db` (`PuddySqlEngine`) โ Reference to the main database engine.
#### Behavior:
- Validates and fills default values (`select`, `join`, `id`, etc.)
- Uses `selectGenerator` for advanced select clause handling.
#### Throws:
- `TypeError` if `settings` is not an object.
- `Error` if `db` is not an instance of `PuddySqlEngine`.
---
### ๐ Private: `#resultCounts`
Maps driver types to the field used to count affected rows:
- `"sqlite3"` โ `"changes"`
- `"postgre"` โ `"rowCount"`
Used internally to abstract SQL dialect differences.
---
## ๐ง Updates, Inserts & Transformations
### ๐ Method: `getResultCount(result)`
Returns the number of affected rows from a database result, abstracting engine-specific fields.
| Engine | Field |
|--------------|---------------|
| `sqlite3` | `changes` |
| `postgre` | `rowCount` |
| Fallback | `rowsAffected` |
#### Parameters:
- `result` (`object|null`) โ Result from `run()` or query execution.
#### Returns:
- `number` โ Affected rows, or `0`.
---
### ๐ Method: `has(id, subId?)`
Checks if a row exists using primary key (and optional `subId` for composite keys).
#### Parameters:
- `id` (`string|number`) โ Primary ID.
- `subId` (`string|number`) โ Optional secondary ID.
#### Returns:
- `Promise<boolean>` โ `true` if exists.
---
### ๐ ๏ธ Private: `#jsonEscapeFix` โ Output Transformers
Used when saving data back to SQL.
| Type | Behavior |
|-------|----------|
| `JSON` | `JSON.stringify(value)` |
| `TAGS` | Ensures all entries are strings before stringifying |
---
### ๐ Method: `escapeValuesFix(v, name)`
Applies the appropriate fix function for a specific column type before writing.
#### Parameters:
- `v` (`any`) โ Value to transform.
- `name` (`string`) โ Column name.
#### Returns:
- `any` โ Escaped value or original.
---
### ๐งฌ Method: `advancedUpdate(valueObj, filter)`
Updates one or more rows using a filter object instead of direct IDs.
#### Parameters:
- `valueObj` (`FreeObj`) โ Fields to update.
- `filter` (`QueryGroup`) โ WHERE clause object.
#### Returns:
- `Promise<number>` โ Rows updated.
---
### ๐ Method: `update(id, valueObj)`
Updates a row using its primary key (`subId` supported if available).
#### Parameters:
- `id` (`string|number`) โ Primary ID.
- `valueObj` (`FreeObj`) โ Fields to update.
#### Returns:
- `Promise<number>` โ Rows updated.
---
### ๐ฅ Method: `set(id, valueObj, onlyIfNew = false)`
Inserts or updates one or more rows. Automatically escapes values and handles generated IDs.
#### Parameters:
- `id` (`string|number|string[]|number[]`) โ Primary key(s).
- `valueObj` (`FreeObj|FreeObj[]`) โ One or many objects with fields.
- `onlyIfNew` (`boolean`) โ If `true`, skips update on conflict.
#### Behavior:
- Uses `ON CONFLICT DO UPDATE` (or `DO NOTHING`)
- Detects auto-generated or primary key columns and returns them.
- Ensures all entries in `valueObj[]` are uniform in keys.
#### Returns:
- `Promise<FreeObj|FreeObj[]|null>` โ Inserted or updated row(s), or `null`.
---
### ๐ Method: `get(id, subId?)`
Fetches a single record using its primary key (and optional `subId` if defined).
#### Parameters:
- `id` (`string|number`) โ Primary key.
- `subId?` (`string|number`) โ Optional composite key.
#### Returns:
- `Promise<FreeObj|null>` โ Record if found, else `null`.
---
### ๐๏ธ Method: `advancedDelete(filter)`
Deletes records matching a complex filter condition.
#### Parameters:
- `filter` (`QueryGroup`) โ Object representing WHERE conditions.
#### Returns:
- `Promise<number>` โ Number of rows deleted.
---
### โ Method: `delete(id, subId?)`
Deletes a record by primary key (and optional `subId`).
#### Parameters:
- `id` (`string|number`)
- `subId?` (`string|number`)
#### Returns:
- `Promise<number>` โ Number of rows deleted.
---
### ๐ข Method: `getAmount(count, filterId?, selectValue?)`
Returns up to `count` items. Optionally filter by ID and control selected columns.
#### Parameters:
- `count` (`number`)
- `filterId?` (`string|number|null`)
- `selectValue?` (`SelectQuery`) โ Default: `"*"`
#### Returns:
- `Promise<FreeObj[]>`
---
### ๐ Method: `getAll(filterId?, selectValue?)`
Fetches all records in the table or filtered by a specific ID.
#### Parameters:
- `filterId?` (`string|number|null`)
- `selectValue?` (`SelectQuery`) โ Default: `"*"`
#### Returns:
- `Promise<FreeObj[]>`
---
### ๐ Method: `execPagination(query, params, perPage, page, queryName?)`
Runs a paginated query and returns total items and total pages.
#### Parameters:
- `query` (`string`)
- `params` (`any[]`)
- `perPage` (`number`)
- `page` (`number`)
- `queryName?` (`string`) โ Optional label for debugging.
#### Returns:
- `Promise<{ items: FreeObj[], totalPages: number, totalItems: number }>` โ Paginated result set.
---
### ๐งฉ Method: `parseWhere(pCache, group)`
Parses a flexible query condition group into a SQL WHERE clause.
#### Supports:
- Logical groups (`AND`, `OR`)
- Custom condition handlers (`this.#conditions`)
- Nested or flat filters
- Placeholders via `pCache`
#### Parameters:
- `pCache` (`Pcache`) โ Placeholder manager: `{ index: number, values: any[] }`
- `group` (`QueryGroup`) โ Group or single condition object.
#### Returns:
- `string` โ SQL WHERE clause string (without `WHERE`)
#### Example:
```js
const p = { index: 1, values: [] };
const clause = this.parseWhere(p, {
group: 'OR',
conditions: [
{ column: 'status', value: 'active' },
{ column: 'type', value: 'admin', operator: '=' },
],
});
// clause: "(status = $1) OR (type = $2)"
// p.values: ['active', 'admin']
```
---
### ๐ Method: `insertJoin()`
Returns a default `LEFT JOIN` clause if configured in `#settings`.
#### Returns:
- `string` โ SQL JOIN clause or empty string.
---
### ๐ `#joinTypes` (private)
Internal object with predefined JOIN types:
- `inner`: `'INNER JOIN'`
- `left`: `'LEFT JOIN'`
- `right`: `'RIGHT JOIN'`
- `full`: `'FULL JOIN'`
- `cross`: `'CROSS JOIN'`
- `join`: `'JOIN'` (shorthand for inner)
---
### ๐งฉ Method: `parseJoin(join)`
Parses JOIN configuration into one or more SQL JOIN clauses.
#### Parameters:
- `join` (`JoinObj | JoinObj[] | string | null`)
#### Returns:
- `string` โ JOIN clauses string.
---
### ๐ Method: `find(searchData)`
Finds the **first** matching result and returns its position, page, and optionally its data.
Query only: `findQuery(searchData)`
#### Parameters:
- `searchData` (`object`)
- `q`: QueryGroup or object condition
- `tagCriteria`: Single or multiple tag filters
- `tagCriteriaOps`: Logical ops between tag filters
- `perPage`: Required, results per page
- `select`: Columns to select (`'*'` by default, or `null` to skip data)
- `order`: Custom `ORDER BY`
- `join`: JOIN configs (string, object or array)
#### Returns:
- `Promise<FindResult|null>`
---
### ๐ Method: `search(searchData)`
Performs a complete filtered query with optional **pagination**, **joins**, and **tags**.
Query only: `searchQuery(searchData)`
#### Parameters:
* `searchData` (`object`)
* `q`: QueryGroup or flat condition object
* `tagsQ`: Tags filter (array or object)
* `tagsOpsQ`: Logical ops between tags (`['AND', 'OR']`)
* `select`: Select clause (`'*'`, array, object or `null`)
* `perPage`: Items per page
* `page`: Page number (default: 1)
* `order`: Custom ORDER BY clause
* `join`: JOINs configuration
* `limit`: Max number of rows (ignored if `perPage` is used)
#### Returns:
* `Promise<FreeObj[] | PaginationResult>`
#### Example:
```js
await table.search({
q: {
group: 'AND',
conditions: [
{ column: 'status', value: 'active' },
{
group: 'OR',
conditions: [
{ column: 'type', value: 'admin' },
{ column: 'type', value: 'mod' }
]
}
]
},
tagsQ: [{ column: 'tags', value: 'featured' }],
select: '*',
perPage: 15,
page: 1,
order: 'created_at DESC',
join: [
{ type: 'left', table: 'profiles', compare: 't.profile_id = j1.id' },
{ type: 'left', table: 'roles', compare: 'j1.role_id = j2.id' }
]
});
```