Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@athenna/database

Package Overview
Dependencies
Maintainers
1
Versions
205
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@athenna/database - npm Package Compare versions

Comparing version
5.38.0
to
5.39.0
+438
src/database/drivers/BaseKnexDriver.d.ts
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { type PaginatedResponse, type PaginationOptions } from '@athenna/common';
import type { Knex } from 'knex';
import { Driver } from '#src/database/drivers/Driver';
import { Transaction } from '#src/database/transactions/Transaction';
import type { ConnectionOptions, Direction, Operations } from '#src/types';
export declare class BaseKnexDriver extends Driver<Knex, Knex.QueryBuilder> {
/**
* Connect to database.
*/
connect(options?: ConnectionOptions): void;
/**
* Close the connection with database in this instance.
*/
close(): Promise<void>;
/**
* Creates a new instance of query builder.
*/
query(): Knex.QueryBuilder;
/**
* Sync a model schema with database.
*/
sync(): Promise<void>;
/**
* Create a new transaction.
*/
startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>;
/**
* Commit the transaction.
*/
commitTransaction(): Promise<void>;
/**
* Rollback the transaction.
*/
rollbackTransaction(): Promise<void>;
/**
* Run database migrations.
*/
runMigrations(): Promise<void>;
/**
* Revert database migrations.
*/
revertMigrations(): Promise<void>;
/**
* List all databases available.
*/
getDatabases(): Promise<string[]>;
/**
* Get the current database name.
*/
getCurrentDatabase(): Promise<string | undefined>;
/**
* Verify if database exists.
*/
hasDatabase(database: string): Promise<boolean>;
/**
* Create a new database.
*/
createDatabase(database: string): Promise<void>;
/**
* Drop some database.
*/
dropDatabase(database: string): Promise<void>;
/**
* List all tables available.
*/
getTables(): Promise<string[]>;
/**
* Verify if table exists.
*/
hasTable(table: string): Promise<boolean>;
/**
* Create a new table in database.
*/
createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Alter a table in database.
*/
alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Drop a table in database.
*/
dropTable(table: string): Promise<void>;
/**
* Remove all data inside some database table
* and restart the identity of the table.
*/
truncate(table: string): Promise<void>;
/**
* Make a raw query in database.
*/
raw<T = any>(sql: string, bindings?: any): T;
/**
* Calculate the average of a given column.
*/
avg(column: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
avgDistinct(column: string): Promise<string>;
/**
* Get the max number of a given column.
*/
max(column: string): Promise<string>;
/**
* Get the min number of a given column.
*/
min(column: string): Promise<string>;
/**
* Sum all numbers of a given column.
*/
sum(column: string): Promise<string>;
/**
* Sum all numbers of a given column in distinct mode.
*/
sumDistinct(column: string): Promise<string>;
/**
* Increment a value of a given column.
*/
increment(column: string): Promise<void>;
/**
* Decrement a value of a given column.
*/
decrement(column: string): Promise<void>;
/**
* Calculate the average of a given column using distinct.
*/
count(column?: string): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string): Promise<number>;
/**
* Find a value in database.
*/
find<T = any>(): Promise<T>;
/**
* Find many values in database.
*/
findMany<T = any>(): Promise<T[]>;
/**
* Find many values in database and return as paginated response.
*/
paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>;
/**
* Create a value in database.
*/
create<T = any>(data?: Partial<T>): Promise<T>;
/**
* Create many values in database.
*/
createMany<T = any>(data?: Partial<T>[]): Promise<T[]>;
/**
* Create data or update if already exists.
*/
createOrUpdate<T = any>(data: Partial<T>): Promise<T>;
/**
* Update a value in database.
*/
update<T = any>(data: Partial<T>): Promise<T | T[]>;
/**
* Stringify object-like values before persisting with Knex.
*/
protected prepareInsert<T = any>(data: Partial<T>): Partial<T>;
/**
* Verify if a value should be serialized before persisting.
*/
private shouldStringifyJsonValue;
/**
* Delete one value in database.
*/
delete(): Promise<void>;
/**
* Set the table that this query will be executed.
*/
table(table: string): this;
/**
* Log in console the actual query built.
*/
dump(): this;
/**
* Set the columns that should be selected on query.
*/
select(...columns: string[]): this;
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql: string, bindings?: any): this;
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table: string): this;
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql: string, bindings?: any): this;
/**
* Set a join statement in your query.
*/
join(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left join statement in your query.
*/
leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right join statement in your query.
*/
rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a cross join statement in your query.
*/
crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a join raw statement in your query.
*/
joinRaw(sql: string, bindings?: any): this;
/**
* Set a group by statement in your query.
*/
groupBy(...columns: string[]): this;
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql: string, bindings?: any): this;
having(column: string): this;
having(column: string, value: any): this;
having(column: string, operation: Operations, value: any): this;
/**
* Set a having raw statement in your query.
*/
havingRaw(sql: string, bindings?: any): this;
/**
* Set a having in statement in your query.
*/
havingIn(column: string, values: any[]): this;
/**
* Set a having not in statement in your query.
*/
havingNotIn(column: string, values: any[]): this;
/**
* Set a having between statement in your query.
*/
havingBetween(column: string, values: [any, any]): this;
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column: string, values: [any, any]): this;
/**
* Set a having null statement in your query.
*/
havingNull(column: string): this;
/**
* Set a having not null statement in your query.
*/
havingNotNull(column: string): this;
orHaving(column: string): this;
orHaving(column: string, value: any): this;
orHaving(column: string, operation: Operations, value: any): this;
/**
* Set an or having raw statement in your query.
*/
orHavingRaw(sql: string, bindings?: any): this;
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column: string, values: any[]): this;
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column: string, values: [any, any]): this;
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column: string, values: [any, any]): this;
/**
* Set an or having null statement in your query.
*/
orHavingNull(column: string): this;
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column: string): this;
where(statement: Record<string, any>): this;
where(key: string, value: any): this;
where(key: string, operation: Operations, value: any): this;
whereNot(statement: Record<string, any>): this;
whereNot(key: string, value: any): this;
/**
* Set a where raw statement in your query.
*/
whereRaw(sql: string, bindings?: any): this;
/**
* Set a where exists statement in your query.
*/
whereExists(closure: (query: BaseKnexDriver) => void): this;
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure: (query: BaseKnexDriver) => void): this;
/**
* Set a where like statement in your query.
*/
whereLike(column: string, value: any): this;
/**
* Set a where ILike statement in your query.
*/
whereILike(column: string, value: any): this;
/**
* Set a where in statement in your query.
*/
whereIn(column: string, values: any[]): this;
/**
* Set a where not in statement in your query.
*/
whereNotIn(column: string, values: any[]): this;
/**
* Set a where between statement in your query.
*/
whereBetween(column: string, values: [any, any]): this;
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column: string, values: [any, any]): this;
/**
* Set a where null statement in your query.
*/
whereNull(column: string): this;
/**
* Set a where not null statement in your query.
*/
whereNotNull(column: string): this;
whereJson(column: string, value: any): this;
whereJson(column: string, operation: Operations, value: any): this;
orWhere(statement: Record<string, any>): this;
orWhere(key: string, value: any): this;
orWhere(key: string, operation: Operations, value: any): this;
orWhereNot(statement: Record<string, any>): this;
orWhereNot(key: string, value: any): this;
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql: string, bindings?: any): this;
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure: (query: BaseKnexDriver) => void): this;
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure: (query: BaseKnexDriver) => void): this;
/**
* Set an or where like statement in your query.
*/
orWhereLike(column: string, value: any): this;
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column: string, value: any): this;
/**
* Set an or where in statement in your query.
*/
orWhereIn(column: string, values: any[]): this;
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column: string, values: any[]): this;
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column: string, values: [any, any]): this;
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column: string, values: [any, any]): this;
/**
* Set an or where null statement in your query.
*/
orWhereNull(column: string): this;
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column: string): this;
orWhereJson(column: string, value: any): this;
orWhereJson(column: string, operation: Operations, value: any): this;
/**
* Convert a json selector path to a valid json path.
*/
private parseJsonSelectorToPath;
/**
* Set an order by statement in your query.
*/
orderBy(column: string, direction?: Direction): this;
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql: string, bindings?: any): this;
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column?: string): this;
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column?: string): this;
/**
* Set the skip number in your query.
*/
offset(number: number): this;
/**
* Set the limit number in your query.
*/
limit(number: number): this;
}
/* eslint-disable @typescript-eslint/ban-ts-comment */
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Exec, Is, Json, Options } from '@athenna/common';
import { debug } from '#src/debug';
import { Log } from '@athenna/logger';
import { Driver } from '#src/database/drivers/Driver';
import { ConnectionFactory } from '#src/factories/ConnectionFactory';
import { Transaction } from '#src/database/transactions/Transaction';
import { MigrationSource } from '#src/database/migrations/MigrationSource';
import { EmptyValueException } from '#src/exceptions/EmptyValueException';
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
import { WrongMethodException } from '#src/exceptions/WrongMethodException';
import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods';
import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException';
export class BaseKnexDriver extends Driver {
/**
* Connect to database.
*/
connect(options = {}) {
options = Options.create(options, {
force: false,
saveOnFactory: true,
connect: true
});
if (!options.connect) {
return;
}
if (this.isConnected && !options.force) {
return;
}
const knex = this.getKnex();
const configs = Config.get(`database.connections.${this.connection}`, {});
const knexOpts = {
migrations: {
tableName: 'migrations'
},
pool: {
min: 2,
max: 20,
acquireTimeoutMillis: 60 * 1000
},
debug: false,
useNullAsDefault: false,
...Json.omit(configs, ['driver', 'validations'])
};
debug('creating new connection using Knex. options defined: %o', knexOpts);
if (Config.is('rc.bootLogs', true)) {
Log.channelOrVanilla('application').success(`Successfully connected to ({yellow} ${this.connection}) database connection`);
}
this.client = knex.default(knexOpts);
this.isConnected = true;
this.isSavedOnFactory = options.saveOnFactory;
if (this.isSavedOnFactory) {
ConnectionFactory.setClient(this.connection, this.client);
}
this.qb = this.query();
}
/**
* Close the connection with database in this instance.
*/
async close() {
if (!this.isConnected) {
return;
}
await this.client.destroy();
this.qb = null;
this.tableName = null;
this.client = null;
this.isConnected = false;
ConnectionFactory.setClient(this.connection, null);
}
/**
* Creates a new instance of query builder.
*/
query() {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
}
const query = this.useSetQB
? this.qb.table(this.tableName)
: this.client.queryBuilder().table(this.tableName);
const handler = {
get: (target, propertyKey) => {
if (PROTECTED_QUERY_METHODS.includes(propertyKey)) {
this.qb = this.query();
}
return target[propertyKey];
}
};
return new Proxy(query, handler);
}
/**
* Sync a model schema with database.
*/
async sync() {
debug(`database sync with ${this.constructor.name} is not available yet, use migration instead.`);
}
/**
* Create a new transaction.
*/
async startTransaction() {
const trx = await this.client.transaction();
return new Transaction(this.clone().setClient(trx));
}
/**
* Commit the transaction.
*/
async commitTransaction() {
const client = this.client;
await client.commit();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Rollback the transaction.
*/
async rollbackTransaction() {
const client = this.client;
await client.rollback();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Run database migrations.
*/
async runMigrations() {
await this.client.migrate.latest({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* Revert database migrations.
*/
async revertMigrations() {
await this.client.migrate.rollback({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* List all databases available.
*/
async getDatabases() {
const [databases] = await this.raw('SHOW DATABASES');
return databases.map(database => database.Database);
}
/**
* Get the current database name.
*/
async getCurrentDatabase() {
return this.client.client.database();
}
/**
* Verify if database exists.
*/
async hasDatabase(database) {
const databases = await this.getDatabases();
return databases.includes(database);
}
/**
* Create a new database.
*/
async createDatabase(database) {
await this.raw('CREATE DATABASE IF NOT EXISTS ??', database);
}
/**
* Drop some database.
*/
async dropDatabase(database) {
await this.raw('DROP DATABASE IF EXISTS ??', database);
}
/**
* List all tables available.
*/
async getTables() {
const [tables] = await this.raw('SELECT table_name FROM information_schema.tables WHERE table_schema = ?', await this.getCurrentDatabase());
return tables.map(table => table.TABLE_NAME);
}
/**
* Verify if table exists.
*/
async hasTable(table) {
return this.client.schema.hasTable(table);
}
/**
* Create a new table in database.
*/
async createTable(table, closure) {
await this.client.schema.createTable(table, closure);
}
/**
* Alter a table in database.
*/
async alterTable(table, closure) {
await this.client.schema.alterTable(table, closure);
}
/**
* Drop a table in database.
*/
async dropTable(table) {
await this.client.schema.dropTableIfExists(table);
}
/**
* Remove all data inside some database table
* and restart the identity of the table.
*/
async truncate(table) {
try {
await this.raw('SET FOREIGN_KEY_CHECKS = 0');
await this.raw('TRUNCATE TABLE ??', table);
}
finally {
await this.raw('SET FOREIGN_KEY_CHECKS = 1');
}
}
/**
* Make a raw query in database.
*/
raw(sql, bindings) {
return this.client.raw(sql, bindings);
}
/**
* Calculate the average of a given column.
*/
async avg(column) {
const [{ avg }] = await this.qb.avg({ avg: column });
return avg;
}
/**
* Calculate the average of a given column using distinct.
*/
async avgDistinct(column) {
const [{ avg }] = await this.qb.avgDistinct({ avg: column });
return avg;
}
/**
* Get the max number of a given column.
*/
async max(column) {
const [{ max }] = await this.qb.max({ max: column });
return max;
}
/**
* Get the min number of a given column.
*/
async min(column) {
const [{ min }] = await this.qb.min({ min: column });
return min;
}
/**
* Sum all numbers of a given column.
*/
async sum(column) {
const [{ sum }] = await this.qb.sum({ sum: column });
return sum;
}
/**
* Sum all numbers of a given column in distinct mode.
*/
async sumDistinct(column) {
const [{ sum }] = await this.qb.sumDistinct({ sum: column });
return sum;
}
/**
* Increment a value of a given column.
*/
async increment(column) {
await this.qb.increment(column);
}
/**
* Decrement a value of a given column.
*/
async decrement(column) {
await this.qb.decrement(column);
}
/**
* Calculate the average of a given column using distinct.
*/
async count(column = '*') {
const [{ count }] = await this.qb.count({ count: column });
return Number(count);
}
/**
* Calculate the average of a given column using distinct.
*/
async countDistinct(column) {
const [{ count }] = await this.qb.countDistinct({ count: column });
return Number(count);
}
/**
* Find a value in database.
*/
async find() {
return this.qb.first();
}
/**
* Find many values in database.
*/
async findMany() {
const data = await this.qb;
this.qb = this.query();
return data;
}
/**
* Find many values in database and return as paginated response.
*/
async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') {
if (Is.Number(page)) {
page = { page, limit, resourceUrl };
}
const [{ count }] = await this.qb
.clone()
.clearOrder()
.clearSelect()
.count({ count: '*' });
const data = await this.offset(page.page * page.limit)
.limit(page.limit)
.findMany();
return Exec.pagination(data, Number(count), page);
}
/**
* Create a value in database.
*/
async create(data = {}) {
if (Is.Array(data)) {
throw new WrongMethodException('create', 'createMany');
}
const created = await this.createMany([data]);
return created[0];
}
/**
* Create many values in database.
*/
async createMany(data = []) {
if (!Is.Array(data)) {
throw new WrongMethodException('createMany', 'create');
}
const preparedData = data.map(data => this.prepareInsert(data));
const ids = [];
const promises = preparedData.map((prepared, index) => {
return this.qb
.clone()
.insert(prepared)
.then(([id]) => ids.push(data[index][this.primaryKey] || id));
});
await Promise.all(promises);
return this.whereIn(this.primaryKey, ids).findMany();
}
/**
* Create data or update if already exists.
*/
async createOrUpdate(data) {
const query = this.qb.clone();
const hasValue = await query.first();
const preparedData = this.prepareInsert(data);
if (hasValue) {
await this.qb
.where(this.primaryKey, hasValue[this.primaryKey])
.limit(1)
.update(preparedData);
return this.where(this.primaryKey, hasValue[this.primaryKey]).find();
}
return this.create(data);
}
/**
* Update a value in database.
*/
async update(data) {
const preparedData = this.prepareInsert(data);
await this.qb.clone().update(preparedData);
const result = await this.findMany();
if (result.length === 1) {
return result[0];
}
return result;
}
/**
* Stringify object-like values before persisting with Knex.
*/
prepareInsert(data) {
return Object.entries(data).reduce((prepared, [key, value]) => {
if (!this.shouldStringifyJsonValue(value)) {
prepared[key] = value;
return prepared;
}
prepared[key] = JSON.stringify(value);
return prepared;
}, {});
}
/**
* Verify if a value should be serialized before persisting.
*/
shouldStringifyJsonValue(value) {
return !!value && (Is.Array(value) || Is.Object(value));
}
/**
* Delete one value in database.
*/
async delete() {
await this.qb.delete();
}
/**
* Set the table that this query will be executed.
*/
table(table) {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
}
if (!Is.String(table)) {
throw new Error('Table must be a string value');
}
this.tableName = table;
this.qb = this.query();
return this;
}
/**
* Log in console the actual query built.
*/
dump() {
process.stdout.write(`${JSON.stringify(this.qb.toSQL().toNative())}\n`);
return this;
}
/**
* Set the columns that should be selected on query.
*/
select(...columns) {
if (!Is.Array(columns)) {
throw new EmptyValueException('select');
}
this.qb.select(...columns);
return this;
}
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql, bindings) {
if (Is.Undefined(sql)) {
throw new EmptyValueException('selectRaw');
}
return this.select(this.raw(sql, bindings));
}
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table) {
if (Is.Undefined(table)) {
throw new Error('Table must be a string value');
}
this.qb.from(table);
return this;
}
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql, bindings) {
if (Is.Undefined(sql)) {
throw new EmptyValueException('fromRaw');
}
return this.from(this.raw(sql, bindings));
}
/**
* Set a join statement in your query.
*/
join(table, column1, operation, column2) {
return this.joinByType('join', table, column1, operation, column2);
}
/**
* Set a left join statement in your query.
*/
leftJoin(table, column1, operation, column2) {
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a right join statement in your query.
*/
rightJoin(table, column1, operation, column2) {
return this.joinByType('rightJoin', table, column1, operation, column2);
}
/**
* Set a cross join statement in your query.
*/
crossJoin(table, column1, operation, column2) {
return this.joinByType('crossJoin', table, column1, operation, column2);
}
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table, column1, operation, column2) {
// TODO https://github.com/knex/knex/issues/3949
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table, column1, operation, column2) {
return this.joinByType('leftOuterJoin', table, column1, operation, column2);
}
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table, column1, operation, column2) {
return this.joinByType('rightOuterJoin', table, column1, operation, column2);
}
/**
* Set a join raw statement in your query.
*/
joinRaw(sql, bindings) {
if (Is.Undefined(sql)) {
throw new EmptyValueException('joinRaw');
}
this.qb.joinRaw(sql, bindings);
return this;
}
/**
* Set a group by statement in your query.
*/
groupBy(...columns) {
if (Is.Undefined(columns)) {
throw new EmptyColumnException('groupBy');
}
this.qb.groupBy(...columns);
return this;
}
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql, bindings) {
if (Is.Undefined(sql)) {
throw new EmptyValueException('groupByRaw');
}
this.qb.groupByRaw(sql, bindings);
return this;
}
/**
* Set a having statement in your query.
*/
having(column, operation, value) {
if (Is.Undefined(operation)) {
if (Is.Undefined(column)) {
throw new EmptyColumnException('having');
}
this.qb.having(column);
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('having');
}
if (Is.Undefined(operation)) {
throw new EmptyValueException('having');
}
this.qb.having(column, '=', operation);
return this;
}
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('having');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('having');
}
this.qb.having(column, operation, value);
return this;
}
/**
* Set a having raw statement in your query.
*/
havingRaw(sql, bindings) {
if (Is.Undefined(sql)) {
throw new EmptyValueException('havingRaw');
}
this.qb.havingRaw(sql, bindings);
return this;
}
/**
* Set a having in statement in your query.
*/
havingIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('havingIn');
}
this.qb.havingIn(column, values);
return this;
}
/**
* Set a having not in statement in your query.
*/
havingNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('havingNotIn');
}
this.qb.havingNotIn(column, values);
return this;
}
/**
* Set a having between statement in your query.
*/
havingBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('havingBetween');
}
this.qb.havingBetween(column, values);
return this;
}
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('havingNotBetween');
}
this.qb.havingNotBetween(column, values);
return this;
}
/**
* Set a having null statement in your query.
*/
havingNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingNull');
}
this.qb.havingNull(column);
return this;
}
/**
* Set a having not null statement in your query.
*/
havingNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('havingNotNull');
}
this.qb.havingNotNull(column);
return this;
}
/**
* Set an or having statement in your query.
*/
orHaving(column, operation, value) {
if (Is.Undefined(operation)) {
if (Is.Undefined(column)) {
throw new EmptyColumnException('orHaving');
}
this.qb.orHaving(column);
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHaving');
}
if (Is.Undefined(operation)) {
throw new EmptyValueException('orHaving');
}
this.qb.orHaving(column, '=', operation);
return this;
}
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHaving');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orHaving');
}
this.qb.orHaving(column, operation, value);
return this;
}
/**
* Set an or having raw statement in your query.
*/
orHavingRaw(sql, bindings) {
if (Is.Undefined(sql) || !Is.String(sql)) {
throw new EmptyValueException('orHavingRaw');
}
this.qb.orHavingRaw(sql, bindings);
return this;
}
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHavingNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('orHavingNotIn');
}
this.qb.orHavingNotIn(column, values);
return this;
}
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHavingBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orHavingBetween');
}
this.qb.orHavingBetween(column, values);
return this;
}
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHavingNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orHavingNotBetween');
}
this.qb.orHavingNotBetween(column, values);
return this;
}
/**
* Set an or having null statement in your query.
*/
orHavingNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHavingNull');
}
this.qb.orHavingNull(column);
return this;
}
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orHavingNotNull');
}
this.qb.orHavingNotNull(column);
return this;
}
/**
* Set a where statement in your query.
*/
where(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.where(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (Is.Undefined(operation)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('where');
}
this.qb.where(statement);
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyValueException('where');
}
if (this.isUsingJsonSelector(statement)) {
this.whereJson(statement, operation);
return this;
}
this.qb.where(statement, operation);
return this;
}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('where');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('where');
}
if (this.isUsingJsonSelector(statement)) {
this.whereJson(statement, operation, value);
return this;
}
this.qb.where(statement, operation, value);
return this;
}
/**
* Set a where not statement in your query.
*/
whereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.whereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('whereNot');
}
this.qb.whereNot(statement);
return this;
}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('whereNot');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('whereNot');
}
this.qb.whereNot(statement, value);
return this;
}
/**
* Set a where raw statement in your query.
*/
whereRaw(sql, bindings) {
if (Is.Undefined(sql) || !Is.String(sql)) {
throw new EmptyValueException('whereRaw');
}
this.qb.whereRaw(sql, bindings);
return this;
}
/**
* Set a where exists statement in your query.
*/
whereExists(closure) {
const driver = this.clone();
this.qb.whereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure) {
const driver = this.clone();
this.qb.whereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where like statement in your query.
*/
whereLike(column, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereLike');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('whereLike');
}
this.qb.whereLike(column, value);
return this;
}
/**
* Set a where ILike statement in your query.
*/
whereILike(column, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereILike');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('whereILike');
}
this.qb.whereILike(column, value);
return this;
}
/**
* Set a where in statement in your query.
*/
whereIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('whereIn');
}
this.qb.whereIn(column, values);
return this;
}
/**
* Set a where not in statement in your query.
*/
whereNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('whereNotIn');
}
this.qb.whereNotIn(column, values);
return this;
}
/**
* Set a where between statement in your query.
*/
whereBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('whereBetween');
}
this.qb.whereBetween(column, values);
return this;
}
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('whereNotBetween');
}
this.qb.whereNotBetween(column, values);
return this;
}
/**
* Set a where null statement in your query.
*/
whereNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNull');
}
this.qb.whereNull(column);
return this;
}
/**
* Set a where not null statement in your query.
*/
whereNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotNull');
}
this.qb.whereNotNull(column);
return this;
}
/**
* Set a where json statement in your query.
*/
whereJson(column, operator, value) {
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
const path = this.parseJsonSelectorToPath(parsed.path);
if (Is.Undefined(value)) {
this.qb.whereJsonPath(parsed.column, path, '=', operator);
return this;
}
this.qb.whereJsonPath(parsed.column, path, operator, value);
return this;
}
/**
* Set a or where statement in your query.
*/
orWhere(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhere(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (Is.Undefined(operation)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('orWhere');
}
this.qb.orWhere(statement);
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('orWhere');
}
this.qb.orWhere(statement, operation);
return this;
}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('orWhere');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhere');
}
this.qb.orWhere(statement, operation, value);
return this;
}
/**
* Set an or where not statement in your query.
*/
orWhereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('orWhereNot');
}
this.qb.orWhereNot(statement);
return this;
}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('orWhereNot');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhereNot');
}
this.qb.orWhereNot(statement, value);
return this;
}
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql, bindings) {
if (Is.Undefined(sql) || !Is.String(sql)) {
throw new EmptyValueException('orWhereRaw');
}
this.qb.orWhereRaw(sql, bindings);
return this;
}
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure) {
const driver = this.clone();
this.qb.orWhereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure) {
const driver = this.clone();
this.qb.orWhereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where like statement in your query.
*/
orWhereLike(column, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereLike');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhereLike');
}
this.qb.orWhereLike(column, value);
return this;
}
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereILike');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhereILike');
}
this.qb.orWhereILike(column, value);
return this;
}
/**
* Set an or where in statement in your query.
*/
orWhereIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('orWhereIn');
}
this.qb.orWhereIn(column, values);
return this;
}
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('orWhereNotIn');
}
this.qb.orWhereNotIn(column, values);
return this;
}
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orWhereBetween');
}
this.qb.orWhereBetween(column, values);
return this;
}
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orWhereNotBetween');
}
this.qb.orWhereNotBetween(column, values);
return this;
}
/**
* Set an or where null statement in your query.
*/
orWhereNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNull');
}
this.qb.orWhereNull(column);
return this;
}
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotNull');
}
this.qb.orWhereNotNull(column);
return this;
}
/**
* Set an or where json statement in your query.
*/
orWhereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereJson');
}
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
const path = this.parseJsonSelectorToPath(parsed.path);
if (Is.Undefined(value)) {
this.qb.orWhereJsonPath(parsed.column, path, '=', operator);
return this;
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhereJson');
}
this.qb.orWhereJsonPath(parsed.column, path, operator, value);
return this;
}
/**
* Convert a json selector path to a valid json path.
*/
parseJsonSelectorToPath(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
return parts.reduce((jsonPath, part) => {
if (part === '*') {
return `${jsonPath}[*]`;
}
if (/^\d+$/.test(part)) {
return `${jsonPath}[${part}]`;
}
return `${jsonPath}.${part}`;
}, '$');
}
/**
* Set an order by statement in your query.
*/
orderBy(column, direction = 'ASC') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orderBy');
}
this.qb.orderBy(column, direction.toUpperCase());
return this;
}
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql, bindings) {
if (Is.Undefined(sql) || !Is.String(sql)) {
throw new EmptyValueException('orderByRaw');
}
this.qb.orderByRaw(sql, bindings);
return this;
}
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column = 'createdAt') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('latest');
}
return this.orderBy(column, 'DESC');
}
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column = 'createdAt') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('oldest');
}
return this.orderBy(column, 'ASC');
}
/**
* Set the skip number in your query.
*/
offset(number) {
if (Is.Undefined(number) || !Is.Number(number)) {
throw new EmptyValueException('offset');
}
this.qb.offset(number);
return this;
}
/**
* Set the limit number in your query.
*/
limit(number) {
if (Is.Undefined(number) || !Is.Number(number)) {
throw new EmptyValueException('limit');
}
this.qb.limit(number);
return this;
}
}
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Exception } from '@athenna/common';
export declare class EmptyColumnException extends Exception {
constructor(method: string);
}
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Exception } from '@athenna/common';
export class EmptyColumnException extends Exception {
constructor(method) {
const message = `The column set in your query builder ${method} method is empty or with wrong type.`;
super({
message,
code: 'E_EMPTY_COLUMN_ERROR',
help: `You must set a column value to perform the ${method}() operation. Accepted values are only strings and objects.`
});
}
}
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Exception } from '@athenna/common';
export declare class EmptyValueException extends Exception {
constructor(method: string);
}
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
import { Exception } from '@athenna/common';
export class EmptyValueException extends Exception {
constructor(method) {
const message = `The value set in your query builder ${method}() operation is undefined.`;
super({
message,
code: 'E_EMPTY_VALUE_ERROR',
help: `You must set a value to perform the ${method}() operation, undefined is not supported.`
});
}
}
+1
-1
{
"name": "@athenna/database",
"version": "5.38.0",
"version": "5.39.0",
"description": "The Athenna database handler for SQL/NoSQL.",

@@ -5,0 +5,0 @@ "license": "MIT",

@@ -86,7 +86,7 @@ /**

*/
count(column?: string | ModelColumns<T>): Promise<string>;
count(column?: string | ModelColumns<T>): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string | ModelColumns<T>): Promise<string>;
countDistinct(column: string | ModelColumns<T>): Promise<number>;
/**

@@ -236,10 +236,2 @@ * Find a value in database or throw exception if undefined.

/**
* Set a having exists statement in your query.
*/
havingExists(closure: (query: Driver) => void): this;
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure: (query: Driver) => void): this;
/**
* Set a having in statement in your query.

@@ -277,14 +269,2 @@ */

/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure: (query: Driver) => void): this;
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure: (query: Driver) => void): this;
/**
* Set an or having in statement in your query.
*/
orHavingIn(column: string | ModelColumns<T>, values: any[]): this;
/**
* Set an or having not in statement in your query.

@@ -362,2 +342,4 @@ */

whereNotNull(column: string | ModelColumns<T>): this;
whereJson(column: string | ModelColumns<T>, operation: any, value?: any): this;
whereJson(column: string | ModelColumns<T>, value: any): this;
orWhere(statement: (query: this) => void): this;

@@ -414,2 +396,4 @@ orWhere(statement: Partial<T>): this;

orWhereNotNull(column: string | ModelColumns<T>): this;
orWhereJson(column: string | ModelColumns<T>, operation: Operations, value?: any): this;
orWhereJson(column: string | ModelColumns<T>, value: any): this;
/**

@@ -416,0 +400,0 @@ * Set an order by statement in your query.

@@ -355,16 +355,2 @@ /**

/**
* Set a having exists statement in your query.
*/
havingExists(closure) {
this.driver.havingExists(closure);
return this;
}
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure) {
this.driver.havingNotExists(closure);
return this;
}
/**
* Set a having in statement in your query.

@@ -426,23 +412,2 @@ */

/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure) {
this.driver.orHavingExists(closure);
return this;
}
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure) {
this.driver.orHavingNotExists(closure);
return this;
}
/**
* Set an or having in statement in your query.
*/
orHavingIn(column, values) {
this.driver.orHavingIn(column, values);
return this;
}
/**
* Set an or having not in statement in your query.

@@ -574,2 +539,9 @@ */

/**
* Set a where json statement in your query.
*/
whereJson(column, operation, value) {
this.driver.whereJson(column, operation, value);
return this;
}
/**
* Set a or where statement in your query.

@@ -666,2 +638,9 @@ */

/**
* Set an orWhereJson statement in your query.
*/
orWhereJson(column, operation, value) {
this.driver.orWhereJson(column, operation, value);
return this;
}
/**
* Set an order by statement in your query.

@@ -668,0 +647,0 @@ */

@@ -91,2 +91,13 @@ /**

/**
* Verify if a statement is using the json selector syntax.
*/
isUsingJsonSelector(statement: string): boolean;
/**
* Parse a statement using the json selector syntax.
*/
parseJsonSelector(statement: string): {
column: string;
path: string;
};
/**
* Connect to database.

@@ -211,7 +222,7 @@ */

*/
abstract count(column?: string): Promise<string>;
abstract count(column?: string): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
abstract countDistinct(column?: string): Promise<string>;
abstract countDistinct(column?: string): Promise<number>;
/**

@@ -271,3 +282,3 @@ * Find a value in database and return as boolean.

*/
abstract createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
abstract createOrUpdate<T = any>(data?: Partial<T>): Promise<T>;
/**

@@ -362,10 +373,2 @@ * Update a value in database.

/**
* Set a having exists statement in your query.
*/
abstract havingExists(closure: (query: Driver<Client, QB>) => void): this;
/**
* Set a having not exists statement in your query.
*/
abstract havingNotExists(closure: (query: Driver<Client, QB>) => void): this;
/**
* Set a having in statement in your query.

@@ -403,14 +406,2 @@ */

/**
* Set an or having exists statement in your query.
*/
abstract orHavingExists(closure: (query: Driver<Client, QB>) => void): this;
/**
* Set an or having not exists statement in your query.
*/
abstract orHavingNotExists(closure: (query: Driver<Client, QB>) => void): this;
/**
* Set an or having in statement in your query.
*/
abstract orHavingIn(column: string, values: any[]): this;
/**
* Set an or having not in statement in your query.

@@ -487,3 +478,9 @@ */

abstract whereNotNull(column: string): this;
abstract whereJson(column: string, value: any): this;
abstract whereJson(column: string, operation: Operations, value?: any): this;
/**
* Set a where json statement in your query.
*/
abstract whereJson(column: string, operation: Operations, value?: any): this;
/**
* Set a or where statement in your query.

@@ -544,3 +541,9 @@ */

abstract orWhereNotNull(column: string): this;
abstract orWhereJson(column: string, value: any): this;
abstract orWhereJson(column: string, operation: Operations, value?: any): this;
/**
* Set an orWhereJson statement in your query.
*/
abstract orWhereJson(column: string, operation: Operations, value?: any): this;
/**
* Set an order by statement in your query.

@@ -547,0 +550,0 @@ */

@@ -9,3 +9,5 @@ /**

*/
import { Module, Options, Collection } from '@athenna/common';
import { Is, Module, Options, Collection } from '@athenna/common';
import { EmptyValueException } from '#src/exceptions/EmptyValueException';
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
import { NotFoundDataException } from '#src/exceptions/NotFoundDataException';

@@ -117,2 +119,5 @@ export class Driver {

setPrimaryKey(primaryKey) {
if (!Is.String(primaryKey)) {
throw new Error('Primary key must be a string value');
}
this.primaryKey = primaryKey;

@@ -125,2 +130,5 @@ return this;

joinByType(joinType, table, column1, operation, column2) {
if (Is.Undefined(table)) {
throw new Error('Table is required for join methods');
}
if (!column1) {

@@ -131,2 +139,5 @@ this.qb[joinType](table);

if (!operation) {
if (Is.Undefined(column1)) {
throw new EmptyColumnException(joinType);
}
this.qb[joinType](table, column1);

@@ -136,5 +147,17 @@ return this;

if (!column2) {
if (Is.Undefined(column1) || !Is.String(column1)) {
throw new EmptyColumnException(joinType);
}
if (Is.Undefined(operation) || !Is.String(operation)) {
throw new EmptyValueException(joinType);
}
this.qb[joinType](table, column1, operation);
return this;
}
if (Is.Undefined(column1) || !Is.String(column1)) {
throw new EmptyColumnException(joinType);
}
if (Is.Undefined(column2) || !Is.String(column2)) {
throw new EmptyColumnException(joinType);
}
this.qb[joinType](table, column1, operation, column2);

@@ -144,2 +167,25 @@ return this;

/**
* Verify if a statement is using the json selector syntax.
*/
isUsingJsonSelector(statement) {
return Is.String(statement) && statement.includes('->');
}
/**
* Parse a statement using the json selector syntax.
*/
parseJsonSelector(statement) {
if (!this.isUsingJsonSelector(statement)) {
return null;
}
const [column, ...pathParts] = statement.split('->');
const path = pathParts.join('->').trim();
if (!column?.trim() || !path) {
return null;
}
return {
column: column.trim(),
path
};
}
/**
* Find a value in database and return as boolean.

@@ -146,0 +192,0 @@ */

@@ -153,7 +153,7 @@ /**

*/
static count(): Promise<string>;
static count(): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
static countDistinct(): Promise<string>;
static countDistinct(): Promise<number>;
/**

@@ -220,3 +220,3 @@ * Find value in database but returns only the value of

*/
static createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
static createOrUpdate<T = any>(data?: Partial<T>): Promise<T>;
/**

@@ -306,10 +306,2 @@ * Update a value in database.

/**
* Set a having exists statement in your query.
*/
static havingExists(): typeof FakeDriver;
/**
* Set a having not exists statement in your query.
*/
static havingNotExists(): typeof FakeDriver;
/**
* Set a having in statement in your query.

@@ -346,14 +338,2 @@ */

/**
* Set an or having exists statement in your query.
*/
static orHavingExists(): typeof FakeDriver;
/**
* Set an or having not exists statement in your query.
*/
static orHavingNotExists(): typeof FakeDriver;
/**
* Set an or having in statement in your query.
*/
static orHavingIn(): typeof FakeDriver;
/**
* Set an or having not in statement in your query.

@@ -427,2 +407,4 @@ */

static whereNotNull(): typeof FakeDriver;
static whereJson(column: string, value: any): typeof FakeDriver;
static whereJson(column: string, operation: Operations, value: any): typeof FakeDriver;
static orWhere(statement: Record<string, any>): typeof FakeDriver;

@@ -477,2 +459,4 @@ static orWhere(key: string, value: any): typeof FakeDriver;

static orWhereNotNull(): typeof FakeDriver;
static orWhereJson(column: string, value: any): typeof FakeDriver;
static orWhereJson(column: string, operation: Operations, value: any): typeof FakeDriver;
/**

@@ -504,2 +488,5 @@ * Set an order by statement in your query.

static limit(): typeof FakeDriver;
static isUsingJsonSelector(): boolean;
static parseJsonSelector(): any;
static parseJsonSelectorToPath(path: string): string;
}

@@ -256,3 +256,3 @@ /**

static async count() {
return '1';
return 1;
}

@@ -263,3 +263,3 @@ /**

static async countDistinct() {
return '1';
return 1;
}

@@ -506,14 +506,2 @@ /**

/**
* Set a having exists statement in your query.
*/
static havingExists() {
return this;
}
/**
* Set a having not exists statement in your query.
*/
static havingNotExists() {
return this;
}
/**
* Set a having in statement in your query.

@@ -567,20 +555,2 @@ */

/**
* Set an or having exists statement in your query.
*/
static orHavingExists() {
return this;
}
/**
* Set an or having not exists statement in your query.
*/
static orHavingNotExists() {
return this;
}
/**
* Set an or having in statement in your query.
*/
static orHavingIn() {
return this;
}
/**
* Set an or having not in statement in your query.

@@ -694,2 +664,8 @@ */

/**
* Set a where json statement in your query.
*/
static whereJson() {
return this;
}
/**
* Set a or where statement in your query.

@@ -773,2 +749,8 @@ */

/**
* Set an or where json statement in your query.
*/
static orWhereJson() {
return this;
}
/**
* Set an order by statement in your query.

@@ -811,2 +793,11 @@ */

}
static isUsingJsonSelector() {
return false;
}
static parseJsonSelector() {
return null;
}
static parseJsonSelectorToPath(path) {
return path;
}
}

@@ -154,7 +154,7 @@ /**

*/
count(column?: string): Promise<string>;
count(column?: string): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string): Promise<string>;
countDistinct(column: string): Promise<number>;
/**

@@ -183,3 +183,3 @@ * Find a value in database.

*/
createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
createOrUpdate<T = any>(data?: Partial<T>): Promise<T>;
/**

@@ -269,10 +269,2 @@ * Update a value in database.

/**
* Set a having exists statement in your query.
*/
havingExists(): this;
/**
* Set a having not exists statement in your query.
*/
havingNotExists(): this;
/**
* Set a having in statement in your query.

@@ -309,14 +301,2 @@ */

/**
* Set an or having exists statement in your query.
*/
orHavingExists(): this;
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(): this;
/**
* Set an or having in statement in your query.
*/
orHavingIn(column: string, values: any[]): this;
/**
* Set an or having not in statement in your query.

@@ -390,2 +370,4 @@ */

whereNotNull(column: string): this;
whereJson(column: string, value: any): this;
whereJson(column: string, operation: Operations, value: any): this;
orWhere(statement: Record<string, any>): this;

@@ -396,2 +378,4 @@ orWhere(key: string, value: any): this;

orWhereNot(key: string, value: any): this;
orWhereJson(column: string, value: any): this;
orWhereJson(column: string, operation: Operations, value: any): this;
/**

@@ -472,2 +456,6 @@ * Set a or where raw statement in your query.

/**
* Convert a json selector path to mongo dot notation.
*/
private jsonSelectorToDotPath;
/**
* Creates the where clause with where and orWhere.

@@ -474,0 +462,0 @@ */

@@ -17,2 +17,4 @@ /**

import { ConnectionFactory } from '#src/factories/ConnectionFactory';
import { EmptyValueException } from '#src/exceptions/EmptyValueException';
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
import { WrongMethodException } from '#src/exceptions/WrongMethodException';

@@ -431,3 +433,3 @@ import { MONGO_OPERATIONS_DICTIONARY } from '#src/constants/MongoOperationsDictionary';

.toArray();
return `${result[0]?.count || 0}`;
return Number(result[0]?.count || 0);
}

@@ -452,3 +454,3 @@ /**

.toArray();
return `${count}`;
return Number(count);
}

@@ -568,2 +570,5 @@ /**

}
if (!Is.String(table)) {
throw new Error('Table must be a string value');
}
this.tableName = table;

@@ -577,7 +582,7 @@ this.qb = this.query();

dump() {
console.log({
process.stdout.write(`${JSON.stringify({
where: this._where,
orWhere: this._orWhere,
pipeline: this.pipeline
});
})}\n`);
return this;

@@ -589,2 +594,5 @@ }

select(...columns) {
if (!Is.Array(columns)) {
throw new EmptyValueException('select');
}
if (columns.includes('*')) {

@@ -713,2 +721,5 @@ return this;

groupBy(...columns) {
if (Is.Undefined(columns) || !Is.Array(columns)) {
throw new EmptyColumnException('groupBy');
}
const $group = { [this.primaryKey]: {} };

@@ -739,14 +750,2 @@ columns.forEach(column => ($group[this.primaryKey][column] = `$${column}`));

/**
* Set a having exists statement in your query.
*/
havingExists() {
throw new NotImplementedMethodException(this.havingExists.name, 'mongo');
}
/**
* Set a having not exists statement in your query.
*/
havingNotExists() {
throw new NotImplementedMethodException(this.havingNotExists.name, 'mongo');
}
/**
* Set a having in statement in your query.

@@ -800,20 +799,2 @@ */

/**
* Set an or having exists statement in your query.
*/
orHavingExists() {
throw new NotImplementedMethodException(this.orHavingExists.name, 'mongo');
}
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists() {
throw new NotImplementedMethodException(this.orHavingNotExists.name, 'mongo');
}
/**
* Set an or having in statement in your query.
*/
orHavingIn(column, values) {
return this.orWhereIn(column, values);
}
/**
* Set an or having not in statement in your query.

@@ -856,7 +837,16 @@ */

}
if (operation === undefined) {
if (Is.Undefined(operation)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('where');
}
this._where.push(statement);
return this;
}
if (value === undefined) {
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyValueException('where');
}
if (this.isUsingJsonSelector(statement)) {
return this.whereJson(statement, operation);
}
this._where.push({

@@ -867,2 +857,11 @@ [statement]: this.setOperator(operation, '=')

}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('where');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('where');
}
if (this.isUsingJsonSelector(statement)) {
return this.whereJson(statement, operation, value);
}
this._where.push({ [statement]: this.setOperator(value, operation) });

@@ -911,2 +910,8 @@ return this;

whereIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('whereIn');
}
values = values.flatMap(value => {

@@ -925,2 +930,8 @@ if (ObjectId.isValidStringOrObject(value)) {

whereNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('whereNotIn');
}
values = values.flatMap(value => {

@@ -939,2 +950,8 @@ if (ObjectId.isValidStringOrObject(value)) {

whereBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('whereBetween');
}
this._where.push({ [column]: { $gte: values[0], $lte: values[1] } });

@@ -947,2 +964,8 @@ return this;

whereNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('whereNotBetween');
}
this._where.push({

@@ -957,2 +980,5 @@ [column]: { $not: { $gte: values[0], $lte: values[1] } }

whereNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNull');
}
this._where.push({ [column]: null });

@@ -965,2 +991,5 @@ return this;

whereNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereNotNull');
}
this._where.push({ [column]: { $ne: null } });

@@ -970,2 +999,25 @@ return this;

/**
* Set a where json statement in your query.
*/
whereJson(column, operation, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereJson');
}
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
const path = this.jsonSelectorToDotPath(parsed.path);
if (value === undefined) {
this._where.push({
[`${parsed.column}.${path}`]: this.setOperator(operation, '=')
});
return this;
}
this._where.push({
[`${parsed.column}.${path}`]: this.setOperator(value, operation)
});
return this;
}
/**
* Set a or where statement in your query.

@@ -978,10 +1030,28 @@ */

}
if (operation === undefined) {
if (Is.Undefined(operation)) {
if (Is.Undefined(statement) || !Is.Object(statement)) {
throw new EmptyValueException('orWhere');
}
this._orWhere.push(statement);
return this;
}
if (value === undefined) {
if (Is.Undefined(value)) {
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('orWhere');
}
if (this.isUsingJsonSelector(statement)) {
return this.orWhereJson(statement, operation);
}
this._orWhere.push({ [statement]: this.setOperator(operation, '=') });
return this;
}
if (Is.Undefined(statement) || !Is.String(statement)) {
throw new EmptyColumnException('orWhere');
}
if (Is.Undefined(value)) {
throw new EmptyValueException('orWhere');
}
if (this.isUsingJsonSelector(statement)) {
return this.orWhereJson(statement, operation, value);
}
this._orWhere.push({ [statement]: this.setOperator(value, operation) });

@@ -997,2 +1067,25 @@ return this;

/**
* Set an or where json statement in your query.
*/
orWhereJson(column, operation, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereJson');
}
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
const path = this.jsonSelectorToDotPath(parsed.path);
if (value === undefined) {
this._orWhere.push({
[`${parsed.column}.${path}`]: this.setOperator(operation, '=')
});
return this;
}
this._orWhere.push({
[`${parsed.column}.${path}`]: this.setOperator(value, operation)
});
return this;
}
/**
* Set a or where raw statement in your query.

@@ -1031,2 +1124,8 @@ */

orWhereIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('orWhereIn');
}
values = values.flatMap(value => {

@@ -1045,2 +1144,8 @@ if (ObjectId.isValidStringOrObject(value)) {

orWhereNotIn(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotIn');
}
if (Is.Undefined(values)) {
throw new EmptyValueException('orWhereNotIn');
}
values = values.flatMap(value => {

@@ -1059,2 +1164,8 @@ if (ObjectId.isValidStringOrObject(value)) {

orWhereBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orWhereBetween');
}
this._orWhere.push({ [column]: { $gte: values[0], $lte: values[1] } });

@@ -1067,2 +1178,8 @@ return this;

orWhereNotBetween(column, values) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotBetween');
}
if (Is.Undefined(values?.[0]) || Is.Undefined(values?.[1])) {
throw new EmptyValueException('orWhereNotBetween');
}
this._orWhere.push({

@@ -1077,2 +1194,5 @@ [column]: { $not: { $gte: values[0], $lte: values[1] } }

orWhereNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNull');
}
this._orWhere.push({ [column]: null });

@@ -1085,2 +1205,5 @@ return this;

orWhereNotNull(column) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereNotNull');
}
this._orWhere.push({ [column]: { $ne: null } });

@@ -1093,2 +1216,5 @@ return this;

orderBy(column, direction = 'ASC') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orderBy');
}
this.pipeline.push({

@@ -1110,2 +1236,5 @@ $sort: { [column]: direction.toLowerCase() === 'asc' ? 1 : -1 }

latest(column = 'createdAt') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('latest');
}
return this.orderBy(column, 'DESC');

@@ -1118,2 +1247,5 @@ }

oldest(column = 'createdAt') {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('oldest');
}
return this.orderBy(column, 'ASC');

@@ -1125,2 +1257,5 @@ }

offset(number) {
if (Is.Undefined(number) || !Is.Number(number)) {
throw new EmptyValueException('offset');
}
this.pipeline.push({ $skip: number });

@@ -1133,2 +1268,5 @@ return this;

limit(number) {
if (Is.Undefined(number) || !Is.Number(number)) {
throw new EmptyValueException('limit');
}
this.pipeline.push({ $limit: number });

@@ -1162,2 +1300,13 @@ return this;

/**
* Convert a json selector path to mongo dot notation.
*/
jsonSelectorToDotPath(path) {
return path
.split('->')
.map(part => part.trim())
.filter(Boolean)
.filter(part => part !== '*')
.join('.');
}
/**
* Creates the where clause with where and orWhere.

@@ -1164,0 +1313,0 @@ */

@@ -9,8 +9,6 @@ /**

*/
import { type PaginatedResponse, type PaginationOptions } from '@athenna/common';
import type { Knex } from 'knex';
import { Driver } from '#src/database/drivers/Driver';
import { Transaction } from '#src/database/transactions/Transaction';
import type { ConnectionOptions, Direction, Operations } from '#src/types';
export declare class MySqlDriver extends Driver<Knex, Knex.QueryBuilder> {
import type { Operations } from '#src/types';
import type { ConnectionOptions } from '#src/types/ConnectionOptions';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
export declare class MySqlDriver extends BaseKnexDriver {
/**

@@ -21,34 +19,2 @@ * Connect to database.

/**
* Close the connection with database in this instance.
*/
close(): Promise<void>;
/**
* Creates a new instance of query builder.
*/
query(): Knex.QueryBuilder;
/**
* Sync a model schema with database.
*/
sync(): Promise<void>;
/**
* Create a new transaction.
*/
startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>;
/**
* Commit the transaction.
*/
commitTransaction(): Promise<void>;
/**
* Rollback the transaction.
*/
rollbackTransaction(): Promise<void>;
/**
* Run database migrations.
*/
runMigrations(): Promise<void>;
/**
* Revert database migrations.
*/
revertMigrations(): Promise<void>;
/**
* List all databases available.

@@ -58,10 +24,2 @@ */

/**
* Get the current database name.
*/
getCurrentDatabase(): Promise<string | undefined>;
/**
* Verify if database exists.
*/
hasDatabase(database: string): Promise<boolean>;
/**
* Create a new database.

@@ -79,18 +37,2 @@ */

/**
* Verify if table exists.
*/
hasTable(table: string): Promise<boolean>;
/**
* Create a new table in database.
*/
createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Alter a table in database.
*/
alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Drop a table in database.
*/
dropTable(table: string): Promise<void>;
/**
* Remove all data inside some database table

@@ -101,347 +43,25 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
*/
raw<T = any>(sql: string, bindings?: any): T;
/**
* Calculate the average of a given column.
*/
avg(column: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
avgDistinct(column: string): Promise<string>;
/**
* Get the max number of a given column.
*/
max(column: string): Promise<string>;
/**
* Get the min number of a given column.
*/
min(column: string): Promise<string>;
/**
* Sum all numbers of a given column.
*/
sum(column: string): Promise<string>;
/**
* Sum all numbers of a given column in distinct mode.
*/
sumDistinct(column: string): Promise<string>;
/**
* Increment a value of a given column.
*/
increment(column: string): Promise<void>;
/**
* Decrement a value of a given column.
*/
decrement(column: string): Promise<void>;
/**
* Calculate the average of a given column using distinct.
*/
count(column?: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string): Promise<string>;
/**
* Find a value in database.
*/
find<T = any>(): Promise<T>;
/**
* Find many values in database.
*/
findMany<T = any>(): Promise<T[]>;
/**
* Find many values in database and return as paginated response.
*/
paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>;
/**
* Create a value in database.
*/
create<T = any>(data?: Partial<T>): Promise<T>;
/**
* Create many values in database.
*/
createMany<T = any>(data?: Partial<T>[]): Promise<T[]>;
whereJson(column: string, value: any): this;
whereJson(column: string, operation: Operations, value: any): this;
orWhereJson(column: string, value: any): this;
orWhereJson(column: string, operation: Operations, value: any): this;
/**
* Create data or update if already exists.
* Convert a json selector path to mysql json path.
*/
createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
private parseJsonSelectorToMySqlPath;
/**
* Update a value in database.
* Split a json selector around the wildcard.
*/
update<T = any>(data: Partial<T>): Promise<T | T[]>;
private parseJsonSelectorToWildcardParts;
/**
* Delete one value in database.
* Convert path parts to a valid json path.
*/
delete(): Promise<void>;
private toJsonPath;
/**
* Set the table that this query will be executed.
* Normalize operator/value pairs from the whereJson overloads.
*/
table(table: string): this;
/**
* Log in console the actual query built.
*/
dump(): this;
/**
* Set the columns that should be selected on query.
*/
select(...columns: string[]): this;
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql: string, bindings?: any): this;
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table: string): this;
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql: string, bindings?: any): this;
/**
* Set a join statement in your query.
*/
join(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left join statement in your query.
*/
leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right join statement in your query.
*/
rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a cross join statement in your query.
*/
crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a join raw statement in your query.
*/
joinRaw(sql: string, bindings?: any): this;
/**
* Set a group by statement in your query.
*/
groupBy(...columns: string[]): this;
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql: string, bindings?: any): this;
having(column: string): this;
having(column: string, value: any): this;
having(column: string, operation: Operations, value: any): this;
/**
* Set a having raw statement in your query.
*/
havingRaw(sql: string, bindings?: any): this;
/**
* Set a having exists statement in your query.
*/
havingExists(closure: (query: MySqlDriver) => void): this;
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure: (query: MySqlDriver) => void): this;
/**
* Set a having in statement in your query.
*/
havingIn(column: string, values: any[]): this;
/**
* Set a having not in statement in your query.
*/
havingNotIn(column: string, values: any[]): this;
/**
* Set a having between statement in your query.
*/
havingBetween(column: string, values: [any, any]): this;
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column: string, values: [any, any]): this;
/**
* Set a having null statement in your query.
*/
havingNull(column: string): this;
/**
* Set a having not null statement in your query.
*/
havingNotNull(column: string): this;
orHaving(column: string): this;
orHaving(column: string, value: any): this;
orHaving(column: string, operation: Operations, value: any): this;
/**
* Set an or having raw statement in your query.
*/
orHavingRaw(sql: string, bindings?: any): this;
/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure: (query: MySqlDriver) => void): this;
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure: (query: MySqlDriver) => void): this;
/**
* Set an or having in statement in your query.
*/
orHavingIn(column: string, values: any[]): this;
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column: string, values: any[]): this;
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column: string, values: [any, any]): this;
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column: string, values: [any, any]): this;
/**
* Set an or having null statement in your query.
*/
orHavingNull(column: string): this;
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column: string): this;
where(statement: Record<string, any>): this;
where(key: string, value: any): this;
where(key: string, operation: Operations, value: any): this;
whereNot(statement: Record<string, any>): this;
whereNot(key: string, value: any): this;
/**
* Set a where raw statement in your query.
*/
whereRaw(sql: string, bindings?: any): this;
/**
* Set a where exists statement in your query.
*/
whereExists(closure: (query: MySqlDriver) => void): this;
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure: (query: MySqlDriver) => void): this;
/**
* Set a where like statement in your query.
*/
whereLike(column: string, value: any): this;
/**
* Set a where ILike statement in your query.
*/
whereILike(column: string, value: any): this;
/**
* Set a where in statement in your query.
*/
whereIn(column: string, values: any[]): this;
/**
* Set a where not in statement in your query.
*/
whereNotIn(column: string, values: any[]): this;
/**
* Set a where between statement in your query.
*/
whereBetween(column: string, values: [any, any]): this;
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column: string, values: [any, any]): this;
/**
* Set a where null statement in your query.
*/
whereNull(column: string): this;
/**
* Set a where not null statement in your query.
*/
whereNotNull(column: string): this;
orWhere(statement: Record<string, any>): this;
orWhere(key: string, value: any): this;
orWhere(key: string, operation: Operations, value: any): this;
orWhereNot(statement: Record<string, any>): this;
orWhereNot(key: string, value: any): this;
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql: string, bindings?: any): this;
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure: (query: MySqlDriver) => void): this;
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure: (query: MySqlDriver) => void): this;
/**
* Set an or where like statement in your query.
*/
orWhereLike(column: string, value: any): this;
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column: string, value: any): this;
/**
* Set an or where in statement in your query.
*/
orWhereIn(column: string, values: any[]): this;
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column: string, values: any[]): this;
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column: string, values: [any, any]): this;
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column: string, values: [any, any]): this;
/**
* Set an or where null statement in your query.
*/
orWhereNull(column: string): this;
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column: string): this;
/**
* Set an order by statement in your query.
*/
orderBy(column: string, direction?: Direction): this;
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql: string, bindings?: any): this;
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column?: string): this;
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column?: string): this;
/**
* Set the skip number in your query.
*/
offset(number: number): this;
/**
* Set the limit number in your query.
*/
limit(number: number): this;
private normalizeJsonOperation;
}

@@ -1,2 +0,1 @@

/* eslint-disable @typescript-eslint/ban-ts-comment */
/**

@@ -10,13 +9,10 @@ * @athenna/database

*/
import { Exec, Is, Json, Options } from '@athenna/common';
import { debug } from '#src/debug';
import { Log } from '@athenna/logger';
import { Driver } from '#src/database/drivers/Driver';
import { Is, Json, Options } from '@athenna/common';
import { ConnectionFactory } from '#src/factories/ConnectionFactory';
import { Transaction } from '#src/database/transactions/Transaction';
import { MigrationSource } from '#src/database/migrations/MigrationSource';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
import { WrongMethodException } from '#src/exceptions/WrongMethodException';
import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods';
import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException';
export class MySqlDriver extends Driver {
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
export class MySqlDriver extends BaseKnexDriver {
/**

@@ -66,85 +62,2 @@ * Connect to database.

/**
* Close the connection with database in this instance.
*/
async close() {
if (!this.isConnected) {
return;
}
await this.client.destroy();
this.qb = null;
this.tableName = null;
this.client = null;
this.isConnected = false;
ConnectionFactory.setClient(this.connection, null);
}
/**
* Creates a new instance of query builder.
*/
query() {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
}
const query = this.useSetQB
? this.qb.table(this.tableName)
: this.client.queryBuilder().table(this.tableName);
const handler = {
get: (target, propertyKey) => {
if (PROTECTED_QUERY_METHODS.includes(propertyKey)) {
this.qb = this.query();
}
return target[propertyKey];
}
};
return new Proxy(query, handler);
}
/**
* Sync a model schema with database.
*/
async sync() {
debug(`database sync with ${MySqlDriver.name} is not available yet, use migration instead.`);
}
/**
* Create a new transaction.
*/
async startTransaction() {
const trx = await this.client.transaction();
return new Transaction(this.clone().setClient(trx));
}
/**
* Commit the transaction.
*/
async commitTransaction() {
const client = this.client;
await client.commit();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Rollback the transaction.
*/
async rollbackTransaction() {
const client = this.client;
await client.rollback();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Run database migrations.
*/
async runMigrations() {
await this.client.migrate.latest({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* Revert database migrations.
*/
async revertMigrations() {
await this.client.migrate.rollback({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* List all databases available.

@@ -157,15 +70,2 @@ */

/**
* Get the current database name.
*/
async getCurrentDatabase() {
return this.client.client.database();
}
/**
* Verify if database exists.
*/
async hasDatabase(database) {
const databases = await this.getDatabases();
return databases.includes(database);
}
/**
* Create a new database.

@@ -190,26 +90,2 @@ */

/**
* Verify if table exists.
*/
async hasTable(table) {
return this.client.schema.hasTable(table);
}
/**
* Create a new table in database.
*/
async createTable(table, closure) {
await this.client.schema.createTable(table, closure);
}
/**
* Alter a table in database.
*/
async alterTable(table, closure) {
await this.client.schema.alterTable(table, closure);
}
/**
* Drop a table in database.
*/
async dropTable(table) {
await this.client.schema.dropTableIfExists(table);
}
/**
* Remove all data inside some database table

@@ -228,117 +104,2 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
*/
raw(sql, bindings) {
return this.client.raw(sql, bindings);
}
/**
* Calculate the average of a given column.
*/
async avg(column) {
const [{ avg }] = await this.qb.avg({ avg: column });
return avg;
}
/**
* Calculate the average of a given column using distinct.
*/
async avgDistinct(column) {
const [{ avg }] = await this.qb.avgDistinct({ avg: column });
return avg;
}
/**
* Get the max number of a given column.
*/
async max(column) {
const [{ max }] = await this.qb.max({ max: column });
return max;
}
/**
* Get the min number of a given column.
*/
async min(column) {
const [{ min }] = await this.qb.min({ min: column });
return min;
}
/**
* Sum all numbers of a given column.
*/
async sum(column) {
const [{ sum }] = await this.qb.sum({ sum: column });
return sum;
}
/**
* Sum all numbers of a given column in distinct mode.
*/
async sumDistinct(column) {
const [{ sum }] = await this.qb.sumDistinct({ sum: column });
return sum;
}
/**
* Increment a value of a given column.
*/
async increment(column) {
await this.qb.increment(column);
}
/**
* Decrement a value of a given column.
*/
async decrement(column) {
await this.qb.decrement(column);
}
/**
* Calculate the average of a given column using distinct.
*/
async count(column = '*') {
const [{ count }] = await this.qb.count({ count: column });
return `${count}`;
}
/**
* Calculate the average of a given column using distinct.
*/
async countDistinct(column) {
const [{ count }] = await this.qb.countDistinct({ count: column });
return `${count}`;
}
/**
* Find a value in database.
*/
async find() {
return this.qb.first();
}
/**
* Find many values in database.
*/
async findMany() {
const data = await this.qb;
this.qb = this.query();
return data;
}
/**
* Find many values in database and return as paginated response.
*/
async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') {
if (Is.Number(page)) {
page = { page, limit, resourceUrl };
}
const [{ count }] = await this.qb
.clone()
.clearOrder()
.clearSelect()
.count({ count: '*' });
const data = await this.offset(page.page * page.limit)
.limit(page.limit)
.findMany();
return Exec.pagination(data, parseInt(count), page);
}
/**
* Create a value in database.
*/
async create(data = {}) {
if (Is.Array(data)) {
throw new WrongMethodException('create', 'createMany');
}
const created = await this.createMany([data]);
return created[0];
}
/**
* Create many values in database.

@@ -350,8 +111,9 @@ */

}
const preparedData = data.map(data => this.prepareInsert(data));
const ids = [];
const promises = data.map(data => {
const promises = preparedData.map((prepared, index) => {
return this.qb
.clone()
.insert(data)
.then(([id]) => ids.push(data[this.primaryKey] || id));
.insert(prepared)
.then(([id]) => ids.push(data[index][this.primaryKey] || id));
});

@@ -362,613 +124,103 @@ await Promise.all(promises);

/**
* Create data or update if already exists.
* Set a where json statement in your query.
*/
async createOrUpdate(data = {}) {
const query = this.qb.clone();
const hasValue = await query.first();
if (hasValue) {
await this.qb
.where(this.primaryKey, hasValue[this.primaryKey])
.update(data);
return this.where(this.primaryKey, hasValue[this.primaryKey]).find();
whereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereJson');
}
return this.create(data);
}
/**
* Update a value in database.
*/
async update(data) {
await this.qb.clone().update(data);
const result = await this.findMany();
if (result.length === 1) {
return result[0];
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
return result;
}
/**
* Delete one value in database.
*/
async delete() {
await this.qb.delete();
}
/**
* Set the table that this query will be executed.
*/
table(table) {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
const normalized = this.normalizeJsonOperation(operator, value);
if (!parsed.path.includes('*')) {
this.qb.whereRaw('JSON_UNQUOTE(JSON_EXTRACT(??, ?)) ' + normalized.operator + ' ?', [
parsed.column,
this.parseJsonSelectorToMySqlPath(parsed.path),
normalized.value
]);
return this;
}
this.tableName = table;
this.qb = this.query();
const wildcard = this.parseJsonSelectorToWildcardParts(parsed.path);
this.qb.whereRaw("exists (select 1 from json_table(json_extract(??, ?), '$[*]' columns (value json path ?)) as jt where JSON_UNQUOTE(jt.value) " +
normalized.operator +
' ?)', [parsed.column, wildcard.arrayPath, wildcard.valuePath, normalized.value]);
return this;
}
/**
* Log in console the actual query built.
* Set an or where json statement in your query.
*/
dump() {
console.log(this.qb.toSQL().toNative());
return this;
}
/**
* Set the columns that should be selected on query.
*/
select(...columns) {
this.qb.select(...columns);
return this;
}
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql, bindings) {
return this.select(this.raw(sql, bindings));
}
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table) {
this.qb.from(table);
return this;
}
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql, bindings) {
return this.from(this.raw(sql, bindings));
}
/**
* Set a join statement in your query.
*/
join(table, column1, operation, column2) {
return this.joinByType('join', table, column1, operation, column2);
}
/**
* Set a left join statement in your query.
*/
leftJoin(table, column1, operation, column2) {
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a right join statement in your query.
*/
rightJoin(table, column1, operation, column2) {
return this.joinByType('rightJoin', table, column1, operation, column2);
}
/**
* Set a cross join statement in your query.
*/
crossJoin(table, column1, operation, column2) {
return this.joinByType('crossJoin', table, column1, operation, column2);
}
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table, column1, operation, column2) {
// TODO https://github.com/knex/knex/issues/3949
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table, column1, operation, column2) {
return this.joinByType('leftOuterJoin', table, column1, operation, column2);
}
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table, column1, operation, column2) {
return this.joinByType('rightOuterJoin', table, column1, operation, column2);
}
/**
* Set a join raw statement in your query.
*/
joinRaw(sql, bindings) {
this.qb.joinRaw(sql, bindings);
return this;
}
/**
* Set a group by statement in your query.
*/
groupBy(...columns) {
this.qb.groupBy(...columns);
return this;
}
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql, bindings) {
this.qb.groupByRaw(sql, bindings);
return this;
}
/**
* Set a having statement in your query.
*/
having(column, operation, value) {
if (operation === undefined) {
this.qb.having(column);
return this;
orWhereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereJson');
}
if (value === undefined) {
this.qb.having(column, '=', operation);
return this;
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
this.qb.having(column, operation, value);
return this;
}
/**
* Set a having raw statement in your query.
*/
havingRaw(sql, bindings) {
this.qb.havingRaw(sql, bindings);
return this;
}
/**
* Set a having exists statement in your query.
*/
havingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having in statement in your query.
*/
havingIn(column, values) {
this.qb.havingIn(column, values);
return this;
}
/**
* Set a having not in statement in your query.
*/
havingNotIn(column, values) {
this.qb.havingNotIn(column, values);
return this;
}
/**
* Set a having between statement in your query.
*/
havingBetween(column, values) {
this.qb.havingBetween(column, values);
return this;
}
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column, values) {
this.qb.havingNotBetween(column, values);
return this;
}
/**
* Set a having null statement in your query.
*/
havingNull(column) {
this.qb.havingNull(column);
return this;
}
/**
* Set a having not null statement in your query.
*/
havingNotNull(column) {
this.qb.havingNotNull(column);
return this;
}
/**
* Set an or having statement in your query.
*/
orHaving(column, operation, value) {
if (operation === undefined) {
this.qb.orHaving(column);
const normalized = this.normalizeJsonOperation(operator, value);
if (!parsed.path.includes('*')) {
this.qb.orWhereRaw('JSON_UNQUOTE(JSON_EXTRACT(??, ?)) ' + normalized.operator + ' ?', [
parsed.column,
this.parseJsonSelectorToMySqlPath(parsed.path),
normalized.value
]);
return this;
}
if (value === undefined) {
this.qb.orHaving(column, '=', operation);
return this;
}
this.qb.orHaving(column, operation, value);
const wildcard = this.parseJsonSelectorToWildcardParts(parsed.path);
this.qb.orWhereRaw("exists (select 1 from json_table(json_extract(??, ?), '$[*]' columns (value json path ?)) as jt where JSON_UNQUOTE(jt.value) " +
normalized.operator +
' ?)', [parsed.column, wildcard.arrayPath, wildcard.valuePath, normalized.value]);
return this;
}
/**
* Set an or having raw statement in your query.
* Convert a json selector path to mysql json path.
*/
orHavingRaw(sql, bindings) {
this.qb.orHavingRaw(sql, bindings);
return this;
parseJsonSelectorToMySqlPath(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
return this.toJsonPath(parts);
}
/**
* Set an or having exists statement in your query.
* Split a json selector around the wildcard.
*/
orHavingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
parseJsonSelectorToWildcardParts(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
const wildcardIndex = parts.indexOf('*');
return {
arrayPath: this.toJsonPath(parts.slice(0, wildcardIndex)),
valuePath: this.toJsonPath(parts.slice(wildcardIndex + 1))
};
}
/**
* Set an or having not exists statement in your query.
* Convert path parts to a valid json path.
*/
orHavingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or having in statement in your query.
*/
orHavingIn(column, values) {
// @ts-ignore
this.qb.orHavingIn(column, values);
return this;
}
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column, values) {
this.qb.orHavingNotIn(column, values);
return this;
}
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column, values) {
this.qb.orHavingBetween(column, values);
return this;
}
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column, values) {
this.qb.orHavingNotBetween(column, values);
return this;
}
/**
* Set an or having null statement in your query.
*/
orHavingNull(column) {
// @ts-ignore
this.qb.orHavingNull(column);
return this;
}
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column) {
// @ts-ignore
this.qb.orHavingNotNull(column);
return this;
}
/**
* Set a where statement in your query.
*/
where(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.where(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (operation === undefined) {
if (Is.Array(statement)) {
throw new Error('Arrays as statement are not supported.');
toJsonPath(parts) {
return parts.reduce((jsonPath, part) => {
if (/^\d+$/.test(part)) {
return `${jsonPath}[${part}]`;
}
if (Is.String(statement)) {
throw new Error(`The value for the "${statement}" column is undefined and where will not work.`);
}
this.qb.where(statement);
return this;
}
if (value === undefined) {
this.qb.where(statement, operation);
return this;
}
this.qb.where(statement, operation, value);
return this;
return `${jsonPath}.${part}`;
}, '$');
}
/**
* Set a where not statement in your query.
* Normalize operator/value pairs from the whereJson overloads.
*/
whereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.whereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
normalizeJsonOperation(operator, value) {
if (Is.Undefined(value)) {
return {
operator: '=',
value: operator
};
}
if (value === undefined) {
this.qb.whereNot(statement);
return this;
}
this.qb.whereNot(statement, value);
return this;
return {
operator,
value
};
}
/**
* Set a where raw statement in your query.
*/
whereRaw(sql, bindings) {
this.qb.whereRaw(sql, bindings);
return this;
}
/**
* Set a where exists statement in your query.
*/
whereExists(closure) {
const driver = this.clone();
this.qb.whereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure) {
const driver = this.clone();
this.qb.whereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where like statement in your query.
*/
whereLike(column, value) {
this.qb.whereLike(column, value);
return this;
}
/**
* Set a where ILike statement in your query.
*/
whereILike(column, value) {
this.qb.whereILike(column, value);
return this;
}
/**
* Set a where in statement in your query.
*/
whereIn(column, values) {
this.qb.whereIn(column, values);
return this;
}
/**
* Set a where not in statement in your query.
*/
whereNotIn(column, values) {
this.qb.whereNotIn(column, values);
return this;
}
/**
* Set a where between statement in your query.
*/
whereBetween(column, values) {
this.qb.whereBetween(column, values);
return this;
}
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column, values) {
this.qb.whereNotBetween(column, values);
return this;
}
/**
* Set a where null statement in your query.
*/
whereNull(column) {
this.qb.whereNull(column);
return this;
}
/**
* Set a where not null statement in your query.
*/
whereNotNull(column) {
this.qb.whereNotNull(column);
return this;
}
/**
* Set a or where statement in your query.
*/
orWhere(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhere(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (operation === undefined) {
this.qb.orWhere(statement);
return this;
}
if (value === undefined) {
this.qb.orWhere(statement, operation);
return this;
}
this.qb.orWhere(statement, operation, value);
return this;
}
/**
* Set an or where not statement in your query.
*/
orWhereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (value === undefined) {
this.qb.orWhereNot(statement);
return this;
}
this.qb.orWhereNot(statement, value);
return this;
}
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql, bindings) {
this.qb.orWhereRaw(sql, bindings);
return this;
}
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure) {
const driver = this.clone();
this.qb.orWhereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure) {
const driver = this.clone();
this.qb.orWhereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where like statement in your query.
*/
orWhereLike(column, value) {
this.qb.orWhereLike(column, value);
return this;
}
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column, value) {
this.qb.orWhereILike(column, value);
return this;
}
/**
* Set an or where in statement in your query.
*/
orWhereIn(column, values) {
this.qb.orWhereIn(column, values);
return this;
}
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column, values) {
this.qb.orWhereNotIn(column, values);
return this;
}
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column, values) {
this.qb.orWhereBetween(column, values);
return this;
}
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column, values) {
this.qb.orWhereNotBetween(column, values);
return this;
}
/**
* Set an or where null statement in your query.
*/
orWhereNull(column) {
this.qb.orWhereNull(column);
return this;
}
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column) {
this.qb.orWhereNotNull(column);
return this;
}
/**
* Set an order by statement in your query.
*/
orderBy(column, direction = 'ASC') {
this.qb.orderBy(column, direction.toUpperCase());
return this;
}
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql, bindings) {
this.qb.orderByRaw(sql, bindings);
return this;
}
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column = 'createdAt') {
return this.orderBy(column, 'DESC');
}
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column = 'createdAt') {
return this.orderBy(column, 'ASC');
}
/**
* Set the skip number in your query.
*/
offset(number) {
this.qb.offset(number);
return this;
}
/**
* Set the limit number in your query.
*/
limit(number) {
this.qb.limit(number);
return this;
}
}

@@ -9,8 +9,6 @@ /**

*/
import { type PaginatedResponse, type PaginationOptions } from '@athenna/common';
import type { Knex } from 'knex';
import { Driver } from '#src/database/drivers/Driver';
import { Transaction } from '#src/database/transactions/Transaction';
import type { ConnectionOptions, Direction, Operations } from '#src/types';
export declare class PostgresDriver extends Driver<Knex, Knex.QueryBuilder> {
import type { Operations } from '#src/types';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
import type { ConnectionOptions } from '#src/types/ConnectionOptions';
export declare class PostgresDriver extends BaseKnexDriver {
/**

@@ -25,30 +23,2 @@ * Connect to database.

/**
* Creates a new instance of query builder.
*/
query(): Knex.QueryBuilder;
/**
* Sync a model schema with database.
*/
sync(): Promise<void>;
/**
* Create a new transaction.
*/
startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>;
/**
* Commit the transaction.
*/
commitTransaction(): Promise<void>;
/**
* Rollback the transaction.
*/
rollbackTransaction(): Promise<void>;
/**
* Run database migrations.
*/
runMigrations(): Promise<void>;
/**
* Revert database migrations.
*/
revertMigrations(): Promise<void>;
/**
* List all databases available.

@@ -58,10 +28,2 @@ */

/**
* Get the current database name.
*/
getCurrentDatabase(): Promise<string | undefined>;
/**
* Verify if database exists.
*/
hasDatabase(database: string): Promise<boolean>;
/**
* Create a new database.

@@ -79,18 +41,2 @@ */

/**
* Verify if table exists.
*/
hasTable(table: string): Promise<boolean>;
/**
* Create a new table in database.
*/
createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Alter a table in database.
*/
alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Drop a table in database.
*/
dropTable(table: string): Promise<void>;
/**
* Remove all data inside some database table

@@ -101,347 +47,21 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
*/
raw<T = any>(sql: string, bindings?: any): T;
/**
* Calculate the average of a given column.
*/
avg(column: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
avgDistinct(column: string): Promise<string>;
/**
* Get the max number of a given column.
*/
max(column: string): Promise<string>;
/**
* Get the min number of a given column.
*/
min(column: string): Promise<string>;
/**
* Sum all numbers of a given column.
*/
sum(column: string): Promise<string>;
/**
* Sum all numbers of a given column in distinct mode.
*/
sumDistinct(column: string): Promise<string>;
/**
* Increment a value of a given column.
*/
increment(column: string): Promise<void>;
/**
* Decrement a value of a given column.
*/
decrement(column: string): Promise<void>;
/**
* Calculate the average of a given column using distinct.
*/
count(column?: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string): Promise<string>;
/**
* Find a value in database.
*/
find<T = any>(): Promise<T>;
/**
* Find many values in database.
*/
findMany<T = any>(): Promise<T[]>;
/**
* Find many values in database and return as paginated response.
*/
paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>;
/**
* Create a value in database.
*/
create<T = any>(data?: Partial<T>): Promise<T>;
/**
* Create many values in database.
*/
createMany<T = any>(data?: Partial<T>[]): Promise<T[]>;
whereJson(column: string, value: any): this;
whereJson(column: string, operation: Operations, value: any): this;
orWhereJson(column: string, value: any): this;
orWhereJson(column: string, operation: Operations, value: any): this;
/**
* Create data or update if already exists.
* Convert a json selector path to a valid postgres json path.
*/
createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
private parseJsonSelectorToWildcardPath;
/**
* Update a value in database.
* Normalize operator/value pair for postgres json path comparisons.
*/
update<T = any>(data: Partial<T>): Promise<T | T[]>;
private normalizeJsonOperation;
/**
* Delete one value in database.
* Convert query operators to postgres json path operators.
*/
delete(): Promise<void>;
/**
* Set the table that this query will be executed.
*/
table(table: string): this;
/**
* Log in console the actual query built.
*/
dump(): this;
/**
* Set the columns that should be selected on query.
*/
select(...columns: string[]): this;
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql: string, bindings?: any): this;
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table: string): this;
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql: string, bindings?: any): this;
/**
* Set a join statement in your query.
*/
join(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left join statement in your query.
*/
leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right join statement in your query.
*/
rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a cross join statement in your query.
*/
crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a join raw statement in your query.
*/
joinRaw(sql: string, bindings?: any): this;
/**
* Set a group by statement in your query.
*/
groupBy(...columns: string[]): this;
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql: string, bindings?: any): this;
having(column: string): this;
having(column: string, value: any): this;
having(column: string, operation: Operations, value: any): this;
/**
* Set a having raw statement in your query.
*/
havingRaw(sql: string, bindings?: any): this;
/**
* Set a having exists statement in your query.
*/
havingExists(closure: (query: PostgresDriver) => void): this;
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure: (query: PostgresDriver) => void): this;
/**
* Set a having in statement in your query.
*/
havingIn(column: string, values: any[]): this;
/**
* Set a having not in statement in your query.
*/
havingNotIn(column: string, values: any[]): this;
/**
* Set a having between statement in your query.
*/
havingBetween(column: string, values: [any, any]): this;
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column: string, values: [any, any]): this;
/**
* Set a having null statement in your query.
*/
havingNull(column: string): this;
/**
* Set a having not null statement in your query.
*/
havingNotNull(column: string): this;
orHaving(column: string): this;
orHaving(column: string, value: any): this;
orHaving(column: string, operation: Operations, value: any): this;
/**
* Set an or having raw statement in your query.
*/
orHavingRaw(sql: string, bindings?: any): this;
/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure: (query: PostgresDriver) => void): this;
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure: (query: PostgresDriver) => void): this;
/**
* Set an or having in statement in your query.
*/
orHavingIn(column: string, values: any[]): this;
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column: string, values: any[]): this;
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column: string, values: [any, any]): this;
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column: string, values: [any, any]): this;
/**
* Set an or having null statement in your query.
*/
orHavingNull(column: string): this;
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column: string): this;
where(statement: Record<string, any>): this;
where(key: string, value: any): this;
where(key: string, operation: Operations, value: any): this;
whereNot(statement: Record<string, any>): this;
whereNot(key: string, value: any): this;
/**
* Set a where raw statement in your query.
*/
whereRaw(sql: string, bindings?: any): this;
/**
* Set a where exists statement in your query.
*/
whereExists(closure: (query: PostgresDriver) => void): this;
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure: (query: PostgresDriver) => void): this;
/**
* Set a where like statement in your query.
*/
whereLike(column: string, value: any): this;
/**
* Set a where ILike statement in your query.
*/
whereILike(column: string, value: any): this;
/**
* Set a where in statement in your query.
*/
whereIn(column: string, values: any[]): this;
/**
* Set a where not in statement in your query.
*/
whereNotIn(column: string, values: any[]): this;
/**
* Set a where between statement in your query.
*/
whereBetween(column: string, values: [any, any]): this;
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column: string, values: [any, any]): this;
/**
* Set a where null statement in your query.
*/
whereNull(column: string): this;
/**
* Set a where not null statement in your query.
*/
whereNotNull(column: string): this;
orWhere(statement: Record<string, any>): this;
orWhere(key: string, value: any): this;
orWhere(key: string, operation: Operations, value: any): this;
orWhereNot(statement: Record<string, any>): this;
orWhereNot(key: string, value: any): this;
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql: string, bindings?: any): this;
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure: (query: PostgresDriver) => void): this;
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure: (query: PostgresDriver) => void): this;
/**
* Set an or where like statement in your query.
*/
orWhereLike(column: string, value: any): this;
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column: string, value: any): this;
/**
* Set an or where in statement in your query.
*/
orWhereIn(column: string, values: any[]): this;
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column: string, values: any[]): this;
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column: string, values: [any, any]): this;
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column: string, values: [any, any]): this;
/**
* Set an or where null statement in your query.
*/
orWhereNull(column: string): this;
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column: string): this;
/**
* Set an order by statement in your query.
*/
orderBy(column: string, direction?: Direction): this;
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql: string, bindings?: any): this;
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column?: string): this;
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column?: string): this;
/**
* Set the skip number in your query.
*/
offset(number: number): this;
/**
* Set the limit number in your query.
*/
limit(number: number): this;
private getJsonPathOperator;
}

@@ -1,2 +0,1 @@

/* eslint-disable @typescript-eslint/ban-ts-comment */
/**

@@ -10,13 +9,10 @@ * @athenna/database

*/
import { Exec, Is, Json, Options } from '@athenna/common';
import { debug } from '#src/debug';
import { Log } from '@athenna/logger';
import { Driver } from '#src/database/drivers/Driver';
import { Is, Json, Options } from '@athenna/common';
import { ConnectionFactory } from '#src/factories/ConnectionFactory';
import { Transaction } from '#src/database/transactions/Transaction';
import { MigrationSource } from '#src/database/migrations/MigrationSource';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
import { WrongMethodException } from '#src/exceptions/WrongMethodException';
import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods';
import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException';
export class PostgresDriver extends Driver {
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
export class PostgresDriver extends BaseKnexDriver {
/**

@@ -80,71 +76,2 @@ * Connect to database.

/**
* Creates a new instance of query builder.
*/
query() {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
}
const query = this.useSetQB
? this.qb.table(this.tableName)
: this.client.queryBuilder().table(this.tableName);
const handler = {
get: (target, propertyKey) => {
if (PROTECTED_QUERY_METHODS.includes(propertyKey)) {
this.qb = this.query();
}
return target[propertyKey];
}
};
return new Proxy(query, handler);
}
/**
* Sync a model schema with database.
*/
async sync() {
debug(`database sync with ${PostgresDriver.name} is not available yet, use migration instead.`);
}
/**
* Create a new transaction.
*/
async startTransaction() {
const trx = await this.client.transaction();
return new Transaction(this.clone().setClient(trx));
}
/**
* Commit the transaction.
*/
async commitTransaction() {
const client = this.client;
await client.commit();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Rollback the transaction.
*/
async rollbackTransaction() {
const client = this.client;
await client.rollback();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Run database migrations.
*/
async runMigrations() {
await this.client.migrate.latest({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* Revert database migrations.
*/
async revertMigrations() {
await this.client.migrate.rollback({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* List all databases available.

@@ -157,15 +84,2 @@ */

/**
* Get the current database name.
*/
async getCurrentDatabase() {
return this.client.client.database();
}
/**
* Verify if database exists.
*/
async hasDatabase(database) {
const databases = await this.getDatabases();
return databases.includes(database);
}
/**
* Create a new database.

@@ -202,26 +116,2 @@ */

/**
* Verify if table exists.
*/
async hasTable(table) {
return this.client.schema.hasTable(table);
}
/**
* Create a new table in database.
*/
async createTable(table, closure) {
await this.client.schema.createTable(table, closure);
}
/**
* Alter a table in database.
*/
async alterTable(table, closure) {
await this.client.schema.alterTable(table, closure);
}
/**
* Drop a table in database.
*/
async dropTable(table) {
await this.client.schema.dropTableIfExists(table);
}
/**
* Remove all data inside some database table

@@ -234,117 +124,2 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
*/
raw(sql, bindings) {
return this.client.raw(sql, bindings);
}
/**
* Calculate the average of a given column.
*/
async avg(column) {
const [{ avg }] = await this.qb.avg({ avg: column });
return avg;
}
/**
* Calculate the average of a given column using distinct.
*/
async avgDistinct(column) {
const [{ avg }] = await this.qb.avgDistinct({ avg: column });
return avg;
}
/**
* Get the max number of a given column.
*/
async max(column) {
const [{ max }] = await this.qb.max({ max: column });
return max;
}
/**
* Get the min number of a given column.
*/
async min(column) {
const [{ min }] = await this.qb.min({ min: column });
return min;
}
/**
* Sum all numbers of a given column.
*/
async sum(column) {
const [{ sum }] = await this.qb.sum({ sum: column });
return sum;
}
/**
* Sum all numbers of a given column in distinct mode.
*/
async sumDistinct(column) {
const [{ sum }] = await this.qb.sumDistinct({ sum: column });
return sum;
}
/**
* Increment a value of a given column.
*/
async increment(column) {
await this.qb.increment(column);
}
/**
* Decrement a value of a given column.
*/
async decrement(column) {
await this.qb.decrement(column);
}
/**
* Calculate the average of a given column using distinct.
*/
async count(column = '*') {
const [{ count }] = await this.qb.count({ count: column });
return `${count}`;
}
/**
* Calculate the average of a given column using distinct.
*/
async countDistinct(column) {
const [{ count }] = await this.qb.countDistinct({ count: column });
return `${count}`;
}
/**
* Find a value in database.
*/
async find() {
return this.qb.first();
}
/**
* Find many values in database.
*/
async findMany() {
const data = await this.qb;
this.qb = this.query();
return data;
}
/**
* Find many values in database and return as paginated response.
*/
async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') {
if (Is.Number(page)) {
page = { page, limit, resourceUrl };
}
const [{ count }] = await this.qb
.clone()
.clearOrder()
.clearSelect()
.count({ count: '*' });
const data = await this.offset(page.page * page.limit)
.limit(page.limit)
.findMany();
return Exec.pagination(data, parseInt(count), page);
}
/**
* Create a value in database.
*/
async create(data = {}) {
if (Is.Array(data)) {
throw new WrongMethodException('create', 'createMany');
}
const created = await this.createMany([data]);
return created[0];
}
/**
* Create many values in database.

@@ -356,615 +131,100 @@ */

}
return this.qb.insert(data, '*');
const preparedData = data.map(data => this.prepareInsert(data));
return this.qb.insert(preparedData, '*');
}
/**
* Create data or update if already exists.
* Set a where json statement in your query.
*/
async createOrUpdate(data = {}) {
const query = this.qb.clone();
const hasValue = await query.first();
if (hasValue) {
await this.qb
.where(this.primaryKey, hasValue[this.primaryKey])
.update(data);
return this.where(this.primaryKey, hasValue[this.primaryKey]).find();
whereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereJson');
}
return this.create(data);
}
/**
* Update a value in database.
*/
async update(data) {
await this.qb.clone().update(data);
const result = await this.findMany();
if (result.length === 1) {
return result[0];
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
return result;
}
/**
* Delete one value in database.
*/
async delete() {
await this.qb.delete();
}
/**
* Set the table that this query will be executed.
*/
table(table) {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
if (!parsed.path.includes('*')) {
return super.whereJson(column, operator, value);
}
this.tableName = table;
this.qb = this.query();
const path = this.parseJsonSelectorToWildcardPath(parsed.path);
const normalized = this.normalizeJsonOperation(operator, value);
this.qb.whereRaw('jsonb_path_exists(??, ?::jsonpath, ?::jsonb)', [
parsed.column,
`${path} ? (@ ${normalized.operator} $value)`,
JSON.stringify({ value: normalized.value })
]);
return this;
}
/**
* Log in console the actual query built.
* Set an or where json statement in your query.
*/
dump() {
console.log(this.qb.toSQL().toNative());
return this;
}
/**
* Set the columns that should be selected on query.
*/
select(...columns) {
this.qb.select(...columns);
return this;
}
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql, bindings) {
return this.select(this.raw(sql, bindings));
}
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table) {
this.qb.from(table);
return this;
}
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql, bindings) {
return this.from(this.raw(sql, bindings));
}
/**
* Set a join statement in your query.
*/
join(table, column1, operation, column2) {
return this.joinByType('join', table, column1, operation, column2);
}
/**
* Set a left join statement in your query.
*/
leftJoin(table, column1, operation, column2) {
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a right join statement in your query.
*/
rightJoin(table, column1, operation, column2) {
return this.joinByType('rightJoin', table, column1, operation, column2);
}
/**
* Set a cross join statement in your query.
*/
crossJoin(table, column1, operation, column2) {
return this.joinByType('crossJoin', table, column1, operation, column2);
}
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table, column1, operation, column2) {
return this.joinByType('fullOuterJoin', table, column1, operation, column2);
}
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table, column1, operation, column2) {
return this.joinByType('leftOuterJoin', table, column1, operation, column2);
}
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table, column1, operation, column2) {
return this.joinByType('rightOuterJoin', table, column1, operation, column2);
}
/**
* Set a join raw statement in your query.
*/
joinRaw(sql, bindings) {
this.qb.joinRaw(sql, bindings);
return this;
}
/**
* Set a group by statement in your query.
*/
groupBy(...columns) {
this.qb.groupBy(...columns);
return this;
}
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql, bindings) {
this.qb.groupByRaw(sql, bindings);
return this;
}
/**
* Set a having statement in your query.
*/
having(column, operation, value) {
if (operation === undefined) {
this.qb.having(column);
return this;
orWhereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereJson');
}
if (value === undefined) {
this.qb.having(column, '=', operation);
return this;
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
this.qb.having(column, operation, value);
return this;
}
/**
* Set a having raw statement in your query.
*/
havingRaw(sql, bindings) {
this.qb.havingRaw(sql, bindings);
return this;
}
/**
* Set a having exists statement in your query.
*/
havingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having in statement in your query.
*/
havingIn(column, values) {
this.qb.havingIn(column, values);
return this;
}
/**
* Set a having not in statement in your query.
*/
havingNotIn(column, values) {
this.qb.havingNotIn(column, values);
return this;
}
/**
* Set a having between statement in your query.
*/
havingBetween(column, values) {
this.qb.havingBetween(column, values);
return this;
}
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column, values) {
this.qb.havingNotBetween(column, values);
return this;
}
/**
* Set a having null statement in your query.
*/
havingNull(column) {
this.qb.havingNull(column);
return this;
}
/**
* Set a having not null statement in your query.
*/
havingNotNull(column) {
this.qb.havingNotNull(column);
return this;
}
/**
* Set an or having statement in your query.
*/
orHaving(column, operation, value) {
if (operation === undefined) {
this.qb.orHaving(column);
return this;
if (!parsed.path.includes('*')) {
return super.orWhereJson(column, operator, value);
}
if (value === undefined) {
this.qb.orHaving(column, '=', operation);
return this;
}
this.qb.orHaving(column, operation, value);
const path = this.parseJsonSelectorToWildcardPath(parsed.path);
const normalized = this.normalizeJsonOperation(operator, value);
this.qb.orWhereRaw('jsonb_path_exists(??, ?::jsonpath, ?::jsonb)', [
parsed.column,
`${path} ? (@ ${normalized.operator} $value)`,
JSON.stringify({ value: normalized.value })
]);
return this;
}
/**
* Set an or having raw statement in your query.
* Convert a json selector path to a valid postgres json path.
*/
orHavingRaw(sql, bindings) {
this.qb.orHavingRaw(sql, bindings);
return this;
}
/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or having in statement in your query.
*/
orHavingIn(column, values) {
// @ts-ignore
this.qb.orHavingIn(column, values);
return this;
}
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column, values) {
this.qb.orHavingNotIn(column, values);
return this;
}
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column, values) {
this.qb.orHavingBetween(column, values);
return this;
}
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column, values) {
this.qb.orHavingNotBetween(column, values);
return this;
}
/**
* Set an or having null statement in your query.
*/
orHavingNull(column) {
// @ts-ignore
this.qb.orHavingNull(column);
return this;
}
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column) {
// @ts-ignore
this.qb.orHavingNotNull(column);
return this;
}
/**
* Set a where statement in your query.
*/
where(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.where(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (operation === undefined) {
if (Is.Array(statement)) {
throw new Error('Arrays as statement are not supported.');
parseJsonSelectorToWildcardPath(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
return parts.reduce((jsonPath, part) => {
if (part === '*') {
return `${jsonPath}[*]`;
}
if (Is.String(statement)) {
throw new Error(`The value for the "${statement}" column is undefined and where will not work.`);
if (/^\d+$/.test(part)) {
return `${jsonPath}[${part}]`;
}
this.qb.where(statement);
return this;
}
if (value === undefined) {
this.qb.where(statement, operation);
return this;
}
this.qb.where(statement, operation, value);
return this;
return `${jsonPath}.${part}`;
}, '$');
}
/**
* Set a where not statement in your query.
* Normalize operator/value pair for postgres json path comparisons.
*/
whereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.whereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
normalizeJsonOperation(operator, value) {
if (Is.Undefined(value)) {
return {
operator: '==',
value: operator
};
}
if (value === undefined) {
this.qb.whereNot(statement);
return this;
}
this.qb.whereNot(statement, value);
return this;
return {
operator: this.getJsonPathOperator(operator),
value
};
}
/**
* Set a where raw statement in your query.
* Convert query operators to postgres json path operators.
*/
whereRaw(sql, bindings) {
this.qb.whereRaw(sql, bindings);
return this;
getJsonPathOperator(operator) {
const operators = {
'=': '==',
'==': '==',
'!=': '!=',
'<>': '!=',
'>': '>',
'>=': '>=',
'<': '<',
'<=': '<='
};
return operators[operator] || operator;
}
/**
* Set a where exists statement in your query.
*/
whereExists(closure) {
const driver = this.clone();
this.qb.whereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure) {
const driver = this.clone();
this.qb.whereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where like statement in your query.
*/
whereLike(column, value) {
this.qb.whereLike(column, value);
return this;
}
/**
* Set a where ILike statement in your query.
*/
whereILike(column, value) {
this.qb.whereILike(column, value);
return this;
}
/**
* Set a where in statement in your query.
*/
whereIn(column, values) {
this.qb.whereIn(column, values);
return this;
}
/**
* Set a where not in statement in your query.
*/
whereNotIn(column, values) {
this.qb.whereNotIn(column, values);
return this;
}
/**
* Set a where between statement in your query.
*/
whereBetween(column, values) {
this.qb.whereBetween(column, values);
return this;
}
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column, values) {
this.qb.whereNotBetween(column, values);
return this;
}
/**
* Set a where null statement in your query.
*/
whereNull(column) {
this.qb.whereNull(column);
return this;
}
/**
* Set a where not null statement in your query.
*/
whereNotNull(column) {
this.qb.whereNotNull(column);
return this;
}
/**
* Set a or where statement in your query.
*/
orWhere(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhere(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (operation === undefined) {
this.qb.orWhere(statement);
return this;
}
if (value === undefined) {
this.qb.orWhere(statement, operation);
return this;
}
this.qb.orWhere(statement, operation, value);
return this;
}
/**
* Set an or where not statement in your query.
*/
orWhereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (value === undefined) {
this.qb.orWhereNot(statement);
return this;
}
this.qb.orWhereNot(statement, value);
return this;
}
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql, bindings) {
this.qb.orWhereRaw(sql, bindings);
return this;
}
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure) {
const driver = this.clone();
this.qb.orWhereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure) {
const driver = this.clone();
this.qb.orWhereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where like statement in your query.
*/
orWhereLike(column, value) {
this.qb.orWhereLike(column, value);
return this;
}
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column, value) {
this.qb.orWhereILike(column, value);
return this;
}
/**
* Set an or where in statement in your query.
*/
orWhereIn(column, values) {
this.qb.orWhereIn(column, values);
return this;
}
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column, values) {
this.qb.orWhereNotIn(column, values);
return this;
}
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column, values) {
this.qb.orWhereBetween(column, values);
return this;
}
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column, values) {
this.qb.orWhereNotBetween(column, values);
return this;
}
/**
* Set an or where null statement in your query.
*/
orWhereNull(column) {
this.qb.orWhereNull(column);
return this;
}
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column) {
this.qb.orWhereNotNull(column);
return this;
}
/**
* Set an order by statement in your query.
*/
orderBy(column, direction = 'ASC') {
this.qb.orderBy(column, direction.toUpperCase());
return this;
}
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql, bindings) {
this.qb.orderByRaw(sql, bindings);
return this;
}
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column = 'createdAt') {
return this.orderBy(column, 'DESC');
}
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column = 'createdAt') {
return this.orderBy(column, 'ASC');
}
/**
* Set the skip number in your query.
*/
offset(number) {
this.qb.offset(number);
return this;
}
/**
* Set the limit number in your query.
*/
limit(number) {
this.qb.limit(number);
return this;
}
}

@@ -9,8 +9,6 @@ /**

*/
import { type PaginatedResponse, type PaginationOptions } from '@athenna/common';
import type { Knex } from 'knex';
import { Driver } from '#src/database/drivers/Driver';
import { Transaction } from '#src/database/transactions/Transaction';
import type { ConnectionOptions, Direction, Operations } from '#src/types';
export declare class SqliteDriver extends Driver<Knex, Knex.QueryBuilder> {
import type { Operations } from '#src/types';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
import type { ConnectionOptions } from '#src/types/ConnectionOptions';
export declare class SqliteDriver extends BaseKnexDriver {
/**

@@ -21,34 +19,2 @@ * Connect to database.

/**
* Close the connection with database in this instance.
*/
close(): Promise<void>;
/**
* Creates a new instance of query builder.
*/
query(): Knex.QueryBuilder;
/**
* Sync a model schema with database.
*/
sync(): Promise<void>;
/**
* Create a new transaction.
*/
startTransaction(): Promise<Transaction<Knex.Transaction, Knex.QueryBuilder>>;
/**
* Commit the transaction.
*/
commitTransaction(): Promise<void>;
/**
* Rollback the transaction.
*/
rollbackTransaction(): Promise<void>;
/**
* Run database migrations.
*/
runMigrations(): Promise<void>;
/**
* Revert database migrations.
*/
revertMigrations(): Promise<void>;
/**
* List all databases available.

@@ -58,10 +24,2 @@ */

/**
* Get the current database name.
*/
getCurrentDatabase(): Promise<string | undefined>;
/**
* Verify if database exists.
*/
hasDatabase(database: string): Promise<boolean>;
/**
* Create a new database.

@@ -79,18 +37,2 @@ */

/**
* Verify if table exists.
*/
hasTable(table: string): Promise<boolean>;
/**
* Create a new table in database.
*/
createTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Alter a table in database.
*/
alterTable(table: string, closure: (builder: Knex.TableBuilder) => void | Promise<void>): Promise<void>;
/**
* Drop a table in database.
*/
dropTable(table: string): Promise<void>;
/**
* Remove all data inside some database table

@@ -101,46 +43,6 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
* Create many values in database.
*/
raw<T = any>(sql: string, bindings?: any): T;
createMany<T = any>(data?: Partial<T>[]): Promise<T[]>;
/**
* Calculate the average of a given column.
*/
avg(column: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
avgDistinct(column: string): Promise<string>;
/**
* Get the max number of a given column.
*/
max(column: string): Promise<string>;
/**
* Get the min number of a given column.
*/
min(column: string): Promise<string>;
/**
* Sum all numbers of a given column.
*/
sum(column: string): Promise<string>;
/**
* Sum all numbers of a given column in distinct mode.
*/
sumDistinct(column: string): Promise<string>;
/**
* Increment a value of a given column.
*/
increment(column: string): Promise<void>;
/**
* Decrement a value of a given column.
*/
decrement(column: string): Promise<void>;
/**
* Calculate the average of a given column using distinct.
*/
count(column?: string): Promise<string>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: string): Promise<string>;
/**
* Find a value in database.

@@ -153,194 +55,31 @@ */

findMany<T = any>(): Promise<T[]>;
whereJson(column: string, value: any): this;
whereJson(column: string, operation: Operations, value: any): this;
orWhereJson(column: string, value: any): this;
orWhereJson(column: string, operation: Operations, value: any): this;
/**
* Find many values in database and return as paginated response.
* Convert a json selector path to sqlite json path.
*/
paginate<T = any>(page?: PaginationOptions | number, limit?: number, resourceUrl?: string): Promise<PaginatedResponse<T>>;
private parseJsonSelectorToSqlitePath;
/**
* Create a value in database.
* Split a json selector around the wildcard.
*/
create<T = any>(data?: Partial<T>): Promise<T>;
private parseJsonSelectorToWildcardParts;
/**
* Create many values in database.
* Convert path parts to a valid json path.
*/
createMany<T = any>(data?: Partial<T>[]): Promise<T[]>;
private toJsonPath;
/**
* Create data or update if already exists.
* Normalize operator/value pairs from the whereJson overloads.
*/
createOrUpdate<T = any>(data?: Partial<T>): Promise<T | T[]>;
private normalizeJsonOperation;
/**
* Update a value in database.
* Normalize json strings returned by sqlite into arrays/objects.
*/
update<T = any>(data: Partial<T>): Promise<T | T[]>;
private normalizeRow;
/**
* Delete one value in database.
* Parse stringified json objects/arrays returned by sqlite.
*/
delete(): Promise<void>;
private normalizeJsonValue;
/**
* Set the table that this query will be executed.
*/
table(table: string): this;
/**
* Log in console the actual query built.
*/
dump(): this;
/**
* Set the columns that should be selected on query.
*/
select(...columns: string[]): this;
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql: string, bindings?: any): this;
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table: string): this;
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql: string, bindings?: any): this;
/**
* Set a join statement in your query.
*/
join(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left join statement in your query.
*/
leftJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right join statement in your query.
*/
rightJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a cross join statement in your query.
*/
crossJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table: any, column1?: any, operation?: any | Operations, column2?: any): this;
/**
* Set a join raw statement in your query.
*/
joinRaw(sql: string, bindings?: any): this;
/**
* Set a group by statement in your query.
*/
groupBy(...columns: string[]): this;
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql: string, bindings?: any): this;
having(column: string): this;
having(column: string, value: any): this;
having(column: string, operation: Operations, value: any): this;
/**
* Set a having raw statement in your query.
*/
havingRaw(sql: string, bindings?: any): this;
/**
* Set a having exists statement in your query.
*/
havingExists(closure: (query: SqliteDriver) => void): this;
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure: (query: SqliteDriver) => void): this;
/**
* Set a having in statement in your query.
*/
havingIn(column: string, values: any[]): this;
/**
* Set a having not in statement in your query.
*/
havingNotIn(column: string, values: any[]): this;
/**
* Set a having between statement in your query.
*/
havingBetween(column: string, values: [any, any]): this;
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column: string, values: [any, any]): this;
/**
* Set a having null statement in your query.
*/
havingNull(column: string): this;
/**
* Set a having not null statement in your query.
*/
havingNotNull(column: string): this;
orHaving(column: string): this;
orHaving(column: string, value: any): this;
orHaving(column: string, operation: Operations, value: any): this;
/**
* Set an or having raw statement in your query.
*/
orHavingRaw(sql: string, bindings?: any): this;
/**
* Set an or having exists statement in your query.
*/
orHavingExists(closure: (query: SqliteDriver) => void): this;
/**
* Set an or having not exists statement in your query.
*/
orHavingNotExists(closure: (query: SqliteDriver) => void): this;
/**
* Set an or having in statement in your query.
*/
orHavingIn(column: string, values: any[]): this;
/**
* Set an or having not in statement in your query.
*/
orHavingNotIn(column: string, values: any[]): this;
/**
* Set an or having between statement in your query.
*/
orHavingBetween(column: string, values: [any, any]): this;
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column: string, values: [any, any]): this;
/**
* Set an or having null statement in your query.
*/
orHavingNull(column: string): this;
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column: string): this;
where(statement: Record<string, any>): this;
where(key: string, value: any): this;
where(key: string, operation: Operations, value: any): this;
whereNot(statement: Record<string, any>): this;
whereNot(key: string, value: any): this;
/**
* Set a where raw statement in your query.
*/
whereRaw(sql: string, bindings?: any): this;
/**
* Set a where exists statement in your query.
*/
whereExists(closure: (query: SqliteDriver) => void): this;
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure: (query: SqliteDriver) => void): this;
/**
* Set a where like statement in your query.
*/
whereLike(column: string, value: any): this;
/**
* Set a where ILike statement in your query.

@@ -350,100 +89,5 @@ */

/**
* Set a where in statement in your query.
* Set a where ILike statement in your query.
*/
whereIn(column: string, values: any[]): this;
/**
* Set a where not in statement in your query.
*/
whereNotIn(column: string, values: any[]): this;
/**
* Set a where between statement in your query.
*/
whereBetween(column: string, values: [any, any]): this;
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column: string, values: [any, any]): this;
/**
* Set a where null statement in your query.
*/
whereNull(column: string): this;
/**
* Set a where not null statement in your query.
*/
whereNotNull(column: string): this;
orWhere(statement: Record<string, any>): this;
orWhere(key: string, value: any): this;
orWhere(key: string, operation: Operations, value: any): this;
orWhereNot(statement: Record<string, any>): this;
orWhereNot(key: string, value: any): this;
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql: string, bindings?: any): this;
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure: (query: SqliteDriver) => void): this;
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure: (query: SqliteDriver) => void): this;
/**
* Set an or where like statement in your query.
*/
orWhereLike(column: string, value: any): this;
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column: string, value: any): this;
/**
* Set an or where in statement in your query.
*/
orWhereIn(column: string, values: any[]): this;
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column: string, values: any[]): this;
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column: string, values: [any, any]): this;
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column: string, values: [any, any]): this;
/**
* Set an or where null statement in your query.
*/
orWhereNull(column: string): this;
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column: string): this;
/**
* Set an order by statement in your query.
*/
orderBy(column: string, direction?: Direction): this;
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql: string, bindings?: any): this;
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column?: string): this;
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column?: string): this;
/**
* Set the skip number in your query.
*/
offset(number: number): this;
/**
* Set the limit number in your query.
*/
limit(number: number): this;
}

@@ -9,14 +9,10 @@ /**

*/
/* eslint-disable @typescript-eslint/ban-ts-comment */
import { Exec, Is, Json, Options } from '@athenna/common';
import { debug } from '#src/debug';
import { Log } from '@athenna/logger';
import { Driver } from '#src/database/drivers/Driver';
import { Is, Json, Options } from '@athenna/common';
import { ConnectionFactory } from '#src/factories/ConnectionFactory';
import { Transaction } from '#src/database/transactions/Transaction';
import { MigrationSource } from '#src/database/migrations/MigrationSource';
import { BaseKnexDriver } from '#src/database/drivers/BaseKnexDriver';
import { WrongMethodException } from '#src/exceptions/WrongMethodException';
import { PROTECTED_QUERY_METHODS } from '#src/constants/ProtectedQueryMethods';
import { NotConnectedDatabaseException } from '#src/exceptions/NotConnectedDatabaseException';
export class SqliteDriver extends Driver {
import { EmptyColumnException } from '#src/exceptions/EmptyColumnException';
export class SqliteDriver extends BaseKnexDriver {
/**

@@ -66,85 +62,2 @@ * Connect to database.

/**
* Close the connection with database in this instance.
*/
async close() {
if (!this.isConnected) {
return;
}
await this.client.destroy();
this.qb = null;
this.tableName = null;
this.client = null;
this.isConnected = false;
ConnectionFactory.setClient(this.connection, null);
}
/**
* Creates a new instance of query builder.
*/
query() {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
}
const query = this.useSetQB
? this.qb.table(this.tableName)
: this.client.queryBuilder().table(this.tableName);
const handler = {
get: (target, propertyKey) => {
if (PROTECTED_QUERY_METHODS.includes(propertyKey)) {
this.qb = this.query();
}
return target[propertyKey];
}
};
return new Proxy(query, handler);
}
/**
* Sync a model schema with database.
*/
async sync() {
debug(`database sync with ${SqliteDriver.name} is not available yet, use migration instead.`);
}
/**
* Create a new transaction.
*/
async startTransaction() {
const trx = await this.client.transaction();
return new Transaction(this.clone().setClient(trx));
}
/**
* Commit the transaction.
*/
async commitTransaction() {
const client = this.client;
await client.commit();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Rollback the transaction.
*/
async rollbackTransaction() {
const client = this.client;
await client.rollback();
this.tableName = null;
this.client = null;
this.isConnected = false;
}
/**
* Run database migrations.
*/
async runMigrations() {
await this.client.migrate.latest({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* Revert database migrations.
*/
async revertMigrations() {
await this.client.migrate.rollback({
migrationSource: new MigrationSource(this.connection)
});
}
/**
* List all databases available.

@@ -157,15 +70,2 @@ */

/**
* Get the current database name.
*/
async getCurrentDatabase() {
return this.client.client.database();
}
/**
* Verify if database exists.
*/
async hasDatabase(database) {
const databases = await this.getDatabases();
return databases.includes(database);
}
/**
* Create a new database.

@@ -202,26 +102,2 @@ */

/**
* Verify if table exists.
*/
async hasTable(table) {
return this.client.schema.hasTable(table);
}
/**
* Create a new table in database.
*/
async createTable(table, closure) {
await this.client.schema.createTable(table, closure);
}
/**
* Alter a table in database.
*/
async alterTable(table, closure) {
await this.client.schema.alterTable(table, closure);
}
/**
* Drop a table in database.
*/
async dropTable(table) {
await this.client.schema.dropTableIfExists(table);
}
/**
* Remove all data inside some database table

@@ -234,117 +110,2 @@ * and restart the identity of the table.

/**
* Make a raw query in database.
*/
raw(sql, bindings) {
return this.client.raw(sql, bindings);
}
/**
* Calculate the average of a given column.
*/
async avg(column) {
const [{ avg }] = await this.qb.avg({ avg: column });
return avg;
}
/**
* Calculate the average of a given column using distinct.
*/
async avgDistinct(column) {
const [{ avg }] = await this.qb.avgDistinct({ avg: column });
return avg;
}
/**
* Get the max number of a given column.
*/
async max(column) {
const [{ max }] = await this.qb.max({ max: column });
return max;
}
/**
* Get the min number of a given column.
*/
async min(column) {
const [{ min }] = await this.qb.min({ min: column });
return min;
}
/**
* Sum all numbers of a given column.
*/
async sum(column) {
const [{ sum }] = await this.qb.sum({ sum: column });
return sum;
}
/**
* Sum all numbers of a given column in distinct mode.
*/
async sumDistinct(column) {
const [{ sum }] = await this.qb.sumDistinct({ sum: column });
return sum;
}
/**
* Increment a value of a given column.
*/
async increment(column) {
await this.qb.increment(column);
}
/**
* Decrement a value of a given column.
*/
async decrement(column) {
await this.qb.decrement(column);
}
/**
* Calculate the average of a given column using distinct.
*/
async count(column = '*') {
const [{ count }] = await this.qb.count({ count: column });
return `${count}`;
}
/**
* Calculate the average of a given column using distinct.
*/
async countDistinct(column) {
const [{ count }] = await this.qb.countDistinct({ count: column });
return `${count}`;
}
/**
* Find a value in database.
*/
async find() {
return this.qb.first();
}
/**
* Find many values in database.
*/
async findMany() {
const data = await this.qb;
this.qb = this.query();
return data;
}
/**
* Find many values in database and return as paginated response.
*/
async paginate(page = { page: 0, limit: 10, resourceUrl: '/' }, limit = 10, resourceUrl = '/') {
if (Is.Number(page)) {
page = { page, limit, resourceUrl };
}
const [{ count }] = await this.qb
.clone()
.clearOrder()
.clearSelect()
.count({ count: '*' });
const data = await this.offset(page.page * page.limit)
.limit(page.limit)
.findMany();
return Exec.pagination(data, parseInt(count), page);
}
/**
* Create a value in database.
*/
async create(data = {}) {
if (Is.Array(data)) {
throw new WrongMethodException('create', 'createMany');
}
const created = await this.createMany([data]);
return created[0];
}
/**
* Create many values in database.

@@ -356,402 +117,153 @@ */

}
return this.qb.insert(data, '*');
const preparedData = data.map(data => this.prepareInsert(data));
return this.qb.insert(preparedData, '*');
}
/**
* Create data or update if already exists.
* Find a value in database.
*/
async createOrUpdate(data = {}) {
const query = this.qb.clone();
const hasValue = await query.first();
if (hasValue) {
await this.qb
.where(this.primaryKey, hasValue[this.primaryKey])
.update(data);
return this.where(this.primaryKey, hasValue[this.primaryKey]).find();
}
return this.create(data);
async find() {
const data = await super.find();
return this.normalizeRow(data);
}
/**
* Update a value in database.
* Find many values in database.
*/
async update(data) {
await this.qb.clone().update(data);
const result = await this.findMany();
if (result.length === 1) {
return result[0];
}
return result;
async findMany() {
const data = await super.findMany();
return data.map(row => this.normalizeRow(row));
}
/**
* Delete one value in database.
* Set a where json statement in your query.
*/
async delete() {
await this.qb.delete();
}
/**
* Set the table that this query will be executed.
*/
table(table) {
if (!this.isConnected) {
throw new NotConnectedDatabaseException();
whereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('whereJson');
}
this.tableName = table;
this.qb = this.query();
return this;
}
/**
* Log in console the actual query built.
*/
dump() {
console.log(this.qb.toSQL().toNative());
return this;
}
/**
* Set the columns that should be selected on query.
*/
select(...columns) {
this.qb.select(...columns);
return this;
}
/**
* Set the columns that should be selected on query raw.
*/
selectRaw(sql, bindings) {
return this.select(this.raw(sql, bindings));
}
/**
* Set the table that should be used on query.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
from(table) {
this.qb.from(table);
return this;
}
/**
* Set the table that should be used on query raw.
* Different from `table()` method, this method
* doesn't change the driver table.
*/
fromRaw(sql, bindings) {
return this.from(this.raw(sql, bindings));
}
/**
* Set a join statement in your query.
*/
join(table, column1, operation, column2) {
return this.joinByType('join', table, column1, operation, column2);
}
/**
* Set a left join statement in your query.
*/
leftJoin(table, column1, operation, column2) {
return this.joinByType('leftJoin', table, column1, operation, column2);
}
/**
* Set a right join statement in your query.
*/
rightJoin(table, column1, operation, column2) {
return this.joinByType('rightJoin', table, column1, operation, column2);
}
/**
* Set a cross join statement in your query.
*/
crossJoin(table, column1, operation, column2) {
return this.joinByType('crossJoin', table, column1, operation, column2);
}
/**
* Set a full outer join statement in your query.
*/
fullOuterJoin(table, column1, operation, column2) {
return this.joinByType('fullOuterJoin', table, column1, operation, column2);
}
/**
* Set a left outer join statement in your query.
*/
leftOuterJoin(table, column1, operation, column2) {
return this.joinByType('leftOuterJoin', table, column1, operation, column2);
}
/**
* Set a right outer join statement in your query.
*/
rightOuterJoin(table, column1, operation, column2) {
return this.joinByType('rightOuterJoin', table, column1, operation, column2);
}
/**
* Set a join raw statement in your query.
*/
joinRaw(sql, bindings) {
this.qb.joinRaw(sql, bindings);
return this;
}
/**
* Set a group by statement in your query.
*/
groupBy(...columns) {
this.qb.groupBy(...columns);
return this;
}
/**
* Set a group by raw statement in your query.
*/
groupByRaw(sql, bindings) {
this.qb.groupByRaw(sql, bindings);
return this;
}
/**
* Set a having statement in your query.
*/
having(column, operation, value) {
if (operation === undefined) {
this.qb.having(column);
return this;
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
if (value === undefined) {
this.qb.having(column, '=', operation);
const normalized = this.normalizeJsonOperation(operator, value);
if (!parsed.path.includes('*')) {
this.qb.whereRaw('json_extract(??, ?) ' + normalized.operator + ' ?', [
parsed.column,
this.parseJsonSelectorToSqlitePath(parsed.path),
normalized.value
]);
return this;
}
this.qb.having(column, operation, value);
const wildcard = this.parseJsonSelectorToWildcardParts(parsed.path);
this.qb.whereRaw('exists (select 1 from json_each(??, ?) where json_extract(json_each.value, ?) ' +
normalized.operator +
' ?)', [parsed.column, wildcard.arrayPath, wildcard.valuePath, normalized.value]);
return this;
}
/**
* Set a having raw statement in your query.
* Set an or where json statement in your query.
*/
havingRaw(sql, bindings) {
this.qb.havingRaw(sql, bindings);
return this;
}
/**
* Set a having exists statement in your query.
*/
havingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having not exists statement in your query.
*/
havingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.havingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a having in statement in your query.
*/
havingIn(column, values) {
this.qb.havingIn(column, values);
return this;
}
/**
* Set a having not in statement in your query.
*/
havingNotIn(column, values) {
this.qb.havingNotIn(column, values);
return this;
}
/**
* Set a having between statement in your query.
*/
havingBetween(column, values) {
this.qb.havingBetween(column, values);
return this;
}
/**
* Set a having not between statement in your query.
*/
havingNotBetween(column, values) {
this.qb.havingNotBetween(column, values);
return this;
}
/**
* Set a having null statement in your query.
*/
havingNull(column) {
this.qb.havingNull(column);
return this;
}
/**
* Set a having not null statement in your query.
*/
havingNotNull(column) {
this.qb.havingNotNull(column);
return this;
}
/**
* Set an or having statement in your query.
*/
orHaving(column, operation, value) {
if (operation === undefined) {
this.qb.orHaving(column);
return this;
orWhereJson(column, operator, value) {
if (Is.Undefined(column) || !Is.String(column)) {
throw new EmptyColumnException('orWhereJson');
}
if (value === undefined) {
this.qb.orHaving(column, '=', operation);
const parsed = this.parseJsonSelector(column);
if (!parsed) {
throw new Error(`Invalid JSON selector: ${column}`);
}
const normalized = this.normalizeJsonOperation(operator, value);
if (!parsed.path.includes('*')) {
this.qb.orWhereRaw('json_extract(??, ?) ' + normalized.operator + ' ?', [
parsed.column,
this.parseJsonSelectorToSqlitePath(parsed.path),
normalized.value
]);
return this;
}
this.qb.orHaving(column, operation, value);
const wildcard = this.parseJsonSelectorToWildcardParts(parsed.path);
this.qb.orWhereRaw('exists (select 1 from json_each(??, ?) where json_extract(json_each.value, ?) ' +
normalized.operator +
' ?)', [parsed.column, wildcard.arrayPath, wildcard.valuePath, normalized.value]);
return this;
}
/**
* Set an or having raw statement in your query.
* Convert a json selector path to sqlite json path.
*/
orHavingRaw(sql, bindings) {
this.qb.orHavingRaw(sql, bindings);
return this;
parseJsonSelectorToSqlitePath(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
return this.toJsonPath(parts);
}
/**
* Set an or having exists statement in your query.
* Split a json selector around the wildcard.
*/
orHavingExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
parseJsonSelectorToWildcardParts(path) {
const parts = path
.split('->')
.map(part => part.trim())
.filter(Boolean);
const wildcardIndex = parts.indexOf('*');
return {
arrayPath: this.toJsonPath(parts.slice(0, wildcardIndex)),
valuePath: this.toJsonPath(parts.slice(wildcardIndex + 1))
};
}
/**
* Set an or having not exists statement in your query.
* Convert path parts to a valid json path.
*/
orHavingNotExists(closure) {
const driver = this.clone();
// @ts-ignore
this.qb.orHavingNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
toJsonPath(parts) {
return parts.reduce((jsonPath, part) => {
if (/^\d+$/.test(part)) {
return `${jsonPath}[${part}]`;
}
return `${jsonPath}.${part}`;
}, '$');
}
/**
* Set an or having in statement in your query.
* Normalize operator/value pairs from the whereJson overloads.
*/
orHavingIn(column, values) {
// @ts-ignore
this.qb.orHavingIn(column, values);
return this;
normalizeJsonOperation(operator, value) {
if (Is.Undefined(value)) {
return {
operator: '=',
value: operator
};
}
return {
operator,
value
};
}
/**
* Set an or having not in statement in your query.
* Normalize json strings returned by sqlite into arrays/objects.
*/
orHavingNotIn(column, values) {
this.qb.orHavingNotIn(column, values);
return this;
normalizeRow(row) {
if (!row || !Is.Object(row)) {
return row;
}
return Object.entries(row).reduce((normalized, [key, value]) => {
normalized[key] = this.normalizeJsonValue(value);
return normalized;
}, {});
}
/**
* Set an or having between statement in your query.
* Parse stringified json objects/arrays returned by sqlite.
*/
orHavingBetween(column, values) {
this.qb.orHavingBetween(column, values);
return this;
}
/**
* Set an or having not between statement in your query.
*/
orHavingNotBetween(column, values) {
this.qb.orHavingNotBetween(column, values);
return this;
}
/**
* Set an or having null statement in your query.
*/
orHavingNull(column) {
// @ts-ignore
this.qb.orHavingNull(column);
return this;
}
/**
* Set an or having not null statement in your query.
*/
orHavingNotNull(column) {
// @ts-ignore
this.qb.orHavingNotNull(column);
return this;
}
/**
* Set a where statement in your query.
*/
where(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.where(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
normalizeJsonValue(value) {
if (!Is.String(value)) {
return value;
}
if (operation === undefined) {
if (Is.Array(statement)) {
throw new Error('Arrays as statement are not supported.');
}
if (Is.String(statement)) {
throw new Error(`The value for the "${statement}" column is undefined and where will not work.`);
}
this.qb.where(statement);
return this;
const trimmed = value.trim();
if (!(trimmed.startsWith('{') && trimmed.endsWith('}')) &&
!(trimmed.startsWith('[') && trimmed.endsWith(']'))) {
return value;
}
if (value === undefined) {
this.qb.where(statement, operation);
return this;
try {
return JSON.parse(trimmed);
}
this.qb.where(statement, operation, value);
return this;
}
/**
* Set a where not statement in your query.
*/
whereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.whereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
catch {
return value;
}
if (value === undefined) {
this.qb.whereNot(statement);
return this;
}
this.qb.whereNot(statement, value);
return this;
}
/**
* Set a where raw statement in your query.
*/
whereRaw(sql, bindings) {
this.qb.whereRaw(sql, bindings);
return this;
}
/**
* Set a where exists statement in your query.
*/
whereExists(closure) {
const driver = this.clone();
this.qb.whereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where not exists statement in your query.
*/
whereNotExists(closure) {
const driver = this.clone();
this.qb.whereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set a where like statement in your query.
*/
whereLike(column, value) {
this.qb.whereLike(column, value);
return this;
}
/**
* Set a where ILike statement in your query.

@@ -764,120 +276,4 @@ */

/**
* Set a where in statement in your query.
* Set a where ILike statement in your query.
*/
whereIn(column, values) {
this.qb.whereIn(column, values);
return this;
}
/**
* Set a where not in statement in your query.
*/
whereNotIn(column, values) {
this.qb.whereNotIn(column, values);
return this;
}
/**
* Set a where between statement in your query.
*/
whereBetween(column, values) {
this.qb.whereBetween(column, values);
return this;
}
/**
* Set a where not between statement in your query.
*/
whereNotBetween(column, values) {
this.qb.whereNotBetween(column, values);
return this;
}
/**
* Set a where null statement in your query.
*/
whereNull(column) {
this.qb.whereNull(column);
return this;
}
/**
* Set a where not null statement in your query.
*/
whereNotNull(column) {
this.qb.whereNotNull(column);
return this;
}
/**
* Set a or where statement in your query.
*/
orWhere(statement, operation, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhere(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (operation === undefined) {
this.qb.orWhere(statement);
return this;
}
if (value === undefined) {
this.qb.orWhere(statement, operation);
return this;
}
this.qb.orWhere(statement, operation, value);
return this;
}
/**
* Set an or where not statement in your query.
*/
orWhereNot(statement, value) {
if (Is.Function(statement)) {
const driver = this.clone();
this.qb.orWhereNot(function () {
statement(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
if (value === undefined) {
this.qb.orWhereNot(statement);
return this;
}
this.qb.orWhereNot(statement, value);
return this;
}
/**
* Set a or where raw statement in your query.
*/
orWhereRaw(sql, bindings) {
this.qb.orWhereRaw(sql, bindings);
return this;
}
/**
* Set an or where exists statement in your query.
*/
orWhereExists(closure) {
const driver = this.clone();
this.qb.orWhereExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where not exists statement in your query.
*/
orWhereNotExists(closure) {
const driver = this.clone();
this.qb.orWhereNotExists(function () {
closure(driver.setQueryBuilder(this, { useSetQB: true }));
});
return this;
}
/**
* Set an or where like statement in your query.
*/
orWhereLike(column, value) {
this.qb.orWhereLike(column, value);
return this;
}
/**
* Set an or where ILike statement in your query.
*/
orWhereILike(column, value) {

@@ -887,86 +283,2 @@ this.qb.orWhereLike(column, value);

}
/**
* Set an or where in statement in your query.
*/
orWhereIn(column, values) {
this.qb.orWhereIn(column, values);
return this;
}
/**
* Set an or where not in statement in your query.
*/
orWhereNotIn(column, values) {
this.qb.orWhereNotIn(column, values);
return this;
}
/**
* Set an or where between statement in your query.
*/
orWhereBetween(column, values) {
this.qb.orWhereBetween(column, values);
return this;
}
/**
* Set an or where not between statement in your query.
*/
orWhereNotBetween(column, values) {
this.qb.orWhereNotBetween(column, values);
return this;
}
/**
* Set an or where null statement in your query.
*/
orWhereNull(column) {
this.qb.orWhereNull(column);
return this;
}
/**
* Set an or where not null statement in your query.
*/
orWhereNotNull(column) {
this.qb.orWhereNotNull(column);
return this;
}
/**
* Set an order by statement in your query.
*/
orderBy(column, direction = 'ASC') {
this.qb.orderBy(column, direction.toUpperCase());
return this;
}
/**
* Set an order by raw statement in your query.
*/
orderByRaw(sql, bindings) {
this.qb.orderByRaw(sql, bindings);
return this;
}
/**
* Order the results easily by the latest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
latest(column = 'createdAt') {
return this.orderBy(column, 'DESC');
}
/**
* Order the results easily by the oldest date. By default, the result will
* be ordered by the table's "createdAt" column.
*/
oldest(column = 'createdAt') {
return this.orderBy(column, 'ASC');
}
/**
* Set the skip number in your query.
*/
offset(number) {
this.qb.offset(number);
return this;
}
/**
* Set the limit number in your query.
*/
limit(number) {
this.qb.limit(number);
return this;
}
}

@@ -10,5 +10,5 @@ /**

import { Collection, type PaginatedResponse, type PaginationOptions } from '@athenna/common';
import type { ModelRelations } from '#src/types';
import { type Faker } from '@faker-js/faker';
import { ModelSchema } from '#src/models/schemas/ModelSchema';
import type { ModelColumns, ModelRelations } from '#src/types';
import { ORIGINAL_SYMBOL } from '#src/constants/OriginalSymbol';

@@ -99,3 +99,4 @@ import { ModelFactory } from '#src/models/factories/ModelFactory';

*/
static pluck<T extends typeof BaseModel, K extends keyof InstanceType<T> = keyof InstanceType<T>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K]>;
static pluck<T extends typeof BaseModel, K extends Extract<ModelColumns<InstanceType<T>>, keyof InstanceType<T>>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K]>;
static pluck<T extends typeof BaseModel>(this: T, key: ModelColumns<InstanceType<T>>, where?: Partial<InstanceType<T>>): Promise<any>;
/**

@@ -105,3 +106,4 @@ * Find many values in database but returns only the

*/
static pluckMany<T extends typeof BaseModel, K extends keyof InstanceType<T> = keyof InstanceType<T>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K][]>;
static pluckMany<T extends typeof BaseModel, K extends Extract<ModelColumns<InstanceType<T>>, keyof InstanceType<T>>>(this: T, key: K, where?: Partial<InstanceType<T>>): Promise<InstanceType<T>[K][]>;
static pluckMany<T extends typeof BaseModel>(this: T, key: ModelColumns<InstanceType<T>>, where?: Partial<InstanceType<T>>): Promise<any[]>;
/**

@@ -108,0 +110,0 @@ * Find a value in database.

@@ -139,6 +139,2 @@ /**

}
/**
* Find value in database but returns only the value of
* selected column directly.
*/
static async pluck(key, where) {

@@ -151,6 +147,2 @@ const query = this.query();

}
/**
* Find many values in database but returns only the
* values of selected column directly.
*/
static async pluckMany(key, where) {

@@ -293,3 +285,4 @@ const query = this.query();

this[ORIGINAL_SYMBOL] = {};
Object.keys(Json.copy(this)).forEach(key => {
const copied = Json.copy(this);
Object.keys(copied).forEach(key => {
const value = this[key];

@@ -302,3 +295,3 @@ if (Is.Array(value) && value[0] && ORIGINAL_SYMBOL in value[0]) {

}
this[ORIGINAL_SYMBOL][key] = value;
this[ORIGINAL_SYMBOL][key] = copied[key];
});

@@ -305,0 +298,0 @@ return this;

@@ -73,7 +73,7 @@ /**

*/
count(column?: ModelColumns<M>): Promise<string>;
count(column?: ModelColumns<M>): Promise<number>;
/**
* Calculate the average of a given column using distinct.
*/
countDistinct(column: ModelColumns<M>): Promise<string>;
countDistinct(column: ModelColumns<M>): Promise<number>;
/**

@@ -83,3 +83,4 @@ * Find value in database but returns only the value of

*/
pluck<K extends keyof M = ModelColumns<M>>(column: K): Promise<M[K]>;
pluck<K extends Extract<ModelColumns<M>, keyof M>>(column: K): Promise<M[K]>;
pluck(column: ModelColumns<M>): Promise<any>;
/**

@@ -89,3 +90,4 @@ * Find many values in database but returns only the

*/
pluckMany<K extends keyof M = ModelColumns<M>>(column: K): Promise<M[K][]>;
pluckMany<K extends Extract<ModelColumns<M>, keyof M>>(column: K): Promise<M[K][]>;
pluckMany(column: ModelColumns<M>): Promise<any[]>;
/**

@@ -218,6 +220,2 @@ * Find a value in database.

/**
* Set a orHaving in statement in your query.
*/
orHavingIn(column: ModelColumns<M>, values: any[]): this;
/**
* Set a orHaving not in statement in your query.

@@ -283,2 +281,4 @@ */

whereNotNull(column: ModelColumns<M>): this;
whereJson(column: ModelColumns<M>, value: any): this;
whereJson(column: ModelColumns<M>, operation: Operations, value: any): this;
orWhere(statement: (query: this) => void): this;

@@ -323,2 +323,4 @@ orWhere(statement: Partial<M>): this;

orWhereNotNull(column: ModelColumns<M>): this;
orWhereJson(column: ModelColumns<M>, value: any): this;
orWhereJson(column: ModelColumns<M>, operation: Operations, value: any): this;
/**

@@ -325,0 +327,0 @@ * Set an order by statement in your query.

@@ -9,3 +9,3 @@ /**

*/
import { Collection, Is, Options } from '@athenna/common';
import { Is, Options, Collection } from '@athenna/common';
import { QueryBuilder } from '#src/database/builders/QueryBuilder';

@@ -141,6 +141,2 @@ import { ModelGenerator } from '#src/models/factories/ModelGenerator';

}
/**
* Find value in database but returns only the value of
* selected column directly.
*/
async pluck(column) {

@@ -151,6 +147,2 @@ this.setInternalQueries();

}
/**
* Find many values in database but returns only the
* values of selected column directly.
*/
async pluckMany(column) {

@@ -501,10 +493,2 @@ this.setInternalQueries();

/**
* Set a orHaving in statement in your query.
*/
orHavingIn(column, values) {
const name = this.schema.getColumnNameByProperty(column);
super.orHavingIn(name, values);
return this;
}
/**
* Set a orHaving not in statement in your query.

@@ -656,2 +640,10 @@ */

/**
* Set a where json statement in your query.
*/
whereJson(column, operation, value) {
const name = this.schema.getColumnNameByProperty(column);
super.whereJson(name, operation, value);
return this;
}
/**
* Set a orWhere statement in your query.

@@ -773,2 +765,10 @@ */

/**
* Set an orWhereJson statement in your query.
*/
orWhereJson(column, operation, value) {
const name = this.schema.getColumnNameByProperty(column);
super.orWhereJson(name, operation, value);
return this;
}
/**
* Set an order by statement in your query.

@@ -775,0 +775,0 @@ */

@@ -10,5 +10,7 @@ /**

import type { BaseModel } from '#src/models/BaseModel';
type UnsafeColumnSelector = `${string}.${string}` | `${string}->${string}`;
export type ColumnKeys<T> = {
[K in keyof T]: T[K] extends BaseModel | BaseModel[] ? never : K;
}[keyof Omit<T, 'save' | 'fresh' | 'refresh' | 'dirty' | 'delete' | 'restore' | 'isDirty' | 'isTrashed' | 'isPersisted' | 'setOriginal' | 'load' | 'toJSON'>];
export type ModelColumns<T> = Extract<ColumnKeys<T>, string>;
export type ModelColumns<T> = Extract<ColumnKeys<T>, string> | UnsafeColumnSelector;
export {};