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.

384 lines (383 loc) 16.6 kB
export default PuddySqlTags; export type SpecialQuery = { title: string; parser?: (arg0: string) => string; }; export type Pcache = import("./PuddySqlQuery.mjs").Pcache; export type TagCriteria = import("./PuddySqlQuery.mjs").TagCriteria; /** * Represents a key-value pair extracted from a special chunk format. */ export type SpecialFromChunks = { /** * - The key or identifier extracted from the chunk. */ key: string; /** * - The associated value linked to the key. */ value: string; }; /** * A chunk can be a single string or an array of strings grouped as OR conditions. */ export type Chunks = Array<string | string[]>; /** * Result of parsing a string expression into a column and list of included values. */ export type ParseStringResult = { /** * - The SQL column to which the values apply. */ column: string; /** * - List of values or grouped OR conditions to be included in the query. */ include: Chunks; }; /** * Represents a mapping entry for a tag input definition. * * Each tag input is defined by the name of the list where it belongs (`list`) * and the key (`valueKey`) used to extract the relevant value from tag objects. * This structure is used to determine how tags are parsed and grouped during search. */ export type TagInput = { /** * - The list name where the tag will be added. */ list: string; /** * - The key for the value associated with the tag input. */ valueKey: string; }; /** @typedef {{ title: string; parser?: function(string): string }} SpecialQuery */ /** @typedef {import('./PuddySqlQuery.mjs').Pcache} Pcache */ /** @typedef {import('./PuddySqlQuery.mjs').TagCriteria} TagCriteria */ /** * Represents a key-value pair extracted from a special chunk format. * * @typedef {Object} SpecialFromChunks * @property {string} key - The key or identifier extracted from the chunk. * @property {string} value - The associated value linked to the key. */ /** * Represents a collection of string chunks used in parsing or filtering. * * @typedef {Array<string | string[]>} Chunks * * A chunk can be a single string or an array of strings grouped as OR conditions. */ /** * Result of parsing a string expression into a column and list of included values. * * @typedef {Object} ParseStringResult * @property {string} column - The SQL column to which the values apply. * @property {Chunks} include - List of values or grouped OR conditions to be included in the query. */ /** * Represents a mapping entry for a tag input definition. * * Each tag input is defined by the name of the list where it belongs (`list`) * and the key (`valueKey`) used to extract the relevant value from tag objects. * This structure is used to determine how tags are parsed and grouped during search. * * @typedef {Object} TagInput * @property {string} list - The list name where the tag will be added. * @property {string} valueKey - The key for the value associated with the tag input. */ /** * @class PuddySqlTags * @description A powerful utility class for building advanced SQL WHERE clauses with support for tag-based filtering, * custom boolean logic, wildcard parsing, and special query handlers. * * PuddySqlTags provides a structured way to interpret and transform flexible user search input into robust SQL conditions, * including support for parentheses grouping, AND/OR logic, special colon-based filters, and customizable weight systems * using symbolic operators. Designed with modularity and extensibility in mind, it also prevents unwanted repetitions and * allows precise control over column names, aliases, and JSON handling through `json_each`. * * The class includes: * - Methods to parse complex string-based filters (`parseString`, `safeParseString`) * - Smart logic to detect and manage tag groups, boolean relationships, and custom operators * - Support for boost values, exclusions, and other modifiers via symbols (e.g., `-`, `!`) * - An internal engine to dynamically build `EXISTS`-based SQL conditions compatible with JSON arrays * - Integration-ready output for SQLite3, Postgre or similar relational databases * * ---------- * 💖 Special Thanks 💖 * Deep gratitude to the Derpibooru project for the inspiration, structure, and creativity * that influenced this tool. A tiny heartfelt thank you to **Nighty**. :3 */ declare class PuddySqlTags { /** * Creates an instance of the PuddySqlTags class. * @param {string} defaultColumn - The default column name to use in queries (default is 'tags'). */ constructor(defaultColumn?: string); /** * Adds a new tag input mapping to the #tagInputs property. * * This method allows dynamic addition of new tag input mappings by providing a `key`, * `list`, and `valueKey`. It validates the types of `list` and `valueKey`, and * prevents adding a tag with the list name "include" and "column" as it is restricted. * * @param {string} key - The key (symbol) to associate with the tag input. * @param {string} list - The list name where the tag will be added. * @param {string} valueKey - The key for the value associated with the tag input. * @throws {Error} Throws an error if `list` or `valueKey` are not strings, * or if the `list` name is "include" or "column". */ addTagInput(key: string, list: string, valueKey: string): void; /** * Checks if a tag input mapping exists for the given key. * * @param {string} key - The tag key to check. * @returns {boolean} `true` if the key exists in `#tagInputs`, otherwise `false`. * @throws {TypeError} If `key` is not a string. */ hasTagInput(key: string): boolean; /** * Removes a tag input mapping from the `#tagInputs` object. * * If the key exists, it will be deleted. * Otherwise, an error is thrown. * * @param {string} key - The key of the tag input to remove. * @throws {Error} If the specified key does not exist in `#tagInputs`. * @throws {TypeError} If `key` is not a string. */ removeTagInput(key: string): void; /** * Gets the title of the first item for a given tag input key. * * @param {string} key - The key of the tag input to retrieve. * @returns {TagInput} The title of the first item. * @throws {TypeError} If `key` is not a string. * @throws {Error} If the key does not exist or has no valid title. */ getTagInput(key: string): TagInput; /** * Gets an array of all tag input titles. * * @returns {TagInput[]} An array containing the tag inputs. */ getAllTagInput(): TagInput[]; /** * Sets whether repeated tags are allowed. * Internally sets `this.#noRepeat` to the inverse of the boolean value provided. * If value is not a boolean, resets `noRepeat` to null. * * @param {boolean} value - True to allow repeated tags, false to prevent them. */ setCanRepeat(value: boolean): void; /** * Sets the wildcard symbol used in the search expression. * Only updates if the value is a string. * * @param {'wildcardA'|'wildcardB'} where - Which wildcard to set. * @param {string|null} value - The wildcard symbol (e.g. '*', '%'). */ setWildcard(where: "wildcardA" | "wildcardB", value: string | null): void; /** * Adds a new custom special query to the internal list. * Special queries can affect how tags are interpreted or matched. * * @param {Object} config - The special query object to be added. * @param {string} config.title - The unique title identifier of the special query. */ addSpecialQuery(config: { title: string; }): void; /** * Checks if a special query with the given title exists. * * @param {string} title - The title of the special query to check. * @returns {boolean} `true` if a special query with the title exists, otherwise `false`. * @throws {TypeError} If `title` is not a string. */ hasSpecialQuery(title: string): boolean; /** * Removes a special query identified by its title. * * If a query with the specified title exists, it is removed. * Otherwise, an error is thrown. * * @param {string} title - The title of the special query to remove. * @throws {TypeError} If `title` is not a string. * @throws {Error} If no special query with the given title exists. */ removeSpecialQuery(title: string): void; /** * Retrieves the title of a special query by its title key. * * This method checks if a special query with the given title exists * and returns its `parser` value. If not found, it throws an error. * * @param {string} title - The title of the special query to retrieve. * @returns {(function(string): string) | null} The function of the found special query. * @throws {TypeError} If `title` is not a string. * @throws {Error} If no special query with the given title exists. */ getSpecialQuery(title: string): ((arg0: string) => string) | null; /** * Returns a list of all special query titles. * * This is a shallow extraction of the `title` field from every item * in the internal `#specialQueries` array. * * @returns {string[]} An array of all special query titles. */ getAllSpecialQuery(): string[]; /** * Sets the name of the default SQL column used when building tag-based conditions. * * @param {string} value - Column name to be used as default (e.g. 'tags'). */ setColumnName(value: string): void; /** * Gets the current default SQL column name used for tag conditions. * * @returns {string} The name of the default column. */ getColumnName(): string; /** * Sets a limit on the number of items parsed from the search string. * Used to avoid overloading the engine with too many conditions. * * @param {number} value - Maximum number of items to parse (use -1 for no limit). */ setParseLimit(value: number): void; /** * Gets the current limit on how many tags are parsed from a search string. * * @returns {number} The current parse limit. */ getParseLimit(): number; /** * Enables or disables the use of `json_each()` in SQL statements. * This affects how JSON-based columns are traversed. * * @param {boolean} value - Whether to use `json_each()` in tag conditions. */ setUseJsonEach(value: boolean): void; /** * Sets the external table name name used in `EXISTS` subqueries, typically referencing `value`. * * @param {string} value - The alias to use in SQL subqueries (e.g. 'value'). */ setTableName(value: string): void; /** * Sets the raw SQL string used for the `json_each()` expression. * This is used for custom SQL generation. * * @param {string} value - The SQL snippet (e.g. "json_each(tags)"). */ setJsonEach(value: string): void; /** * Sets whether the engine is running in PostgreSQL mode. * * @param {boolean} value - Must be a boolean true/false. * @throws {TypeError} If the value is not a boolean. */ setIsPgMode(value: boolean): void; /** * Gets whether the engine is currently in PostgreSQL mode. * * @returns {boolean} */ getIsPgMode(): boolean; /** * Builds an SQL WHERE clause from a structured tag group definition. * * This method supports both direct equality and wildcard matching using custom * wildcard symbols (`wildcardA`, `wildcardB`). Tags can be negated with a leading `!`. * It generates nested `EXISTS` or `NOT EXISTS` subqueries depending on the `useJsonEach` flag. * * The method returns a string representing the SQL WHERE clause, and updates `pCache.values` * with the filtered values in proper order for parameterized queries. * * @param {Pcache} [pCache={ index: 1, values: [] }] - Placeholder cache object. * @param {TagCriteria} [group={}] - Tag group definition to build the clause from. * * @returns {string} The generated SQL condition string (e.g., `(EXISTS (...)) AND (NOT EXISTS (...))`). */ parseWhere(group?: TagCriteria, pCache?: Pcache): string; /** * Parses a search input string into structured query components. * * This method tokenizes the input string based on grouping (parentheses), logical * operators (`AND`, `OR`), and quoting (single or double). It supports optional * repetition control (`noRepeat`) and a configurable tag limit (`parseLimit`). * * The output is normalized into an `include` list of tags or OR-groups (arrays), * as well as dynamic sets of extracted metadata like `boosts`, `specials`, etc. * * This parser supports expressions like: * `applejack^2, "rainbow dash", (solo OR duo), pudding AND source:ponybooru` * * @param {string} input - The raw input string provided by the user. * @param {boolean} [strictMode=false] - Enables strict validation checks. * @param {Object} [strictConfig={}] - Optional validation rules for strict mode: * @param {boolean} [strictConfig.emptyInput=true] - Throw if input is empty after trimming. * @param {boolean} [strictConfig.parseLimit=true] - Enforce the parse limit (`this.parseLimit`). * @param {boolean} [strictConfig.openParens=true] - Require balanced parentheses. * @param {boolean} [strictConfig.quoteChar=true] - Require closing quotes if one is opened. * * @returns {ParseStringResult} An object containing: * - `column`: The column name from `this.getColumnName()`. * - `include`: Array of tags and OR-groups to include in the query. * - Additional properties (e.g., `boosts`, `specials`) depending on matches in `#tagInputs` or `#specialQueries`. * * Example return: * ```js * { * column: 'tags', * include: ['applejack', ['solo', 'duo'], 'pudding'], * boosts: [{ term: 'applejack', boost: 2 }], * specials: [{ key: 'source', value: 'ponybooru' }] * } * ``` */ parseString(input: string, strictMode?: boolean, strictConfig?: { emptyInput?: boolean | undefined; parseLimit?: boolean | undefined; openParens?: boolean | undefined; quoteChar?: boolean | undefined; }): ParseStringResult; /** * Sanitizes and normalizes a raw input string before parsing. * * This method prepares user input for parsing by replacing common symbolic * boolean operators (`&&`, `||`, `-`, `NOT`) with their textual equivalents * (`AND`, `OR`, `!`). It also trims whitespace and replaces commas with `AND` * to enforce consistent logical separation. * * This is useful when parsing user input that might come from flexible or * user-friendly interfaces where symbols are more commonly used than * structured boolean expressions. * * @param {string} input - The raw input string provided by the user. * @param {boolean} [strictMode=false] - Enables strict validation checks. * @param {Object} [strictConfig={}] - Optional validation rules for strict mode: * @param {boolean} [strictConfig.emptyInput=true] - Throw if input is empty after trimming. * @param {boolean} [strictConfig.parseLimit=true] - Enforce the parse limit (`this.parseLimit`). * @param {boolean} [strictConfig.openParens=true] - Require balanced parentheses. * @param {boolean} [strictConfig.quoteChar=true] - Require closing quotes if one is opened. * * @returns {ParseStringResult} A structured result object returned by `parseString()`, * containing keys like `column`, `include`, `specials`, `boosts`, etc., depending on * the tags and expressions detected. * * @example * safeParseString("applejack, -source, rarity || twilight") * // → equivalent to: parseString("applejack AND !source AND rarity OR twilight") */ safeParseString(input: string, strictMode?: boolean, strictConfig?: { emptyInput?: boolean | undefined; parseLimit?: boolean | undefined; openParens?: boolean | undefined; quoteChar?: boolean | undefined; }): ParseStringResult; #private; }