import { QueryEngine } from '@dbcube/core'; export interface JoinCondition { column1: string; operator: string; column2: string; } export interface Join { type: "INNER" | "LEFT" | "RIGHT"; table: string; on: JoinCondition; } export interface WhereCondition { column: string; operator: string; value?: any; type: "AND" | "OR"; isGroup: boolean; } export interface GroupedWhereCondition { type: "AND" | "OR"; isGroup: true; conditions: WhereCondition[]; } export interface OrderBy { column: string; direction: "ASC" | "DESC"; } export interface Aggregation { type: "COUNT" | "SUM" | "AVG" | "MAX" | "MIN"; column: string; alias: string; } export interface DML { type: "select" | "insert" | "update" | "delete" | "columns"; database: string; table: string; columns: string[]; requestedFields?: string[]; computedFieldsNeeded?: any[]; distinct: boolean; joins: Join[]; where: (WhereCondition | GroupedWhereCondition)[]; orderBy: OrderBy[]; groupBy: string[]; limit: number | null; offset: number | null; data: any[] | Record | null; aggregation: Aggregation | null; having?: (WhereCondition | GroupedWhereCondition)[]; } export interface PaginatedResult { items: T[]; page: number; perPage: number; total: number; totalPages: number; hasNext: boolean; hasPrev: boolean; } export interface RelationOptions { /** Child/related table name (defaults to the relation name) */ table?: string; /** FK column on the related table (hasMany) or on this table (belongsTo) */ foreignKey?: string; /** Key on the parent table (defaults to 'id') */ localKey?: string; /** 'many' attaches an array (hasMany), 'one' attaches a single record (belongsTo) */ type?: "many" | "one"; } export type WhereCallback = (query: Table) => void; export type DatabaseRecord = Record; /** Result row returned by write operations (update/delete/truncate/upsert). */ export interface MutationInfo { affectedRows?: number; affected_rows?: number; lastInsertId?: number | string; [key: string]: unknown; } /** A computed-field definition loaded from dbcube_computes_config. */ export interface ComputedFieldConfig { column: string; type: string; instruction: string; table_ref?: string; database_ref?: string; [key: string]: unknown; } /** A runtime-trigger definition loaded from dbcube_triggers_config. */ export interface TriggerConfig { type: string; table_ref: string; database_ref: string; name?: string; description?: string; [key: string]: unknown; } /** * Main class to handle MySQL database connections and queries. * Implements the Singleton pattern to ensure a single instance of the connection pool. */ export declare class Database { private name; private engine; private computedFields; private triggers; private txId; constructor(name: string); /** * Executes raw SQL (MySQL/PostgreSQL/SQLite) or a raw command document (MongoDB) * with bound parameters. The escape hatch for anything the builder doesn't cover. * * @example * const rows = await db.raw('SELECT * FROM users WHERE age > ?', [25]); * await db.raw('CREATE INDEX idx_users_email ON users(email)'); */ raw(query: string, params?: unknown[]): Promise; /** * Runs a callback inside a database transaction. Everything executed through * the received connection is committed atomically; any thrown error rolls * the whole transaction back. * * Requires daemon mode (enabled by default with an up-to-date query-engine). * * @example * await db.transaction(async (trx) => { * await trx.table('accounts').where('id', '=', 1).update({ balance: 50 }); * await trx.table('accounts').where('id', '=', 2).update({ balance: 150 }); * }); */ transaction(callback: (trx: Database) => Promise): Promise; /** * Atomic batch: every write queued in the callback runs inside ONE * transaction with a SINGLE engine round-trip (begin/commit included). * The callback is synchronous — writes are collected, not awaited. * Any failure rolls back everything. * * This is the fastest way to run a sequence of writes atomically. * For transactions that need to READ intermediate results, use * `transaction()` (interactive) instead. Triggers/computed fields do * not run in batch mode. * * @example * await db.batch(b => { * b.table('accounts').where('id', '=', 1).decrement('balance', 200); * b.table('accounts').where('id', '=', 2).increment('balance', 200); * }); */ batch(builder: (b: Database) => void): Promise; useComputes(): Promise; useTriggers(): Promise; connect(): Promise; disconnect(): Promise; /** * Creates and returns a new instance of `Table` for the specified table. * This method is used to start building queries for a specific table. * It provides a fluent interface for common database operations like select, insert, update, and delete. * * @param {string} tableName - The name of the table to query. * @returns {Table} - Returns a new instance of `Table` for the specified table. * * @example * // Select all records from a table * const users = await db.table('users').get(); * * // Select records with conditions * const activeUsers = await db.table('users') * .where('status', '=', 'active') * .orderBy('created_at', 'DESC') * .limit(10) * .get(); * * // Insert records * await db.table('users').insert([ * { name: 'John', email: 'john@example.com', age: 30 } * ]); * * // Update records * await db.table('users') * .where('id', '=', 1) * .update({ status: 'inactive' }); * * // Delete records * await db.table('users') * .where('status', '=', 'deleted') * .delete(); * * // Access column management * const columns = await db.table('users').columns().get(); */ table(tableName: string): Table; private setComputedFields; private setTriggers; } /** * Class to build and execute SQL queries for a specific table. * Supports operations like SELECT, INSERT, UPDATE, DELETE, and more. * * Generic over the row shape: `db.table('users').get()` resolves to * `Promise`. Pair it with the interfaces emitted by `dbcube generate`. */ export declare class Table { private engine; private nextType; private dml; private computedFields; private trigger; private triggers; private txId; private relations; /** Builders de grupo mutan en sitio (ver clone()) */ private _mutable; /** En modo batch (db.batch) las escrituras se encolan aquí en vez de * ejecutarse: toda la transacción viaja al engine en UN solo cruce. */ _batchSink: DML[] | null; private instance; constructor(instance: Database, databaseName: string, tableName: string, engine: QueryEngine, computedFields?: ComputedFieldConfig[], triggers?: TriggerConfig[], txId?: string | null); /** * Specifies the columns to select in a SELECT query. * * @param {string[]} fields - Array of column names to select. If empty, selects all columns. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').select(['id', 'name']).get(); * console.log(users); // [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] */ select(fields?: string[]): Table; /** * Adds a WHERE condition to the query. * * @param {string} column - The column to filter by. * @param {string} operator - The comparison operator (e.g., '=', '>', '<', 'IS NULL', 'IS NOT NULL'). * @param {any} value - The value to compare against (optional for IS NULL/IS NOT NULL). * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').where('age', '>', 25).get(); * const nullUsers = await db.table('users').where('email', 'IS NULL').get(); * console.log(users); // [{ id: 1, name: 'John', age: 30 }] */ where(column: string, operator: "IS NULL" | "IS NOT NULL"): Table; where(column: string, operator: "=" | "!=" | "<>" | ">" | "<" | ">=" | "<=" | "LIKE" | "NOT LIKE" | "IN" | "NOT IN" | "BETWEEN" | "NOT BETWEEN", value: any): Table; /** * Adds an OR WHERE condition to the query. * * @param {string} column - The column to filter by. * @param {string} operator - The comparison operator (e.g., '=', '>', '<', 'IS NULL', 'IS NOT NULL'). * @param {any} value - The value to compare against (optional for IS NULL/IS NOT NULL). * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').where('age', '>', 25).orWhere('name', '=', 'Jane').get(); * const nullUsers = await db.table('users').where('active', '=', true).orWhere('email', 'IS NULL').get(); * console.log(users); // [{ id: 1, name: 'John', age: 30 }, { id: 2, name: 'Jane', age: 25 }] */ orWhere(column: string, operator: "IS NULL" | "IS NOT NULL"): Table; orWhere(column: string, operator: "=" | "!=" | "<>" | ">" | "<" | ">=" | "<=" | "LIKE" | "NOT LIKE" | "IN" | "NOT IN" | "BETWEEN" | "NOT BETWEEN", value: any): Table; /** * Adds a grouped WHERE condition to the query. * * @param {WhereCallback} callback - A callback function that receives a new Table instance to build the grouped conditions. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').whereGroup(query => { * query.where('age', '>', 25).orWhere('name', '=', 'Jane'); * }).get(); * console.log(users); // [{ id: 1, name: 'John', age: 30 }, { id: 2, name: 'Jane', age: 25 }] */ whereGroup(callback: WhereCallback): Table; or(): Table; and(): Table; /** * Adds a WHERE BETWEEN condition to the query. * * @param {string} column - The column to filter by. * @param {[any, any]} values - A tuple with two values representing the range. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').whereBetween('age', [20, 30]).get(); * console.log(users); // [{ id: 1, name: 'John', age: 30 }, { id: 2, name: 'Jane', age: 25 }] */ whereBetween(column: string, values: [ any, any ]): Table; /** * Adds a WHERE IN condition to the query. * * @param {string} column - The column to filter by. * @param {any[]} values - An array of values to match. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').whereIn('id', [1, 2]).get(); * console.log(users); // [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] */ whereIn(column: string, values: any[]): Table; /** * Adds a WHERE IS NULL condition to the query. * * @param {string} column - The column to filter by. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').whereNull('email').get(); * console.log(users); // [{ id: 3, name: 'Alice', email: null }] */ whereNull(column: string): Table; /** * Adds a WHERE IS NOT NULL condition to the query. * * @param {string} column - The column to filter by. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').whereNotNull('email').get(); * console.log(users); // [{ id: 1, name: 'John', email: 'john@example.com' }] */ whereNotNull(column: string): Table; /** * Adds a JOIN clause to the query. * * @param {string} table - The table to join. * @param {string} column1 - The column from the current table. * @param {string} operator - The comparison operator (e.g., '=', '>', '<'). * @param {string} column2 - The column from the joined table. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').join('orders', 'users.id', '=', 'orders.user_id').get(); * console.log(users); // [{ id: 1, name: 'John', order_id: 101 }] */ join(table: string, column1: string, operator: string, column2: string): Table; /** * Adds a LEFT JOIN clause to the query. * * @param {string} table - The table to join. * @param {string} column1 - The column from the current table. * @param {string} operator - The comparison operator (e.g., '=', '>', '<'). * @param {string} column2 - The column from the joined table. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').leftJoin('orders', 'users.id', '=', 'orders.user_id').get(); * console.log(users); // [{ id: 1, name: 'John', order_id: 101 }, { id: 2, name: 'Jane', order_id: null }] */ leftJoin(table: string, column1: string, operator: string, column2: string): Table; /** * Adds a RIGHT JOIN clause to the query. * * @param {string} table - The table to join. * @param {string} column1 - The column from the current table. * @param {string} operator - The comparison operator (e.g., '=', '>', '<'). * @param {string} column2 - The column from the joined table. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').rightJoin('orders', 'users.id', '=', 'orders.user_id').get(); * console.log(users); // [{ id: 1, name: 'John', order_id: 101 }, { id: null, name: null, order_id: 102 }] */ rightJoin(table: string, column1: string, operator: string, column2: string): Table; /** * Adds an ORDER BY clause to the query. * * @param {string} column - The column to order by. * @param {'ASC' | 'DESC'} direction - The sorting direction ('ASC' or 'DESC'). * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').orderBy('name', 'ASC').get(); * console.log(users); // [{ id: 2, name: 'Jane' }, { id: 1, name: 'John' }] */ orderBy(column: string, direction?: "ASC" | "DESC"): Table; /** * Adds a GROUP BY clause to the query. * * @param {string} column - The column to group by. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').groupBy('age').get(); * console.log(users); // [{ age: 30, count: 1 }, { age: 25, count: 1 }] */ groupBy(column: string): Table; /** * Adds a DISTINCT clause to the query. * * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').distinct().select(['name']).get(); * console.log(users); // [{ name: 'John' }, { name: 'Jane' }] */ distinct(): Table; /** * Adds a COUNT clause to the query. * * @param {string} column - The column to count (default is '*'). * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const count = await db.table('users').count().first(); * console.log(count); // { count: 2 } */ count(column?: string): Promise; /** * Adds a SUM clause to the query. * * @param {string} column - The column to sum. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const totalAge = await db.table('users').sum('age').first(); * console.log(totalAge); // { sum: 55 } */ sum(column: string): Promise; /** * Adds an AVG clause to the query. * * @param {string} column - The column to calculate the average. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const avgAge = await db.table('users').avg('age').first(); * console.log(avgAge); // { avg: 27.5 } */ avg(column: string): Promise; /** * Adds a MAX clause to the query. * * @param {string} column - The column to find the maximum value. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const maxAge = await db.table('users').max('age').first(); * console.log(maxAge); // { max: 30 } */ max(column: string): Promise; /** * Adds a MIN clause to the query. * * @param {string} column - The column to find the minimum value. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const minAge = await db.table('users').min('age').first(); * console.log(minAge); // { min: 25 } */ min(column: string): Promise; /** * Gets the column names of the table. * For SQL databases (MySQL, PostgreSQL, SQLite), returns a simple array of column names. * For MongoDB, returns a hierarchical structure with nested documents. * * @returns {Promise} - Returns an array of column names for SQL databases, * or a hierarchical structure for MongoDB. * * @example * // SQL databases (MySQL, PostgreSQL, SQLite) * const columns = await db.table('users').columns(); * console.log(columns); // ['id', 'name', 'email', 'age', 'created_at'] * * @example * // MongoDB * const structure = await db.table('users').columns(); * console.log(structure); * // { * // columns: ['id', 'name', 'profile'], * // submenu: { * // profile: { * // columns: ['age', 'city'], * // submenu: {} * // } * // } * // } */ columns(): Promise; /** * Adds a LIMIT clause to the query. * * @param {number} number - The maximum number of rows to return. * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').limit(1).get(); * console.log(users); // [{ id: 1, name: 'John', age: 30 }] */ limit(number: number): Table; /** * Adds pagination to the query using LIMIT and OFFSET. * * @param {number} number - The page number (starting from 1). * @returns {Table} - Returns the current instance of Table for method chaining. * * @example * const users = await db.table('users').limit(1).page(2).get(); * console.log(users); // [{ id: 2, name: 'Jane', age: 25 }] */ page(number: number): Table; /** * Executes the query and returns all matching rows. * * @returns {Promise} - Returns an array of rows. * * @example * const users = await db.table('users').get(); * console.log(users); // [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }] */ get(): Promise; /** * Executes the query and returns the first matching row. * * @returns {Promise} - Returns the first row or null if no rows match. * * @example * const user = await db.table('users').first(); * console.log(user); // { id: 1, name: 'John' } */ first(): Promise; /** * Finds a row by a specific column value. * * @param {any} value - The value to search for. * @param {string} column - The column to search in (default is 'id'). * @returns {Promise} - Returns the first matching row or null if no rows match. * * @example * const user = await db.table('users').find(1); * console.log(user); // { id: 1, name: 'John' } */ find(value: string | number, column?: string): Promise; /** * Inserts one or more rows into the table. * * @param {DatabaseRecord[]} data - An array of objects representing the rows to insert. * @returns {Promise} - Returns an array of the inserted rows. * * @example * const newUsers = await db.table('users').insert([ * { name: 'Alice', age: 28 }, * { name: 'Bob', age: 32 } * ]); * console.log(newUsers); // [{ id: 3, name: 'Alice', age: 28 }, { id: 4, name: 'Bob', age: 32 }] */ insert(data: Partial[]): Promise; /** * Updates rows in the table based on the defined conditions. * * @param {DatabaseRecord} data - An object with key-value pairs representing the fields to update. * @returns {Promise} - Returns the result of the update operation. * * @example * const result = await db.table('users') * .where('id', '=', 1) * .update({ name: 'John Updated', age: 31 }); * console.log(result); // { affectedRows: 1 } */ update(data: Partial): Promise; /** * Deletes rows from the table based on the defined conditions. * * @returns {Promise} - Returns the result of the delete operation. * * @example * const result = await db.table('users').where('id', '=', 1).delete(); * console.log(result); // { affectedRows: 1 } */ delete(): Promise; /** * Adds a WHERE NOT IN condition to the query. * * @example * const users = await db.table('users').whereNotIn('status', ['banned', 'deleted']).get(); */ whereNotIn(column: string, values: any[]): Table; /** * Sets an explicit OFFSET for the query (alternative to page()). * * @example * const rows = await db.table('logs').orderBy('id', 'ASC').limit(50).offset(100).get(); */ offset(number: number): Table; /** * Appends raw expressions to the SELECT list (aggregates, functions, aliases). * Combine with groupBy() and having() for per-group metrics. * * @example * const stats = await db.table('orders') * .select(['user_id']) * .selectRaw(['COUNT(*) AS order_count', 'SUM(amount) AS total']) * .groupBy('user_id') * .having('order_count', '>', 5) * .get(); */ selectRaw(expressions: string[]): Table; /** * Adds a HAVING condition (filters grouped results). * * @example * .groupBy('user_id').having('COUNT(*)', '>', 5) */ having(column: string, operator: string, value?: any): Table; /** * Checks if at least one row matches the current conditions. * Cheaper than first(): selects a constant with LIMIT 1. * * @example * const taken = await db.table('users').where('email', '=', email).exists(); */ exists(): Promise; /** * Fetches one page of results plus pagination metadata in a single call. * Runs the page query and the total count with the same conditions. * * @example * const { items, total, totalPages, hasNext } = await db.table('products') * .where('published', '=', true) * .orderBy('id', 'ASC') * .paginate(2, 25); */ paginate(page?: number, perPage?: number): Promise>; /** * Processes all matching rows in batches of `size`, keeping memory flat. * Return `false` from the callback to stop early. * * @example * await db.table('logs').orderBy('id', 'ASC').chunk(500, async (rows) => { * await processBatch(rows); * }); */ chunk(size: number, callback: (rows: T[], page: number) => Promise | void | boolean): Promise; /** * Atomically increments a numeric column: `SET col = col + amount`. * Requires at least one WHERE condition. Extra fields can be updated in the same statement. * * @example * await db.table('products').where('id', '=', 5).increment('stock', 3); * await db.table('posts').where('id', '=', 1).increment('views', 1, { last_viewed_at: new Date().toISOString() }); */ increment(column: string, amount?: number, extra?: Partial): Promise; /** * Atomically decrements a numeric column: `SET col = col - amount`. * * @example * await db.table('products').where('id', '=', 5).decrement('stock', 1); */ decrement(column: string, amount?: number, extra?: Partial): Promise; /** * Deletes ALL rows from the table. The only write operation allowed * without a WHERE — the destructive intent is explicit in the name. * * @example * await db.table('temp_imports').truncate(); */ truncate(): Promise; /** * Inserts rows, updating them instead when a conflict occurs on the given keys. * MySQL → ON DUPLICATE KEY UPDATE · PostgreSQL/SQLite → ON CONFLICT ... DO UPDATE. * * @param data Rows to insert. * @param conflictKeys Column(s) with the UNIQUE/PK constraint that triggers the update. * @param updateColumns Columns to overwrite on conflict (defaults to every non-conflict column). * * @example * await db.table('settings').upsert( * [{ key: 'theme', value: 'dark' }], * ['key'] * ); */ upsert(data: Partial[], conflictKeys: string[], updateColumns?: string[]): Promise; /** * Declares a relation to eager-load with the results of get(). * Relations are resolved from `foreign` definitions in your .cube files, * or explicitly via options. Loads each relation with ONE batched query * (whereIn) — no N+1. * * @example * // hasMany: orders.user_id → users.id (auto-detected from orders.table.cube) * const users = await db.table('users').with('orders').get(); * // users[0].orders === [{...}, {...}] * * // belongsTo: posts.author_id → users.id, attached as a single object * const posts = await db.table('posts') * .with('author', { table: 'users', foreignKey: 'author_id', type: 'one' }) * .get(); */ with(relation: string, options?: RelationOptions): Table; private attachRelations; private getResponse; private clone; } export { Database as default, }; export {};