Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

litdb

Package Overview
Dependencies
Maintainers
0
Versions
24
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

litdb - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

dist/index.min.js

976

dist/index.d.ts
// Generated by dts-bundle-generator v9.5.1
export declare class Sql {
static ops: {
[key: string]: string;
export type DeleteOptions = {
/** force delete even with no where clause */
force?: boolean;
where?: Fragment | Fragment[];
};
export declare class Schema {
dialect: Dialect;
constructor(dialect: Dialect);
converters: {
[key: string]: TypeConverter;
};
static opKeys: string[];
static create(driver: Driver): {
(strings: TemplateStringsArray | string, ...params: any[]): Fragment;
ref<Table extends Constructor<any>>(cls: Table, as?: string): TypeRef<InstanceType<Table>>;
refs<T extends readonly Constructor[]>(...classes_0: T): ConstructorToTypeRef<T>;
join<JoinTables extends Constructor<any>[]>(...joinTables: JoinTables): SqlJoinBuilder<JoinTables>;
sqlTableNames(schema?: string): string;
sqlColumnDefinition(column: ColumnDefinition): string;
sqlIndexDefinition(table: TableDefinition, column: ColumnDefinition): string;
dropTable(table: ClassParam): string;
createTable(table: ClassParam): string;
insert(table: ClassParam, options?: {
onlyProps?: string[];
}): string;
update(table: ClassParam, options?: {
onlyProps?: string[];
}): string;
delete(table: ClassParam, options?: DeleteOptions): string;
toDbBindings(table: ClassInstance): DbBinding[];
toDbObject(table: ClassInstance, options?: {
onlyProps?: string[];
}): {
[key: string]: DbBinding;
};
}
export type SelectOptions = {
props?: string[];
columns?: string[];
sql?: Fragment | Fragment[];
export type Constructor<T = any> = new (...args: any[]) => T;
export type First<T extends readonly any[]> = T extends [
infer F,
...any[]
] ? F extends Constructor<any> ? F : never : never;
export type Last<T extends readonly any[]> = T extends [
...any[],
infer L
] ? L extends Constructor<any> ? L : never : never;
export type ScalarValue = string | bigint | number | boolean | null | symbol;
export type DbBinding = string | bigint | NodeJS.TypedArray | number | boolean | null | Record<string, string | bigint | NodeJS.TypedArray | number | boolean | null>;
export interface ReflectMeta {
name: string;
$id: symbol;
$type: {
name: string;
table?: TableDefinition;
};
$props: [
{
name: string;
column?: ColumnDefinition;
}
];
}
export type ColumnType = "INTEGER" | "SMALLINT" | "BIGINT" | "DECIMAL" | "NUMERIC" | "REAL" | "FLOAT" | "DOUBLE" | "MONEY" | "DATE" | "DATETIME" | "TIME" | "TIMEZ" | "TIMESTAMP" | "TIMESTAMPZ" | "INTERVAL" | "BOOLEAN" | "UUID" | "BLOB" | "BYTES" | "BIT" | "TEXT" | "VARCHAR" | "NVARCHAR" | "CHAR" | "NCHAR" | "JSON" | "JSONB" | "XML";
export type DialectTypes = {
native: ColumnType[];
map: Record<string, ColumnType[]>;
};
export declare class SelectQuery<Tables extends Constructor<any>[]> extends WhereQuery<Tables> {
protected _select: string[];
protected _skip: number | undefined;
protected _take: number | undefined;
select(options: SelectOptions | TemplateStringsArray | string | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
get hasSelect(): boolean;
skip(rows?: number): this;
take(rows?: number): this;
limit(skip?: number, take?: number): this;
buildSelect(): string;
buildFrom(): string;
buildGroupBy(): string;
buildHaving(): string;
buildLimit(): string;
build(): {
sql: string;
params: Record<string, any>;
export type ClassParam = ReflectMeta | {
constructor: ReflectMeta;
} | Constructor<any>;
export type ClassInstance = {
constructor: ReflectMeta;
} & Record<string, any> | Record<string, any>;
export type TypeRef<T> = T & {
$ref: {
cls: Constructor<T>;
as?: string;
};
};
export type ConstructorToTypeRef<T extends readonly any[]> = {
[K in keyof T]: T[K] extends new (...args: any[]) => infer R ? TypeRef<R> : never;
};
export type ConstructorsToRefs<T extends Constructor<any>[]> = {
[K in keyof T]: TypeRef<InstanceType<T[K]>>;
};
export type TypeRefs<Tables extends Constructor<any>[]> = {
[K in keyof Tables]: TypeRef<InstanceType<Tables[K]>>;
};
export interface TableDefinition {
name: string;
alias?: string;
}
declare class UpdateQuery<Tables extends Constructor<any>[]> extends WhereQuery<Tables> {
private _set;
set(options: {
sql?: Fragment | Fragment[];
rawSql?: string | string[];
values?: Record<string, any>;
}): this;
get hasSet(): boolean;
buildUpdate(): string;
build(): {
sql: string;
params: Record<string, any>;
export interface ColumnDefinition {
name: string;
alias?: string;
type: string;
primaryKey?: boolean;
autoIncrement?: boolean;
required?: boolean;
precision?: number;
scale?: number;
unique?: boolean;
index?: boolean;
defaultValue?: string;
}
export type Changes = {
changes: number;
lastInsertRowid: number | bigint;
};
export interface Statement<ReturnType, ParamsType extends DbBinding[]> {
get native(): any;
all(...params: ParamsType): Promise<ReturnType[]>;
one(...params: ParamsType): Promise<ReturnType | null>;
value<ReturnValue>(...params: ParamsType): Promise<ReturnValue | null>;
arrays(...params: ParamsType): Promise<any[][]>;
array(...params: ParamsType): Promise<any[] | null>;
exec(...params: ParamsType): Promise<Changes>;
run(...params: ParamsType): Promise<void>;
}
export interface SyncStatement<ReturnType, ParamsType extends DbBinding[]> {
get native(): any;
as<T extends Constructor<any>>(t: T): SyncStatement<T, ParamsType>;
allSync(...params: ParamsType): ReturnType[];
oneSync(...params: ParamsType): ReturnType | null;
valueSync<ReturnValue>(...params: ParamsType): ReturnValue | null;
arraysSync(...params: ParamsType): any[][];
arraySync(...params: ParamsType): any[] | null;
execSync(...params: ParamsType): Changes;
runSync(...params: ParamsType): void;
}
export interface TypeConverter {
toDb(value: any): any;
fromDb(value: any): any;
}
export interface NamingStrategy {
tableName(table: string): string;
columnName(column: string): string;
tableFromDef(def: TableDefinition): string;
}
export interface Dialect {
get $(): any;
strategy: NamingStrategy;
quote(name: string): string;
quoteTable(name: string): string;
quoteColumn(name: string): string;
sqlLimit(skip?: number, take?: number): Fragment;
}
export interface Driver {
get dialect(): Dialect;
get schema(): Schema;
get converters(): {
[key: string]: TypeConverter;
};
}
export type OnJoin<First extends Constructor<any>, Second extends Constructor<any>, Table extends Constructor<any>> = (from: TypeRef<InstanceType<First>>, to: TypeRef<InstanceType<Second>>, table: TypeRef<InstanceType<Table>>) => Fragment;
declare class SqlJoinBuilder<Tables extends Constructor<any>[]> implements JoinBuilder<First<Tables>> {
export interface Connection {
driver: Driver;
get table(): First<Tables>;
tables: Tables;
refs: ConstructorsToRefs<Tables>;
$: ReturnType<typeof Sql.create>;
/**
* Prepare a parameterized statement and return an async Statement
*/
prepare<ReturnType, ParamsType extends DbBinding[]>(sql: TemplateStringsArray | string, ...params: DbBinding[]): Statement<ReturnType, ParamsType extends any[] ? ParamsType : [
ParamsType
]>;
}
export interface SyncConnection {
driver: Driver;
/**
* Prepare a parameterized statement and return a sync Statement
*/
prepareSync<ReturnType, ParamsType extends DbBinding[]>(sql: TemplateStringsArray | string, ...params: DbBinding[]): SyncStatement<ReturnType, ParamsType extends any[] ? ParamsType : [
ParamsType
]>;
}
export type Fragment = {
sql: string;
params: Record<string, any>;
alias: string;
buildOn?: (refs: ConstructorsToRefs<Tables>, params: Record<string, any>) => string;
constructor(driver: Driver, ...tables: Tables);
on(expr: (...args: ConstructorsToRefs<Tables>) => Fragment): this;
as(alias: string): this;
build(refs: ConstructorsToRefs<Tables>, type: JoinType): {
type: JoinType;
table: string;
as: any;
on: string;
params: Record<string, any>;
};
export type IntoFragment<T> = Fragment & {
into: T;
};
export interface SqlBuilder {
build(): Fragment;
}
export type WhereOptions = {
equals?: Record<string, ScalarValue>;
notEquals?: Record<string, ScalarValue>;
like?: Record<string, ScalarValue>;
notLike?: Record<string, ScalarValue>;
startsWith?: Record<string, ScalarValue>;
endsWith?: Record<string, ScalarValue>;
contains?: Record<string, ScalarValue>;
in?: Record<string, ScalarValue[]>;
notIn?: Record<string, ScalarValue[]>;
isNull?: string[];
notNull?: string[];
op?: [
string,
Record<string, any>
];
sql?: Fragment;
rawSql?: string | string[];
params?: Record<string, any>;
};
export type JoinType = "JOIN" | "INNER JOIN" | "LEFT JOIN" | "RIGHT JOIN" | "OUTER JOIN" | "FULL JOIN" | "CROSS JOIN";
export type JoinDefinition = {
type: JoinType;
on?: string;
params?: Record<string, any>;
};
export interface JoinBuilder<Table extends Constructor<any>> {
get table(): Table;
get tables(): Constructor<any>[];
build(refs: ConstructorsToRefs<any>, type: JoinType): JoinDefinition;
}
export interface GroupByBuilder {
build(refs: ConstructorsToRefs<any>): Fragment;
}
export interface HavingBuilder {
build(refs: ConstructorsToRefs<any>): Fragment;
}
export interface OrderByBuilder {
build(refs: ConstructorsToRefs<any>): Fragment;
}
export declare class Meta {
cls: ReflectMeta;
static metadata: {
[id: symbol]: Meta;
};
constructor(cls: ReflectMeta);
static assertClass(table: ClassParam): ReflectMeta;
static assertTable(table: ClassParam): ReflectMeta;
static assertMeta(table: ClassParam): Meta;
get name(): string;
get tableName(): string;
get type(): {
name: string;
table?: TableDefinition | undefined;
};
get table(): TableDefinition;
get props(): [
{
name: string;
column?: ColumnDefinition | undefined;
}
];
get columns(): ColumnDefinition[];
}
export type OnJoin<First extends Constructor<any>, Second extends Constructor<any>, Table extends Constructor<any>> = (from: TypeRef<InstanceType<First>>, to: TypeRef<InstanceType<Second>>, table: TypeRef<InstanceType<Table>>) => Fragment;
export type QueryType<T> = T extends SelectQuery<any> ? SelectQuery<any> : T extends UpdateQuery<any> ? UpdateQuery<any> : T extends DeleteQuery<any> ? DeleteQuery<any> : WhereQuery<any>;
export type This<T, NewTables extends Constructor<any>[]> = QueryType<T> extends SelectQuery<any> ? SelectQuery<NewTables> : QueryType<T> extends UpdateQuery<any> ? UpdateQuery<NewTables> : QueryType<T> extends DeleteQuery<any> ? DeleteQuery<NewTables> : WhereQuery<NewTables>;
export declare class WhereQuery<Tables extends Constructor<any>[]> {
driver: Driver;
export declare class WhereQuery<Tables extends Constructor<any>[]> implements SqlBuilder {
$: ReturnType<typeof Sql.create>;
tables: [

@@ -83,6 +252,5 @@ ...Tables

refs: TypeRefs<Tables>;
constructor(driver: Driver, tables: [
constructor($: ReturnType<typeof Sql.create>, tables: [
...Tables
], metas: Meta[], refs: TypeRefs<Tables>);
$: ReturnType<typeof Sql.create>;
protected _where: {

@@ -103,4 +271,3 @@ condition: string;

};
prevJoin(): TypeRef<InstanceType<Constructor<any>>>;
createInstance<NewTable extends Constructor<any>>(table: NewTable): This<typeof WhereQuery, [
protected createInstance<NewTable extends Constructor<any>>(table: NewTable, ref?: TypeRef<InstanceType<NewTable>>): This<typeof WhereQuery, [
...Tables,

@@ -110,64 +277,67 @@ NewTable

copyInto(instance: WhereQuery<any>): WhereQuery<any>;
addJoin<NewTable extends Constructor<any>>(join: {
clone(): WhereQuery<Tables>;
protected addJoin<NewTable extends Constructor<any>>(options: {
type: JoinType;
cls: NewTable;
ref?: TypeRef<InstanceType<NewTable>>;
on?: string | ((...params: any[]) => Fragment);
as?: string;
params?: Record<string, any>;
}): This<this, [
}): This<typeof WhereQuery, [
...Tables,
NewTable
]>;
joinBuilder<NewTable extends Constructor<any>>(builder: JoinBuilder<NewTable>, typeHint?: JoinType): This<this, [
protected joinBuilder<NewTable extends Constructor<any>>(builder: JoinBuilder<NewTable>, typeHint?: JoinType): This<typeof WhereQuery, [
...Tables,
NewTable
]>;
join<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable>, options?: {
join<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable> | TypeRef<InstanceType<NewTable>>, options?: {
on?: OnJoin<Last<Tables>, NewTable, First<Tables>>;
as?: string;
} | SqlBuilder): This<this, [
} | SqlBuilder | Fragment): This<this, [
...Tables,
NewTable
]>;
leftJoin<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable>, options?: {
leftJoin<NewTable extends Constructor<any>>(cls: NewTable | TypeRef<InstanceType<NewTable>>, options?: {
on?: OnJoin<Last<Tables>, NewTable, First<Tables>>;
as?: string;
} | SqlBuilder): This<this, [
} | SqlBuilder | Fragment): This<this, [
...Tables,
NewTable
]>;
rightJoin<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable>, options?: {
rightJoin<NewTable extends Constructor<any>>(cls: NewTable | TypeRef<InstanceType<NewTable>>, options?: {
on?: OnJoin<Last<Tables>, NewTable, First<Tables>>;
as?: string;
} | SqlBuilder): This<this, [
} | SqlBuilder | Fragment): This<this, [
...Tables,
NewTable
]>;
fullJoin<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable>, options?: {
fullJoin<NewTable extends Constructor<any>>(cls: NewTable | TypeRef<InstanceType<NewTable>>, options?: {
on?: OnJoin<Last<Tables>, NewTable, First<Tables>>;
as?: string;
} | SqlBuilder): This<this, [
} | SqlBuilder | Fragment): This<this, [
...Tables,
NewTable
]>;
crossJoin<NewTable extends Constructor<any>>(cls: NewTable | JoinBuilder<NewTable>, options?: {
crossJoin<NewTable extends Constructor<any>>(cls: NewTable | TypeRef<InstanceType<NewTable>>, options?: {
on?: OnJoin<Last<Tables>, NewTable, First<Tables>>;
as?: string;
} | SqlBuilder): This<this, [
} | SqlBuilder | Fragment): This<this, [
...Tables,
NewTable
]>;
where(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
and(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
or(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
condition(condition: "AND" | "OR", options: WhereOptions): this;
where(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment) | Fragment, ...params: any[]): this;
and(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment) | Fragment, ...params: any[]): this;
or(options: WhereOptions | TemplateStringsArray | ((...params: TypeRefs<Tables>) => Fragment) | Fragment, ...params: any[]): this;
condition(condition: "AND" | "OR", options: WhereOptions | Fragment): this;
quote(symbol: string): string;
quoteTable(table: string): string;
quoteColumn(column: string): string;
alias(alias?: string): this;
as(alias?: string): this;
protected addParams(params?: Record<string, any>): void;
protected mergeParams(f: Fragment): string;
private addWhere;
buildWhere(): string;
buildJoins(): string;
protected buildWhere(): string;
protected buildJoins(): string;
into<T extends Constructor<any>>(into: T): IntoFragment<InstanceType<T>>;
build(): {

@@ -178,2 +348,57 @@ sql: string;

}
export type SelectOptions = {
props?: string[];
columns?: string[];
sql?: Fragment;
};
export declare class SelectQuery<Tables extends Constructor<any>[]> extends WhereQuery<Tables> {
protected _select: string[];
protected _groupBy: string[];
protected _having: string[];
protected _orderBy: string[];
protected _skip: number | undefined;
protected _take: number | undefined;
protected _limit?: string;
copyInto(instance: SelectQuery<any>): SelectQuery<any>;
clone(): SelectQuery<Tables>;
groupBy(options: TemplateStringsArray | Fragment | GroupByBuilder | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
having(options: TemplateStringsArray | Fragment | HavingBuilder | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
orderBy(options: TemplateStringsArray | Fragment | OrderByBuilder | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
select(options: SelectOptions | TemplateStringsArray | string | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
get hasSelect(): boolean;
skip(rows?: number): this;
take(rows?: number): this;
limit(take?: number, skip?: number): this;
exists(): IntoFragment<Boolean>;
rowCount(): {
sql: string;
params: Record<string, any>;
into: NumberConstructor;
};
protected buildSelect(): string;
protected buildFrom(): string;
protected buildGroupBy(): string;
protected buildHaving(): string;
protected buildOrderBy(): string;
protected buildLimit(): string;
build(): {
sql: string;
params: Record<string, any>;
into: [
...Tables
][0] | undefined;
};
}
export declare class UpdateQuery<Tables extends Constructor<any>[]> extends WhereQuery<Tables> {
private _set;
set(options: TemplateStringsArray | Fragment | {
[K in keyof Partial<InstanceType<First<Tables>>>]: any;
} | ((...params: TypeRefs<Tables>) => Fragment), ...params: any[]): this;
get hasSet(): boolean;
buildUpdate(): string;
build(): {
sql: string;
params: Record<string, any>;
};
}
export declare class DeleteQuery<Tables extends Constructor<any>[]> extends WhereQuery<Tables> {

@@ -186,20 +411,82 @@ buildDelete(): string;

}
declare class Meta {
cls: ReflectMeta;
constructor(cls: ReflectMeta);
get name(): string;
get tableName(): string;
get type(): {
name: string;
table?: TableDefinition | undefined;
export declare class Sql {
static ops: {
[key: string]: string;
};
get table(): TableDefinition;
get props(): [
{
name: string;
column?: ColumnDefinition | undefined;
}
];
get columns(): ColumnDefinition[];
static opKeys: string[];
static create(dialect: Dialect): {
(strings: TemplateStringsArray | string, ...params: any[]): Fragment;
dialect: Dialect;
quote: (name: string) => string;
quoteColumn: (name: string) => string;
quoteTable: (name: string) => string;
ref<Table extends Constructor<any>>(cls: Table, as?: string): TypeRef<InstanceType<Table>>;
refs<T extends readonly Constructor[]>(...classes_0: T): ConstructorToTypeRef<T>;
fragment(sql: string | Fragment, params?: Record<string, any>): Fragment;
from<Table_1 extends Constructor<any>>(table: Table_1 | TypeRef<InstanceType<Table_1>>, alias?: string): SelectQuery<[
Table_1
]>;
update<Table_2 extends Constructor<any>>(table: Table_2): UpdateQuery<[
Table_2
]>;
deleteFrom<Table_3 extends Constructor<any>>(table: Table_3): DeleteQuery<[
Table_3
]>;
join<Tables extends Constructor<any>[]>(...tables: Tables): SqlJoinBuilder<Tables>;
groupBy<Tables_1 extends Constructor<any>[]>(...tables: Tables_1): SqlGroupByBuilder<Tables_1>;
having<Tables_2 extends Constructor<any>[]>(...tables: Tables_2): SqlHavingBuilder<Tables_2>;
orderBy<Tables_3 extends Constructor<any>[]>(...tables: Tables_3): SqlOrderByBuilder<Tables_3>;
idEquals<Table_4 extends {
id: number | string;
}>(id: number | string): (x: Table_4) => Fragment;
log(obj: any): void;
dump(obj: any[]): void;
};
}
declare class SqlJoinBuilder<Tables extends Constructor<any>[]> implements JoinBuilder<First<Tables>> {
$: ReturnType<typeof Sql.create>;
get table(): First<Tables>;
tables: Tables;
refs: ConstructorsToRefs<Tables>;
exprs: {
type: JoinType;
expr: ((refs: ConstructorsToRefs<Tables>) => Fragment);
}[];
params: Record<string, any>;
alias: string;
buildOn?: (refs: ConstructorsToRefs<Tables>, params: Record<string, any>) => string;
constructor($: ReturnType<typeof Sql.create>, ...tables: Tables);
join(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
leftJoin(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
rightJoin(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
fullJoin(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
crossJoin(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
add(type: JoinType, expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
as(alias: string): this;
build(refs: ConstructorsToRefs<Tables>): {
type: JoinType;
on: string;
params: Record<string, any>;
};
}
declare class SqlBuilderBase<Tables extends Constructor<any>[]> {
$: ReturnType<typeof Sql.create>;
tables: Tables;
params: Record<string, any>;
exprs: ((refs: ConstructorsToRefs<Tables>) => Fragment)[];
delimiter: string;
constructor($: ReturnType<typeof Sql.create>, ...tables: Tables);
add(expr: ((...args: ConstructorsToRefs<Tables>) => Fragment) | TemplateStringsArray, ...params: any[]): this;
build(refs: ConstructorsToRefs<Tables>): {
sql: string;
params: Record<string, any>;
};
}
declare class SqlGroupByBuilder<Tables extends Constructor<any>[]> extends SqlBuilderBase<Tables> implements GroupByBuilder {
}
declare class SqlOrderByBuilder<Tables extends Constructor<any>[]> extends SqlBuilderBase<Tables> implements OrderByBuilder {
}
declare class SqlHavingBuilder<Tables extends Constructor<any>[]> extends SqlBuilderBase<Tables> implements HavingBuilder {
constructor($: ReturnType<typeof Sql.create>, ...tables: Tables);
}
export type InsertOptions = {

@@ -216,248 +503,100 @@ /** only insert these props */

onlyWithValues?: boolean;
/** force update even with no where clause */
force?: boolean;
};
export type DeleteOptions = {
/** force delete even with no where clause */
force?: boolean;
type DeleteOptions$1 = {
where?: Fragment | Fragment[];
};
export declare class ConnectionBase {
export declare class DbConnection {
connection: Connection & {
$: ReturnType<typeof Sql.create>;
};
driver: Driver;
$: ReturnType<typeof Sql.create>;
constructor(driver: Driver);
schema: Schema;
constructor(connection: Connection & {
$: ReturnType<typeof Sql.create>;
});
get sync(): SyncDbConnection;
quote(symbol: string): string;
from<Table extends Constructor<any>>(table: Table): SelectQuery<[
Table
]>;
updateFor<Table extends Constructor<any>>(table: Table): UpdateQuery<[
Table
]>;
deleteFrom<Table extends Constructor<any>>(table: Table): DeleteQuery<[
Table
]>;
}
export declare class Connection extends ConnectionBase {
get sync(): SyncConnection;
quote(symbol: string): string;
insert<T extends ClassInstance>(row: T, options?: InsertOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
} | undefined>;
insertAll<T extends ClassInstance>(rows: T[], options?: InsertOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
} | null | undefined>;
listTables(): Promise<unknown[]>;
dropTable<Table extends ClassParam>(table: Table): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
createTable<Table extends ClassParam>(table: Table): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
insert<T extends ClassInstance>(row: T, options?: InsertOptions): Promise<Changes>;
insertAll<T extends ClassInstance>(rows: T[], options?: InsertOptions): Promise<Changes>;
listTables(): Promise<string[]>;
dropTable<Table extends ClassParam>(table: Table): Promise<Changes>;
createTable<Table extends ClassParam>(table: Table): Promise<Changes>;
all<ReturnType>(strings: TemplateStringsArray, ...params: any[]): Promise<ReturnType[]>;
single<ReturnType>(strings: TemplateStringsArray, ...params: any[]): Promise<ReturnType | null>;
}
export declare class SyncConnection extends ConnectionBase {
insert<T extends ClassInstance>(row: T, options?: InsertOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}> | undefined;
insertAll<T extends ClassInstance>(rows: T[], options?: InsertOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}> | null | undefined;
update<T extends ClassInstance>(row: T, options?: UpdateOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}> | undefined;
delete<T extends ClassInstance>(row: T, options?: DeleteOptions): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}> | undefined;
listTables(): unknown[];
dropTable<Table extends ClassParam>(table: Table): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
createTable<Table extends ClassParam>(table: Table): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
createStatment<T>(strings: TemplateStringsArray | SqlBuilder, ...params: any[]): [
one<ReturnType>(strings: TemplateStringsArray, ...params: any[]): Promise<Awaited<ReturnType> | null>;
column<ReturnValue>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<ReturnValue[]>;
value<ReturnValue>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<unknown>;
arrays(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<any[][]>;
array(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<any[] | null>;
exec(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<Changes>;
run(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Promise<void>;
prepare<T>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): [
Statement<T, DbBinding[]> | Statement<T, any>,
any[] | Record<string, any>
];
all<ReturnType>(strings: TemplateStringsArray | SqlBuilder, ...params: any[]): ReturnType[];
single<ReturnType>(strings: TemplateStringsArray | SqlBuilder, ...params: any[]): ReturnType | null;
column<ReturnValue>(strings: TemplateStringsArray | SqlBuilder, ...params: any[]): unknown[];
scalar<ReturnValue>(strings: TemplateStringsArray | SqlBuilder, ...params: any[]): unknown;
exec(sql: string | SqlBuilder, params: Record<string, any>): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
}
export declare class NamingStrategy {
tableName(table: string): string;
columnName(column: string): string;
tableFromDef(def: TableDefinition): string;
}
export type ConstructorsToRefs<T extends Constructor<any>[]> = {
[K in keyof T]: TypeRef<InstanceType<T[K]>>;
};
export type First<T extends readonly any[]> = T extends [
infer F,
...any[]
] ? F extends Constructor<any> ? F : never : never;
export type Last<T extends readonly any[]> = T extends [
...any[],
infer L
] ? L extends Constructor<any> ? L : never : never;
export type ScalarValue = string | bigint | number | boolean | null | symbol;
export type DbBinding = string | bigint | NodeJS.TypedArray | number | boolean | null | Record<string, string | bigint | NodeJS.TypedArray | number | boolean | null>;
export interface ReflectMeta {
name: string;
$id: symbol;
$type: {
name: string;
table?: TableDefinition;
export declare class SyncDbConnection {
connection: SyncConnection & {
$: ReturnType<typeof Sql.create>;
};
$props: [
{
name: string;
column?: ColumnDefinition;
}
driver: Driver;
$: ReturnType<typeof Sql.create>;
schema: Schema;
constructor(connection: SyncConnection & {
$: ReturnType<typeof Sql.create>;
});
quote(symbol: string): string;
insert<T extends ClassInstance>(row: T, options?: InsertOptions): Changes;
insertAll<T extends ClassInstance>(rows: T[], options?: InsertOptions): Changes;
update<T extends ClassInstance>(row: T, options?: UpdateOptions): Changes;
delete<T extends ClassInstance>(row: T, options?: DeleteOptions$1): Changes;
listTables(): string[];
dropTable<Table extends ClassParam>(table: Table): Changes;
createTable<Table extends ClassParam>(table: Table): Changes;
prepareSync<T>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): [
SyncStatement<T, DbBinding[]> | SyncStatement<T, any>,
any[] | Record<string, any>,
T | undefined
];
all<ReturnType>(strings: TemplateStringsArray | SqlBuilder | Fragment | IntoFragment<ReturnType>, ...params: any[]): ReturnType[];
one<ReturnType>(strings: TemplateStringsArray | SqlBuilder | Fragment | IntoFragment<ReturnType>, ...params: any[]): ReturnType | null;
column<ReturnValue>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): ReturnValue[];
value<ReturnValue>(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): unknown;
arrays(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): any[][];
array(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): any[] | null;
exec(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): Changes;
run(strings: TemplateStringsArray | SqlBuilder | Fragment, ...params: any[]): void;
}
export type ColumnType = "INTEGER" | "SMALLINT" | "BIGINT" | "DECIMAL" | "NUMERIC" | "REAL" | "FLOAT" | "DOUBLE" | "MONEY" | "DATE" | "DATETIME" | "TIME" | "TIMEZ" | "TIMESTAMP" | "TIMESTAMPZ" | "INTERVAL" | "BOOLEAN" | "UUID" | "BLOB" | "BYTES" | "BIT" | "TEXT" | "VARCHAR" | "NVARCHAR" | "CHAR" | "NCHAR" | "JSON" | "JSONB" | "XML";
export type Constructor<T = any> = new (...args: any[]) => T;
export type ClassParam = ReflectMeta | {
constructor: ReflectMeta;
} | Constructor<any>;
export type ClassInstance = {
constructor: ReflectMeta;
} & Record<string, any> | Record<string, any>;
export interface TableDefinition {
name: string;
alias?: string;
}
export interface ColumnDefinition {
name: string;
alias?: string;
type: string;
primaryKey?: boolean;
autoIncrement?: boolean;
required?: boolean;
precision?: number;
scale?: number;
unique?: boolean;
index?: boolean;
defaultValue?: string;
}
export interface Statement<ReturnType, ParamsType extends DbBinding[]> {
get native(): any;
all(...params: ParamsType): Promise<ReturnType[]>;
allSync(...params: ParamsType): ReturnType[];
first(...params: ParamsType): Promise<ReturnType | null>;
firstSync(...params: ParamsType): ReturnType | null;
column<ReturnValue>(...params: ParamsType): Promise<ReturnValue[]>;
columnSync<ReturnValue>(...params: ParamsType): ReturnValue[];
scalar<ReturnValue>(...params: ParamsType): Promise<ReturnValue | null>;
scalarSync<ReturnValue>(...params: ParamsType): ReturnValue | null;
arrays(...params: ParamsType): Promise<any[][]>;
arraysSync(...params: ParamsType): any[][];
array(...params: ParamsType): Promise<any[] | null>;
arraySync(...params: ParamsType): any[] | null;
exec(...params: ParamsType): Promise<{
changes: number;
lastInsertRowid: number | bigint;
}>;
execSync(...params: ParamsType): {
changes: number;
lastInsertRowid: number | bigint;
declare class ConnectionBase {
driver: Driver & {
$: ReturnType<typeof Sql.create>;
};
}
export interface TypeConverter {
toDb(value: any): any;
fromDb(value: any): any;
}
export interface Driver {
get $(): any;
get name(): string;
get async(): Connection;
get sync(): SyncConnection | undefined;
get converters(): {
[key: string]: TypeConverter;
};
quote(name: string): string;
quoteTable(name: string): string;
quoteColumn(name: string): string;
sqlColumnDefinition(column: ColumnDefinition): string;
sqlIndexDefinition(table: TableDefinition, column: ColumnDefinition): string;
sqlTableNames(schema?: string): string;
sqlLimit(skip?: number, take?: number): string;
prepareRaw<ReturnType, ParamsType extends DbBinding[]>(sql: String): Statement<ReturnType, ParamsType extends any[] ? ParamsType : [
$: ReturnType<typeof Sql.create>;
async: DbConnection;
sync: SyncDbConnection;
schema: Schema;
dialect: Dialect;
constructor(driver: Driver & {
$: ReturnType<typeof Sql.create>;
});
prepare<ReturnType, ParamsType extends DbBinding[]>(sql: TemplateStringsArray | string, ...params: DbBinding[]): Statement<ReturnType, ParamsType extends any[] ? ParamsType : [
ParamsType
]>;
prepare<ReturnType, ParamsType extends DbBinding[]>(strings: TemplateStringsArray, ...params: DbBinding[]): Statement<ReturnType, ParamsType extends any[] ? ParamsType : [
prepareSync<ReturnType, ParamsType extends DbBinding[]>(sql: TemplateStringsArray | string, ...params: DbBinding[]): SyncStatement<ReturnType, ParamsType extends any[] ? ParamsType : [
ParamsType
]>;
}
export type Fragment = {
sql: string;
params?: Record<string, any>;
};
export interface SqlBuilder {
build(): {
sql: string;
params: Record<string, any>;
};
export declare class DefaultStrategy implements NamingStrategy {
tableName(table: string): string;
columnName(column: string): string;
tableFromDef(def: TableDefinition): string;
}
export type WhereOptions = {
equals?: Record<string, ScalarValue>;
notEquals?: Record<string, ScalarValue>;
like?: Record<string, ScalarValue>;
notLike?: Record<string, ScalarValue>;
startsWith?: Record<string, ScalarValue>;
endsWith?: Record<string, ScalarValue>;
contains?: Record<string, ScalarValue>;
in?: Record<string, ScalarValue[]>;
notIn?: Record<string, ScalarValue[]>;
isNull?: string[];
notNull?: string[];
op?: [
string,
Record<string, any>
];
sql?: Fragment | Fragment[];
rawSql?: string | string[];
params?: Record<string, any>;
export declare class SnakeCaseStrategy implements NamingStrategy {
tableName(table: string): string;
columnName(column: string): string;
tableFromDef(def: TableDefinition): string;
}
export declare function useFilter(db: SyncDbConnection, filter: (sql: TemplateStringsArray | string, params: DbBinding[]) => void): {
release: () => void;
};
export type TypeRef<T> = T & {
$ref: {
cls: Constructor<T>;
as?: string;
};
};
export type ConstructorToTypeRef<T extends readonly any[]> = {
[K in keyof T]: T[K] extends new (...args: any[]) => infer R ? TypeRef<R> : never;
};
export type JoinType = "JOIN" | "INNER JOIN" | "LEFT JOIN" | "RIGHT JOIN" | "OUTER JOIN" | "FULL JOIN" | "CROSS JOIN";
export type TypeRefs<Tables extends Constructor<any>[]> = {
[K in keyof Tables]: TypeRef<InstanceType<Tables[K]>>;
};
export type JoinDefinition = {
type: JoinType;
table: string;
on?: string;
as?: string;
params?: Record<string, any>;
};
export interface JoinBuilder<Table extends Constructor<any>> {
get table(): Table;
get tables(): Constructor<any>[];
build(refs: ConstructorsToRefs<any>, type: JoinType): JoinDefinition;
}
export declare class Inspect {

@@ -469,2 +608,9 @@ static dump(obj: any): string;

}
export declare function pick<T extends Record<string, any> | Record<string, any>[]>(input: T, keys: string[]): T extends Record<string, any>[] ? Record<string, any>[] : Record<string, any>;
export declare function omit<T extends Record<string, any> | Record<string, any>[]>(input: T, keys: string[]): T extends Record<string, any>[] ? Record<string, any>[] : Record<string, any>;
export declare function toStr(value: any): string;
export declare function nextParam(params: Record<string, any>): string;
export declare function mergeParams(params: Record<string, any>, f: Fragment): string;
export declare function isTemplateStrings(arg: any): arg is TemplateStringsArray;
export declare function snakeCase(s: string): string;
export declare function converterFor(converter: TypeConverter, ...dataTypes: string[]): {

@@ -492,6 +638,6 @@ [key: string]: TypeConverter;

}): (target: any, propertyKey: string) => void;
export declare function Table<T extends Constructor<any>>(cls: new () => T, definition: TableDefinition$1<T>): new () => T;
interface TableDefinition$1<T> {
export declare function Table<T extends Constructor<any>>(cls: T, definition: TableDefinition$1<T>): T;
interface TableDefinition$1<T extends Constructor<any>> {
table?: TableConfig;
columns: ColumnsConfig<T>;
columns: ColumnsConfig<InstanceType<T>>;
}

@@ -554,3 +700,177 @@ export interface TableConfig {

};
export declare class Sqlite implements Driver {
static connection: ConnectionBase;
static driver: Driver;
static schema: Schema;
static init(): SqliteConnection;
name: string;
dialect: Dialect;
schema: Schema;
strategy: NamingStrategy;
$: ReturnType<typeof Sql.create>;
variables: {
[key: string]: string;
};
types: DialectTypes;
converters: {
[key: string]: TypeConverter;
};
constructor();
}
declare class SqliteConnection extends ConnectionBase {
}
export declare class SqliteDialect implements Dialect {
$: ReturnType<typeof Sql.create>;
strategy: DefaultStrategy;
constructor();
quote(name: string): string;
quoteTable(name: string): string;
quoteColumn(name: string): string;
sqlLimit(offset?: number, limit?: number): Fragment;
}
export declare class MySql extends Sqlite {
static connection: ConnectionBase;
static driver: Driver;
static schema: Schema;
static init(): MySqlConnection;
constructor();
}
declare class MySqlConnection extends ConnectionBase {
}
export declare class MySqlDialect implements Dialect {
$: ReturnType<typeof Sql.create>;
strategy: DefaultStrategy;
constructor();
quote(name: string): string;
quoteTable(name: string): string;
quoteColumn(name: string): string;
sqlLimit(offset?: number, limit?: number): Fragment;
}
export declare class PostgreSql extends Sqlite {
static connection: ConnectionBase;
static driver: Driver;
static schema: Schema;
static init(): PostgreSqlConnection;
constructor();
}
declare class PostgreSqlConnection extends ConnectionBase {
}
export declare class PostgreSqlDialect implements Dialect {
$: ReturnType<typeof Sql.create>;
strategy: DefaultStrategy;
constructor();
quote(name: string): string;
quoteTable(name: string): string;
quoteColumn(name: string): string;
sqlLimit(offset?: number, limit?: number): Fragment;
}
export declare class SqliteSchema extends Schema {
driver: Driver & {
$: ReturnType<typeof Sql.create>;
types: DialectTypes;
variables: {
[key: string]: string;
};
};
constructor(driver: Driver & {
$: ReturnType<typeof Sql.create>;
types: DialectTypes;
variables: {
[key: string]: string;
};
});
sqlTableNames(): string;
sqlIndexDefinition(table: TableDefinition, column: ColumnDefinition): string;
sqlColumnDefinition(column: ColumnDefinition): string;
sqlLimit(offset?: number, limit?: number): Fragment;
}
export declare class MySqlSchema extends SqliteSchema {
}
export declare class PostgreSqlSchema extends SqliteSchema {
}
export declare const sqlite: {
(strings: string | TemplateStringsArray, ...params: any[]): Fragment;
dialect: Dialect;
quote: (name: string) => string;
quoteColumn: (name: string) => string;
quoteTable: (name: string) => string;
ref<Table extends Constructor<any>>(cls: Table, as?: string | undefined): TypeRef<InstanceType<Table>>;
refs<T extends readonly Constructor[]>(...classes_0: T): ConstructorToTypeRef<T>;
fragment(sql: string | Fragment, params?: Record<string, any>): Fragment;
from<Table_1 extends Constructor<any>>(table: Table_1 | TypeRef<InstanceType<Table_1>>, alias?: string | undefined): SelectQuery<[
Table_1
]>;
update<Table_2 extends Constructor<any>>(table: Table_2): UpdateQuery<[
Table_2
]>;
deleteFrom<Table_3 extends Constructor<any>>(table: Table_3): DeleteQuery<[
Table_3
]>;
join<Tables extends Constructor<any>[]>(...tables: Tables): SqlJoinBuilder<Tables>;
groupBy<Tables_1 extends Constructor<any>[]>(...tables: Tables_1): SqlGroupByBuilder<Tables_1>;
having<Tables_2 extends Constructor<any>[]>(...tables: Tables_2): SqlHavingBuilder<Tables_2>;
orderBy<Tables_3 extends Constructor<any>[]>(...tables: Tables_3): SqlOrderByBuilder<Tables_3>;
idEquals<Table_4 extends {
id: string | number;
}>(id: string | number): (x: Table_4) => Fragment;
log(obj: any): void;
dump(obj: any[]): void;
};
export declare const mysql: {
(strings: string | TemplateStringsArray, ...params: any[]): Fragment;
dialect: Dialect;
quote: (name: string) => string;
quoteColumn: (name: string) => string;
quoteTable: (name: string) => string;
ref<Table extends Constructor<any>>(cls: Table, as?: string | undefined): TypeRef<InstanceType<Table>>;
refs<T extends readonly Constructor[]>(...classes_0: T): ConstructorToTypeRef<T>;
fragment(sql: string | Fragment, params?: Record<string, any>): Fragment;
from<Table_1 extends Constructor<any>>(table: Table_1 | TypeRef<InstanceType<Table_1>>, alias?: string | undefined): SelectQuery<[
Table_1
]>;
update<Table_2 extends Constructor<any>>(table: Table_2): UpdateQuery<[
Table_2
]>;
deleteFrom<Table_3 extends Constructor<any>>(table: Table_3): DeleteQuery<[
Table_3
]>;
join<Tables extends Constructor<any>[]>(...tables: Tables): SqlJoinBuilder<Tables>;
groupBy<Tables_1 extends Constructor<any>[]>(...tables: Tables_1): SqlGroupByBuilder<Tables_1>;
having<Tables_2 extends Constructor<any>[]>(...tables: Tables_2): SqlHavingBuilder<Tables_2>;
orderBy<Tables_3 extends Constructor<any>[]>(...tables: Tables_3): SqlOrderByBuilder<Tables_3>;
idEquals<Table_4 extends {
id: string | number;
}>(id: string | number): (x: Table_4) => Fragment;
log(obj: any): void;
dump(obj: any[]): void;
};
export declare const postgres: {
(strings: string | TemplateStringsArray, ...params: any[]): Fragment;
dialect: Dialect;
quote: (name: string) => string;
quoteColumn: (name: string) => string;
quoteTable: (name: string) => string;
ref<Table extends Constructor<any>>(cls: Table, as?: string | undefined): TypeRef<InstanceType<Table>>;
refs<T extends readonly Constructor[]>(...classes_0: T): ConstructorToTypeRef<T>;
fragment(sql: string | Fragment, params?: Record<string, any>): Fragment;
from<Table_1 extends Constructor<any>>(table: Table_1 | TypeRef<InstanceType<Table_1>>, alias?: string | undefined): SelectQuery<[
Table_1
]>;
update<Table_2 extends Constructor<any>>(table: Table_2): UpdateQuery<[
Table_2
]>;
deleteFrom<Table_3 extends Constructor<any>>(table: Table_3): DeleteQuery<[
Table_3
]>;
join<Tables extends Constructor<any>[]>(...tables: Tables): SqlJoinBuilder<Tables>;
groupBy<Tables_1 extends Constructor<any>[]>(...tables: Tables_1): SqlGroupByBuilder<Tables_1>;
having<Tables_2 extends Constructor<any>[]>(...tables: Tables_2): SqlHavingBuilder<Tables_2>;
orderBy<Tables_3 extends Constructor<any>[]>(...tables: Tables_3): SqlOrderByBuilder<Tables_3>;
idEquals<Table_4 extends {
id: string | number;
}>(id: string | number): (x: Table_4) => Fragment;
log(obj: any): void;
dump(obj: any[]): void;
};
export {};

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

// src/query.ts
// src/utils.ts
function isDate(d) {
return d && Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d);
}
function toDate(s) {
return !s ? null : isDate(s) ? s : s[0] == "/" ? new Date(parseFloat(/Date\(([^)]+)\)/.exec(s)[1])) : new Date(s);
}
function propsWithValues(obj) {
return Object.keys(obj).filter((k) => obj[k] != null);
}
function uniqueKeys(rows) {
let to = [];
rows.forEach((o) => Object.keys(o).forEach((k) => {
if (to.indexOf(k) === -1) {
to.push(k);
}
}));
return to;
}
function pick(input, keys) {
if (Array.isArray(input)) {
return input.map((item) => keys.reduce((obj, key) => ({
...obj,
[key]: item[key]
}), {}));
}
return keys.reduce((obj, key) => ({
...obj,
[key]: input[key]
}), {});
}
function omit(input, keys) {
if (Array.isArray(input)) {
return input.map((item) => {
const result2 = { ...item };
keys.forEach((key) => delete result2[key]);
return result2;
});
}
const result = { ...input };
keys.forEach((key) => delete result[key]);
return result;
}
function leftPart(s, needle) {
if (s == null)
return null;
let pos = s.indexOf(needle);
return pos == -1 ? s : s.substring(0, pos);
}
function toStr(value) {
return typeof value == "symbol" ? `:${value.description ?? ""}` : `${value}`;
}
function nextParam(params) {
const positionalParams = Object.keys(params).map((x) => x[0] === "_" ? parseInt(x.substring(1)) : NaN).filter((x) => !isNaN(x));
return "_" + (positionalParams.length == 0 ? 1 : Math.max(...positionalParams) + 1);
}
function mergeParams(params, f) {
let sql = f.sql;
if (f.params && typeof f.params == "object") {
for (const [key, value] of Object.entries(f.params)) {
const exists = key in params && key[0] === "_" && !isNaN(parseInt(key.substring(1)));
if (exists) {
const nextvalue = nextParam(params);
sql = sql.replaceAll(`\$${key}`, `\$${nextvalue}`);
params[nextvalue] = value;
} else {
params[key] = value;
}
}
}
return sql;
}
function asType(cls) {
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
const ref = cls.$ref ? cls : undefined;
return !cls?.$ref && cls.tables ? cls.table : ref ? ref.$ref.cls : cls;
}
function asRef(cls) {
return typeof cls == "object" && cls.$ref ? cls : undefined;
}
function isTemplateStrings(arg) {
return Array.isArray(arg) && "raw" in arg;
}
function snakeCase(s) {
return (s || "").replace(/([a-z])([A-Z])/g, "$1_$2").toLowerCase();
}
// src/meta.ts
class Meta {
cls;
static metadata = {};
constructor(cls) {
this.cls = cls;
if (!cls)
throw new Error(`Class must be provided`);
if (!cls.$type)
throw new Error(`Class ${cls.name ?? cls} have a \$type property`);
}
static assertClass(table) {
if (!table)
throw new Error(`Class must be provided`);
const cls = table?.constructor?.$id ? table?.constructor : table.$id ? table : null;
if (!cls) {
const name = table?.name ?? table?.constructor?.name;
if (!name)
throw new Error(`Class or constructor function required`);
else if (typeof table === "function" || typeof table.constructor === "function")
throw new Error(`${name} is not a class or constructor function`);
else
throw new Error(`${name} does not contain metadata, missing @table?`);
}
return cls;
}
static assertTable(table) {
const cls = Meta.assertClass(table);
if (!cls.$type?.table) {
throw new Error(`${cls.name} does not have a @table annotation`);
}
if (!cls.$props || !cls.$props.find((x) => x.column)) {
throw new Error(`${cls.name} does not have any @column annotations`);
}
return cls;
}
static assertMeta(table) {
const cls = Meta.assertClass(table);
const id = cls.$id;
return Meta.metadata[id] ?? (Meta.metadata[id] = new Meta(Meta.assertTable(cls)));
}
get name() {
return this.cls.$type?.name ?? this.cls.name;
}
get tableName() {
const cls = this.cls;
const ret = cls.$type?.table?.alias ?? cls.$type?.name ?? cls.name;
if (!ret)
throw new Error(`Table name not found for ${cls.name}`);
return ret;
}
get type() {
return this.cls.$type;
}
get table() {
const ret = this.type.table;
if (!ret)
throw new Error(`Table definition not found for ${this.cls.name}`);
return ret;
}
get props() {
return this.cls.$props ?? [];
}
get columns() {
return this.props.filter((x) => x.column).map((x) => x.column);
}
}
// src/converters.ts
function converterFor(converter, ...dataTypes) {
const to = {};
for (const dataType of dataTypes) {
to[dataType] = converter;
}
return to;
}
class DateTimeConverter {
static instance = new DateTimeConverter;
toDb(value) {
const d = toDate(value);
return d ? d.toISOString() : null;
}
fromDb(value) {
if (!value)
return null;
return toDate(value);
}
}
// src/schema.ts
var DriverRequired = `Missing Driver Implementation, see: https://github.com/litdb/litdb`;
var DriverRequiredProxy = new Proxy({}, {
get: (target, key) => {
throw new Error(DriverRequired);
}
});
function assertSql(sql) {
if (typeof sql != "object" || !sql.sql) {
const desc = typeof sql == "symbol" ? sql.description : Array.isArray(sql) ? "Array" : `${sql}`;
throw new Error(`Expected ${"sql`...`"} fragment, received: ${desc}`);
}
return sql;
}
class Schema {
dialect;
constructor(dialect) {
this.dialect = dialect;
}
converters = {
...converterFor(DateTimeConverter.instance, "DATE", "DATETIME", "TIMESTAMP", "TIMESTAMPZ")
};
sqlTableNames(schema) {
throw new Error(DriverRequired);
}
sqlColumnDefinition(column) {
throw new Error(DriverRequired);
}
sqlIndexDefinition(table, column) {
throw new Error(DriverRequired);
}
dropTable(table) {
const meta = Meta.assertMeta(table);
let sql = `DROP TABLE IF EXISTS ${this.dialect.quoteTable(meta.tableName)}`;
return sql;
}
createTable(table) {
const meta = Meta.assertMeta(table);
const columns = meta.columns;
let sqlColumns = columns.map((c) => `${this.sqlColumnDefinition(c)}`).join(",\n ");
let sql = `CREATE TABLE ${this.dialect.quoteTable(meta.tableName)} (\n ${sqlColumns}\n);\n`;
const indexes = columns.filter((c) => c.index).map((c) => `${this.sqlIndexDefinition(meta.table, c)};`);
if (indexes.length > 0) {
sql += indexes.join("\n");
}
return sql;
}
insert(table, options) {
const meta = Meta.assertMeta(table);
let props = meta.props.filter((x) => x.column);
if (options?.onlyProps) {
props = props.filter((c) => options.onlyProps.includes(c.name));
}
let columns = props.map((x) => x.column).filter((c) => !c.autoIncrement);
let sqlColumns = columns.map((c) => `${this.dialect.quoteColumn(c.name)}`).join(", ");
let sqlParams = columns.map((c) => `\$${c.name}`).join(", ");
let sql = `INSERT INTO ${this.dialect.quoteTable(meta.tableName)} (${sqlColumns}) VALUES (${sqlParams})`;
return sql;
}
update(table, options) {
const meta = Meta.assertMeta(table);
let props = meta.props.filter((x) => x.column);
if (options?.onlyProps) {
props = props.filter((c) => options.onlyProps.includes(c.name) || c.column?.primaryKey);
}
const columns = props.map((x) => x.column);
const setColumns = columns.filter((c) => !c.primaryKey);
const whereColumns = columns.filter((c) => c.primaryKey);
const setSql = setColumns.map((c) => `${this.dialect.quoteColumn(c.name)}=\$${c.name}`).join(", ");
const whereSql = whereColumns.map((c) => `${this.dialect.quoteColumn(c.name)} = \$${c.name}`).join(" AND ");
let sql = `UPDATE ${this.dialect.quoteTable(meta.tableName)} SET ${setSql}`;
if (whereSql) {
sql += ` WHERE ${whereSql}`;
} else {
throw new Error(`No WHERE clause exists for UPDATE ${meta.tableName}`);
}
return sql;
}
delete(table, options) {
const meta = Meta.assertMeta(table);
let props = meta.props.filter((x) => x.column);
const columns = props.map((x) => x.column);
const whereColumns = columns.filter((c) => c.primaryKey);
let whereSql = whereColumns.map((c) => `${this.dialect.quoteColumn(c.name)} = \$${c.name}`).join(" AND ");
if (options?.where) {
let sql2 = whereSql ? " AND " : " WHERE ";
const where = Array.isArray(options.where) ? options.where : [options.where];
whereSql += sql2 + where.join(" AND ");
}
let sql = `DELETE FROM ${this.dialect.quoteTable(meta.tableName)}`;
if (whereSql) {
sql += ` WHERE ${whereSql}`;
} else {
throw new Error(`No WHERE clause exists for DELETE ${meta.tableName}`);
}
return sql;
}
toDbBindings(table) {
const values = [];
const meta = Meta.assertMeta(table.constructor);
const props = meta.props.filter((x) => x.column);
props.forEach((x) => {
const value = table[x.column.name];
const converter = this.converters[x.column.type];
if (converter) {
const dbValue = converter.toDb(value);
values.push(dbValue);
} else {
values.push(value);
}
});
return values;
}
toDbObject(table, options) {
const values = {};
const meta = Meta.assertMeta(table.constructor);
const props = meta.props.filter((x) => x.column);
for (const x of props) {
if (options?.onlyProps && !options.onlyProps.includes(x.name))
continue;
const value = table[x.name];
const converter = this.converters[x.column.type];
if (converter) {
const dbValue = converter.toDb(value);
values[x.column.name] = dbValue;
} else {
values[x.column.name] = value;
}
}
return values;
}
}
// src/connection.ts
class DbConnection {
connection;
driver;
$;
schema;
constructor(connection) {
this.connection = connection;
this.$ = connection.$;
this.driver = connection.driver;
this.schema = connection.driver.schema;
}
get sync() {
if (this.driver.sync == null) {
throw new Error(`${this.$.name} does not support sync APIs`);
}
return this.driver.sync;
}
quote(symbol) {
return this.$.quote(symbol);
}
insert(row, options) {
return Promise.resolve(this.sync.insert(row, options));
}
insertAll(rows, options) {
return Promise.resolve(this.sync.insertAll(rows, options));
}
listTables() {
return Promise.resolve(this.sync.listTables());
}
dropTable(table) {
return Promise.resolve(this.sync.dropTable(table));
}
createTable(table) {
return Promise.resolve(this.sync.createTable(table));
}
all(strings, ...params) {
return Promise.resolve(this.sync.all(strings, ...params));
}
one(strings, ...params) {
return Promise.resolve(this.sync.one(strings, ...params));
}
column(strings, ...params) {
return Promise.resolve(this.sync.column(strings, ...params));
}
value(strings, ...params) {
return Promise.resolve(this.sync.value(strings, ...params));
}
arrays(strings, ...params) {
return Promise.resolve(this.sync.arrays(strings, ...params));
}
array(strings, ...params) {
return Promise.resolve(this.sync.array(strings, ...params));
}
exec(strings, ...params) {
return Promise.resolve(this.sync.exec(strings, ...params));
}
run(strings, ...params) {
return Promise.resolve(this.sync.run(strings, ...params));
}
prepare(strings, ...params) {
if (isTemplateStrings(strings)) {
let stmt = this.connection.prepare(strings, ...params);
return [stmt, params];
} else if (typeof strings == "object") {
if ("build" in strings) {
let query = strings.build();
let stmt = this.connection.prepare(query.sql);
return [stmt, query.params];
} else if ("sql" in strings) {
let stmt = this.connection.prepare(strings.sql);
return [stmt, strings.params ?? {}];
}
}
throw new Error(`Invalid argument: ${toStr(strings)}`);
}
}
class SyncDbConnection {
connection;
driver;
$;
schema;
constructor(connection) {
this.connection = connection;
this.$ = connection.$;
this.driver = connection.driver;
this.schema = connection.driver.schema;
}
quote(symbol) {
return this.$.quote(symbol);
}
insert(row, options) {
const ret = { changes: 0, lastInsertRowid: 0 };
if (!row)
return ret;
const cls = row.constructor;
if (options?.onlyProps || options?.onlyWithValues) {
const onlyProps = options?.onlyProps ?? propsWithValues(row);
const onlyOptions = { onlyProps };
let stmt = this.connection.prepareSync(this.schema.insert(cls, onlyOptions));
const dbRow = this.schema.toDbObject(row, onlyOptions);
return stmt.execSync(dbRow);
} else {
let stmt = this.connection.prepareSync(this.schema.insert(cls));
const dbRow = this.schema.toDbObject(row);
return stmt.execSync(dbRow);
}
}
insertAll(rows, options) {
const ret = { changes: 0, lastInsertRowid: 0 };
if (rows.length == 0)
return ret;
const cls = rows[0].constructor;
if (options?.onlyProps || options?.onlyWithValues) {
for (const row of rows) {
const last = this.insert(row, options);
ret.changes += last.changes;
ret.lastInsertRowid = last.lastInsertRowid;
}
} else {
let last = null;
let stmt = this.connection.prepareSync(this.schema.insert(cls));
for (const row of rows) {
const dbRow = this.schema.toDbObject(row);
last = stmt.execSync(dbRow);
ret.changes += last.changes;
ret.lastInsertRowid = last.lastInsertRowid;
}
}
return ret;
}
update(row, options) {
const ret = { changes: 0, lastInsertRowid: 0 };
if (!row)
return ret;
const cls = row.constructor;
if (options?.onlyProps || options?.onlyWithValues) {
const pkNames = cls.$props.filter((x) => x.column?.primaryKey).map((x) => x.column.name);
const onlyProps = Array.from(new Set([...options?.onlyProps ?? propsWithValues(row), ...pkNames]));
const onlyOptions = { onlyProps };
let stmt = this.connection.prepareSync(this.schema.update(cls, onlyOptions));
const dbRow = this.schema.toDbObject(row, onlyOptions);
return stmt.execSync(dbRow);
} else {
let stmt = this.connection.prepareSync(this.schema.update(cls));
const dbRow = this.schema.toDbObject(row);
return stmt.execSync(dbRow);
}
}
delete(row, options) {
const ret = { changes: 0, lastInsertRowid: 0 };
if (!row)
return ret;
const cls = row.constructor;
let stmt = this.connection.prepareSync(this.schema.delete(cls, options));
const meta = Meta.assertMeta(cls);
const pkColumns = meta.props.filter((p) => p.column?.primaryKey);
const onlyProps = pkColumns.map((p) => p.name);
const dbRow = this.schema.toDbObject(row, { onlyProps });
return stmt.execSync(dbRow);
}
listTables() {
return this.column({ sql: this.schema.sqlTableNames(), params: {} });
}
dropTable(table) {
let stmt = this.connection.prepareSync(this.schema.dropTable(table));
return stmt.execSync();
}
createTable(table) {
let stmt = this.connection.prepareSync(this.schema.createTable(table));
return stmt.execSync();
}
prepareSync(strings, ...params) {
if (isTemplateStrings(strings)) {
let stmt = this.connection.prepareSync(strings, ...params);
return [stmt, params, undefined];
} else if (typeof strings == "object") {
if ("build" in strings) {
let query = strings.build();
let stmt = this.connection.prepareSync(query.sql);
return [stmt, query.params ?? {}, query.into];
} else if ("sql" in strings) {
let sql = strings.sql;
let params2 = strings.params ?? {};
let stmt = this.connection.prepareSync(sql);
return [stmt, params2, strings.into];
}
}
throw new Error(`Invalid argument: ${toStr(strings)}`);
}
all(strings, ...params) {
const [stmt, p, into] = this.prepareSync(strings, ...params);
if (into) {
const use = stmt.as(into);
return Array.isArray(p) ? use.allSync(...p) : use.allSync(p);
} else {
return Array.isArray(p) ? stmt.allSync(...p) : stmt.allSync(p);
}
}
one(strings, ...params) {
const [stmt, p, into] = this.prepareSync(strings, ...params);
if (into) {
const use = stmt.as(into);
return Array.isArray(p) ? use.oneSync(...p) : use.oneSync(p);
} else {
return Array.isArray(p) ? stmt.oneSync(...p) : stmt.oneSync(p);
}
}
column(strings, ...params) {
const [stmt, p] = this.prepareSync(strings, ...params);
return Array.isArray(p) ? stmt.arraysSync(...p).map((x) => x[0]) : stmt.arraysSync(p).map((x) => x[0]);
}
value(strings, ...params) {
const [stmt, p, into] = this.prepareSync(strings, ...params);
const value = Array.isArray(p) ? stmt.valueSync(...p) : stmt.valueSync(p);
if (into) {
if (into === Boolean) {
return !!value;
}
}
return value;
}
arrays(strings, ...params) {
const [stmt, p] = this.prepareSync(strings, ...params);
return Array.isArray(p) ? stmt.arraysSync(...p) : stmt.arraysSync(p);
}
array(strings, ...params) {
const [stmt, p] = this.prepareSync(strings, ...params);
return Array.isArray(p) ? stmt.arraySync(...p) : stmt.arraySync(p);
}
exec(strings, ...params) {
const [stmt, p] = this.prepareSync(strings, ...params);
return Array.isArray(p) ? stmt.execSync(...p) : stmt.execSync(p);
}
run(strings, ...params) {
const [stmt, p] = this.prepareSync(strings, ...params);
if (Array.isArray(p)) {
stmt.runSync(...p);
} else {
stmt.runSync(p);
}
}
}
class ConnectionBase {
driver;
$;
async;
sync;
schema;
dialect;
constructor(driver) {
this.driver = driver;
this.$ = driver.$;
this.schema = driver.schema;
this.dialect = driver.dialect;
this.async = new DbConnection(this);
this.sync = new SyncDbConnection(this);
}
prepare(sql, ...params) {
throw new Error(DriverRequired);
}
prepareSync(sql, ...params) {
throw new Error(DriverRequired);
}
}
class DefaultStrategy {
tableName(table) {
return table;
}
columnName(column) {
return column;
}
tableFromDef(def) {
return def.alias ?? def.name;
}
}
class SnakeCaseStrategy {
tableName(table) {
return snakeCase(table);
}
columnName(column) {
return snakeCase(column);
}
tableFromDef(def) {
return snakeCase(def.alias ?? def.name);
}
}
class FilterConnection {
db;
fn;
$;
orig;
constructor(db, fn) {
this.db = db;
this.fn = fn;
this.orig = db.connection;
db.connection = this;
this.$ = db.$;
}
get driver() {
return this.db.driver;
}
prepareSync(sql, ...params) {
this.fn(sql, params);
return this.orig.prepareSync(sql, ...params);
}
release() {
this.db.connection = this.orig;
}
}
function useFilter(db, filter) {
return new FilterConnection(db, filter);
}
// src/inspect.ts
function alignLeft(str, len, pad = " ") {
if (len < 0)
return "";
let aLen = len + 1 - str.length;
if (aLen <= 0)
return str;
return pad + str + pad.repeat(len + 1 - str.length);
}
function alignCenter(str, len, pad = " ") {
if (len < 0)
return "";
if (!str)
str = "";
let nLen = str.length;
let half = Math.floor(len / 2 - nLen / 2);
let odds = Math.abs(nLen % 2 - len % 2);
return pad.repeat(half + 1) + str + pad.repeat(half + 1 + odds);
}
function alignRight(str, len, pad = " ") {
if (len < 0)
return "";
let aLen = len + 1 - str.length;
if (aLen <= 0)
return str;
return pad.repeat(len + 1 - str.length) + str + pad;
}
function alignAuto(obj, len, pad = " ") {
let str = `${obj}`;
if (str.length <= len) {
return typeof obj === "number" ? alignRight(str, len, pad) : alignLeft(str, len, pad);
}
return str;
}
class Inspect {
static dump(obj) {
let to = JSON.stringify(obj, null, 4);
return to.replace(/"/g, "");
}
static printDump(obj) {
console.log(Inspect.dump(obj));
}
static dumpTable(rows) {
let mapRows = rows;
let keys = uniqueKeys(mapRows);
let colSizes = {};
keys.forEach((k) => {
let max = k.length;
mapRows.forEach((row) => {
let col = row[k];
if (col != null) {
let valSize = `${col}`.length;
if (valSize > max) {
max = valSize;
}
}
});
colSizes[k] = max;
});
let colSizesLength = Object.keys(colSizes).length;
let rowWidth = Object.keys(colSizes).map((k) => colSizes[k]).reduce((p, c) => p + c, 0) + colSizesLength * 2 + (colSizesLength + 1);
let sb = [];
sb.push(`+${"-".repeat(rowWidth - 2)}+`);
let head = "|";
keys.forEach((k) => head += alignCenter(k, colSizes[k]) + "|");
sb.push(head);
sb.push(`|${"-".repeat(rowWidth - 2)}|`);
mapRows.forEach((row) => {
let to = "|";
keys.forEach((k) => to += "" + alignAuto(row[k], colSizes[k]) + "|");
sb.push(to);
});
sb.push(`+${"-".repeat(rowWidth - 2)}+`);
return sb.join("\n");
}
static printDumpTable(rows) {
console.log(Inspect.dumpTable(rows));
}
}
// src/sql.ts
class Sql {

@@ -19,5 +731,5 @@ static ops = {

static opKeys = Object.keys(Sql.ops);
static create(driver) {
static create(dialect) {
function $(strings, ...params) {
if (Array.isArray(strings)) {
if (isTemplateStrings(strings)) {
let sb = "";

@@ -33,6 +745,12 @@ const sqlParams = {};

} else if (typeof value == "object" && value.$ref) {
sb += driver.quoteTable(Schema.assertMeta(value.$ref.cls).tableName);
sb += dialect.quoteTable(Meta.assertMeta(value.$ref.cls).tableName);
} else if (typeof value == "object" && typeof value.build == "function") {
const frag = value.build();
sb += mergeParams(sqlParams, frag).replaceAll("\n", "\n ");
} else if (typeof value == "object" && typeof value.sql == "string") {
const frag = value;
sb += mergeParams(sqlParams, frag).replaceAll("\n", "\n ");
} else if (value) {
const paramIndex = Object.keys(sqlParams).length + 1;
const name = `${paramIndex}`;
const name = `_${paramIndex}`;
sb += `\$${name}`;

@@ -48,13 +766,17 @@ sqlParams[name] = value;

}
function quote(meta, prop) {
$.dialect = dialect;
$.quote = dialect.quote.bind(dialect);
$.quoteColumn = dialect.quoteColumn.bind(dialect);
$.quoteTable = dialect.quoteTable.bind(dialect);
function quoteProp(meta, prop) {
const p = meta.props.find((x) => x.name == prop)?.column;
if (!p)
throw new Error(`${meta.name} does not have a column property ${prop}`);
return driver.quoteColumn(p.name);
return dialect.quoteColumn(p.name);
}
$.ref = function(cls, as) {
const meta = Schema.assertMeta(cls);
const meta = Meta.assertMeta(cls);
if (as == null)
as = driver.quoteTable(meta.tableName);
const get = (target, key) => key == "$ref" ? { cls, as } : Symbol(target.prefix + quote(meta, typeof key == "string" ? key : key.description));
as = dialect.quoteTable(meta.tableName);
const get = (target, key) => key == "$ref" ? { cls, as } : Symbol(target.prefix + quoteProp(meta, typeof key == "string" ? key : key.description));
const p = new Proxy({ prefix: as ? as + "." : "", meta }, { get });

@@ -66,5 +788,37 @@ return p;

};
$.join = function(...joinTables) {
return new SqlJoinBuilder(driver, ...joinTables);
$.fragment = function(sql, params = {}) {
return typeof sql == "object" ? { sql: mergeParams(params, sql), params } : { sql, params };
};
$.from = function(table, alias) {
const cls = asType(table);
const ref = asRef(table) ?? $.ref(table, alias ?? "");
return new SelectQuery($, [cls], [Meta.assertMeta(cls)], [ref]);
};
$.update = function(table) {
return new UpdateQuery($, [table], [Meta.assertMeta(table)], [$.ref(table, "")]);
};
$.deleteFrom = function(table) {
return new DeleteQuery($, [table], [Meta.assertMeta(table)], [$.ref(table, "")]);
};
$.join = function(...tables) {
return new SqlJoinBuilder($, ...tables);
};
$.groupBy = function(...tables) {
return new SqlGroupByBuilder($, ...tables);
};
$.having = function(...tables) {
return new SqlHavingBuilder($, ...tables);
};
$.orderBy = function(...tables) {
return new SqlOrderByBuilder($, ...tables);
};
$.idEquals = function hasId(id) {
return (x) => $.fragment($`${x.id} = $id`, { id });
};
$.log = function(obj) {
console.log(Inspect.dump(obj));
};
$.dump = function(obj) {
console.log(Inspect.dumpTable(obj));
};
return $;

@@ -74,60 +828,4 @@ }

// src/utils.ts
function isDate(d) {
return d && Object.prototype.toString.call(d) === "[object Date]" && !isNaN(d);
}
function toDate(s) {
return !s ? null : isDate(s) ? s : s[0] == "/" ? new Date(parseFloat(/Date\(([^)]+)\)/.exec(s)[1])) : new Date(s);
}
function propsWithValues(obj) {
return Object.keys(obj).filter((k) => obj[k] != null);
}
function uniqueKeys(rows) {
let to = [];
rows.forEach((o) => Object.keys(o).forEach((k) => {
if (to.indexOf(k) === -1) {
to.push(k);
}
}));
return to;
}
function toStr(value) {
return typeof value == "symbol" ? `:${value.description ?? ""}` : `${value}`;
}
// src/builders/where.ts
var joinOptions = function(type, cls, options) {
if (typeof options == "object") {
options = options;
return { type, cls, on: options?.on, as: options?.as, params: options?.params };
} else if (typeof options == "function") {
const builder = options;
const { sql, params } = builder.build();
return { type, cls, on: sql, params };
} else
throw new Error(`Invalid Join Option: ${typeof options}`);
};
var nextParam = function(params) {
const positionalParams = Object.keys(params).map((x) => parseInt(x)).filter((x) => !isNaN(x));
return positionalParams.length == 0 ? 1 : Math.max(...positionalParams) + 1;
};
var mergeParams = function(params, f) {
let sql = f.sql;
if (f.params && typeof f.params == "object") {
for (const [key, value] of Object.entries(f.params)) {
const exists = key in params && !isNaN(parseInt(key));
if (exists) {
const nextvalue = nextParam(params);
sql = sql.replaceAll(`\$${key}`, `\$${nextvalue}`);
params[nextvalue] = value;
} else {
params[key] = value;
}
}
}
return sql;
};
class SqlJoinBuilder {
driver;
$;
get table() {

@@ -138,14 +836,32 @@ return this.tables[0];

refs;
$;
exprs = [];
params = {};
alias = "";
buildOn;
constructor(driver, ...tables) {
this.driver = driver;
constructor($, ...tables) {
this.$ = $;
this.tables = tables;
this.$ = driver.$;
this.refs = this.tables.map((x) => this.$.ref(x));
}
on(expr) {
this.buildOn = (refs, params) => mergeParams(params, expr.call(this, ...refs));
join(expr, ...params) {
return this.add("JOIN", expr, ...params);
}
leftJoin(expr, ...params) {
return this.add("LEFT JOIN", expr, ...params);
}
rightJoin(expr, ...params) {
return this.add("RIGHT JOIN", expr, ...params);
}
fullJoin(expr, ...params) {
return this.add("FULL JOIN", expr, ...params);
}
crossJoin(expr, ...params) {
return this.add("CROSS JOIN", expr, ...params);
}
add(type, expr, ...params) {
if (Array.isArray(expr)) {
this.exprs.push({ type, expr: (_) => this.$(expr, ...params) });
} else if (typeof expr == "function") {
this.exprs.push({ type, expr: (refs) => expr.call(this, ...refs) });
}
return this;

@@ -157,27 +873,90 @@ }

}
build(refs, type) {
const params = {};
build(refs) {
if (this.alias != null) {
refs[0].$ref.as = this.$.ref(refs[0].$ref.cls, this.alias);
}
const on = this.buildOn(refs, params);
return { type, table: this.tables[0].name, as: refs[0].$ref.as, on, params };
const params = {};
const sqls = [];
for (const join of this.exprs) {
const result = join.expr(refs);
const prefix = sqls.length ? `${alignRight(join.type, 5)}` : "";
sqls.push(`${prefix} ${mergeParams(params, result)}`);
}
const on = sqls.join("");
return { type: this.exprs[0].type, on, params };
}
}
class SqlBuilderBase {
$;
tables;
params = {};
exprs = [];
delimiter = ", ";
constructor($, ...tables) {
this.$ = $;
this.tables = tables;
}
add(expr, ...params) {
if (Array.isArray(expr)) {
this.exprs.push((_) => this.$(expr, ...params));
} else if (typeof expr == "function") {
this.exprs.push((refs) => expr.call(this, ...refs));
}
return this;
}
build(refs) {
const params = {};
const sqls = [];
for (const expr of this.exprs) {
const result = expr(refs);
sqls.push(mergeParams(params, result));
}
const sql = sqls.join(this.delimiter);
return { sql, params };
}
}
class SqlGroupByBuilder extends SqlBuilderBase {
}
class SqlOrderByBuilder extends SqlBuilderBase {
}
class SqlHavingBuilder extends SqlBuilderBase {
constructor($, ...tables) {
super($, ...tables);
this.delimiter = "\n AND ";
}
}
// src/sql.builders.ts
function joinOptions(type, cls, options, ref) {
if (typeof options == "object") {
if (options?.sql) {
const { sql, params } = options;
return { type, cls, ref, on: sql, params };
} else {
options = options;
return { type, cls, ref, as: options?.as, on: options?.on, params: options?.params };
}
} else if (typeof options == "function") {
const builder = options;
const { sql, params } = builder.build();
return { type, cls, on: sql, params };
} else
throw new Error(`Invalid Join Option: ${typeof options}`);
}
class WhereQuery {
driver;
$;
tables;
metas;
refs;
constructor(driver, tables, metas, refs) {
this.driver = driver;
constructor($, tables, metas, refs) {
this.$ = $;
this.tables = tables;
this.metas = metas;
this.refs = refs;
if (!driver.$)
throw new Error(`\$ not in Driver: ${driver}`);
this.$ = driver.$;
}
$;
_where = [];

@@ -211,10 +990,7 @@ _joins = [];

}
prevJoin() {
return this.refs[this.refs.length - 1];
createInstance(table, ref) {
const meta = Meta.assertMeta(table);
ref = ref ?? this.$.ref(table);
return new this.constructor(this.$, [...this.tables, table], [...this.metas, meta], [...this.refs, ref]);
}
createInstance(table) {
const meta = {};
const ref = this.$.ref(table);
return new this.constructor(this.driver, [...this.tables, table], [...this.metas, meta], [...this.refs, ref]);
}
copyInto(instance) {

@@ -226,6 +1002,12 @@ instance.params = Object.assign({}, this.params);

}
addJoin(join) {
const table = join.cls;
const instance = this.createInstance(table);
clone() {
const instance = new this.constructor(this.$, [...this.tables], [...this.metas], [...this.refs]);
this.copyInto(instance);
return instance;
}
addJoin(options) {
const table = options.cls;
const ref = options?.ref ?? (options.as ? this.$.ref(table, options.as) : undefined);
const instance = this.createInstance(table, ref);
this.copyInto(instance);
let q = instance;

@@ -237,10 +1019,10 @@ if (!q.refs[0].$ref.as) {

const qProtected = q;
if (typeof join.on == "string") {
on = join.params ? qProtected.mergeParams({ sql: join.on, params: join.params }) : join.on;
} else if (typeof join.on == "function") {
if (typeof options.on == "string") {
on = options.params ? qProtected.mergeParams({ sql: options.on, params: options.params }) : options.on;
} else if (typeof options.on == "function") {
const refs = q.refs.slice(-2).concat([q.ref]);
const sql = Schema.assertSql(join.on.call(q, ...refs));
const sql = assertSql(options.on.call(q, ...refs));
on = qProtected.mergeParams(sql);
}
qProtected._joins.push({ type: join.type, table: Schema.assertMeta(table).tableName, on, params: join.params });
qProtected._joins.push({ type: options.type, table, on, params: options.params });
return instance;

@@ -253,3 +1035,3 @@ }

const refs = builder.tables.map((cls2) => this.refOf(cls2) ?? this.$.ref(cls2));
let { type, table, on, as, params } = builder.build(refs, typeHint);
let { type, on, params } = builder.build(refs, typeHint);
if (on && params) {

@@ -259,19 +1041,29 @@ on = this.mergeParams({ sql: on, params });

const qProtected = q;
qProtected._joins.push({ type, table, on, as, params });
qProtected._joins.push({ type, on, params });
return q;
}
join(cls, options) {
return cls.tables ? this.joinBuilder(cls, "JOIN") : this.addJoin(joinOptions("JOIN", cls, options));
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
return !cls?.$ref && cls.tables ? this.joinBuilder(cls, "JOIN") : this.addJoin(joinOptions("JOIN", asType(cls), options, asRef(cls)));
}
leftJoin(cls, options) {
return cls.tables ? this.joinBuilder(cls, "LEFT JOIN") : this.addJoin(joinOptions("LEFT JOIN", cls, options));
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
return this.addJoin(joinOptions("LEFT JOIN", asType(cls), options, asRef(cls)));
}
rightJoin(cls, options) {
return cls.tables ? this.joinBuilder(cls, "RIGHT JOIN") : this.addJoin(joinOptions("RIGHT JOIN", cls, options));
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
return this.addJoin(joinOptions("RIGHT JOIN", asType(cls), options, asRef(cls)));
}
fullJoin(cls, options) {
return cls.tables ? this.joinBuilder(cls, "FULL JOIN") : this.addJoin(joinOptions("FULL JOIN", cls, options));
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
return this.addJoin(joinOptions("FULL JOIN", asType(cls), options, asRef(cls)));
}
crossJoin(cls, options) {
return cls.tables ? this.joinBuilder(cls, "CROSS JOIN") : this.addJoin(joinOptions("CROSS JOIN", cls, options));
if (typeof cls != "object" && typeof cls != "function")
throw new Error(`invalid argument: ${typeof cls}`);
return this.addJoin(joinOptions("CROSS JOIN", asType(cls), options, asRef(cls)));
}

@@ -285,7 +1077,7 @@ where(options, ...params) {

return this;
} else if (Array.isArray(options)) {
return this.condition("AND", { sql: this.$(options, ...params) });
} else if (isTemplateStrings(options)) {
return this.condition("AND", this.$(options, ...params));
} else if (typeof options == "function") {
const sql = Schema.assertSql(options.call(this, ...this.refs));
return this.condition("AND", { sql });
const sql = assertSql(options.call(this, ...this.refs));
return this.condition("AND", sql);
} else {

@@ -300,6 +1092,6 @@ return this.condition("AND", options);

} else if (Array.isArray(options)) {
return this.condition("OR", { sql: this.$(options, ...params) });
return this.condition("OR", this.$(options, ...params));
} else if (typeof options == "function") {
const sql = Schema.assertSql(options.call(this, ...this.refs));
return this.condition("OR", { sql });
const sql = assertSql(options.call(this, ...this.refs));
return this.condition("OR", sql);
} else {

@@ -310,9 +1102,5 @@ return this.condition("OR", options);

condition(condition, options) {
if (options.sql) {
const sql = Array.isArray(options.sql) ? options.sql : [options.sql];
for (const fragment of sql) {
this._where.push({ condition, sql: this.mergeParams(fragment) });
}
}
if (options.rawSql) {
if ("sql" in options && "params" in options) {
this._where.push({ condition, sql: this.mergeParams(options) });
} else if (options.rawSql) {
const sql = Array.isArray(options.rawSql) ? options.rawSql : [options.rawSql];

@@ -335,6 +1123,6 @@ for (const fragment of sql) {

quote(symbol) {
return this.driver.quote(symbol);
return this.$.quote(symbol);
}
quoteTable(table) {
return this.driver.quoteTable(table);
return this.$.quoteTable(table);
}

@@ -344,5 +1132,5 @@ quoteColumn(column) {

const prefix = as ? as + "." : "";
return prefix + this.driver.quoteColumn(column);
return prefix + this.$.quoteColumn(column);
}
alias(alias) {
as(alias) {
this.refs[0] = this.$.ref(this.refs[0].$ref.cls, alias);

@@ -362,8 +1150,7 @@ return this;

for (const [key, value] of Object.entries(f.params)) {
const exists = key in this.params && !isNaN(parseInt(key));
const exists = key in this.params && key[0] === "_" && !isNaN(parseInt(key.substring(1)));
if (exists) {
const positionalParams = Object.keys(this.params).map((x) => parseInt(x)).filter((x) => !isNaN(x));
const nextParam2 = positionalParams.length == 0 ? 1 : Math.max(...positionalParams) + 1;
sql = sql.replaceAll(`\$${key}`, `\$${nextParam2}`);
this.params[nextParam2] = value;
const nextvalue = nextParam(this.params);
sql = sql.replaceAll(`\$${key}`, `\$${nextvalue}`);
this.params[nextvalue] = value;
} else {

@@ -395,3 +1182,3 @@ this.params[key] = value;

}
const sql = columnNames.map((name) => `${this.driver.quoteColumn(name)} ${Sql.ops[op]}`).join(` ${condition} `);
const sql = columnNames.map((name) => `${this.$.quoteColumn(name)} ${Sql.ops[op]}`).join(` ${condition} `);
this._where.push({ condition, sql });

@@ -405,3 +1192,3 @@ } else if (typeof values == "object") {

throw new Error(`Property ${key} is not a column`);
const sqlLeft = `${this.driver.quoteColumn(prop.column.name)} ${sqlOp}`;
const sqlLeft = `${this.$.quoteColumn(prop.column.name)} ${sqlOp}`;
if (Array.isArray(value)) {

@@ -429,6 +1216,6 @@ let sqlValues = ``;

return "";
let sb = " WHERE ";
let sb = "\n WHERE ";
for (const [i, { condition, sql }] of this._where.entries()) {
if (i > 0)
sb += ` ${condition} `;
sb += `\n${alignRight(condition, 5)}`;
sb += sql;

@@ -442,33 +1229,95 @@ }

let sql = "";
for (const { type, table, as, on } of this._joins) {
const quotedTable = this.driver.quoteTable(table);
const sqlAs = as && as !== quotedTable ? ` ${as}` : "";
for (let i = 0;i < this._joins.length; i++) {
const { type, on } = this._joins[i];
const ref = this.refs[i + 1];
const meta = this.metas[i + 1];
const quotedTable = this.$.quoteTable(meta.tableName);
const refAs = ref.$ref.as;
const sqlAs = refAs && refAs !== quotedTable ? ` ${refAs}` : "";
const sqlOn = typeof on == "string" ? ` ON ${on}` : "";
sql += ` ${type ?? "JOIN"} ${quotedTable}${sqlAs}${sqlOn}`;
let joinType = type ?? "JOIN";
const spaces = leftPart(joinType, " ").length <= 4 ? " " : " ";
sql += `\n${spaces}${type ?? "JOIN"} ${quotedTable}${sqlAs}${sqlOn}`;
}
return sql;
}
into(into) {
const { sql, params } = this.build();
return { sql, params, into };
}
build() {
const sql = this.buildWhere();
return { sql, params: this.params };
const params = this.params;
return { sql, params };
}
}
// src/builders/delete.ts
class DeleteQuery extends WhereQuery {
buildDelete() {
const sql = `DELETE FROM ${this.quoteTable(this.meta.tableName)}${this.buildWhere()}`;
return sql;
}
build() {
const sql = this.buildDelete();
return { sql, params: this.params };
}
}
// src/builders/select.ts
class SelectQuery extends WhereQuery {
_select = [];
_groupBy = [];
_having = [];
_orderBy = [];
_skip;
_take;
_limit;
copyInto(instance) {
super.copyInto(instance);
instance._select = Array.from(this._select);
instance._groupBy = Array.from(this._groupBy);
instance._having = Array.from(this._having);
instance._skip = this._skip;
instance._take = this._take;
return instance;
}
clone() {
return super.clone();
}
groupBy(options, ...params) {
if (!options && params.length == 0) {
this._groupBy.length = 0;
} else if (Array.isArray(options)) {
const frag = this.$(options, ...params);
this._groupBy.push(this.mergeParams(frag));
} else if (typeof options == "object") {
const frag = typeof options.build == "function" ? options.build(this.refs) : assertSql(options);
this._groupBy.push(this.mergeParams(frag));
} else if (typeof options == "function") {
const frag = assertSql(options.call(this, ...this.refs));
this._groupBy.push(this.mergeParams(frag));
} else
throw new Error(`Invalid Argument: ${typeof options}`);
return this;
}
having(options, ...params) {
if (!options && params.length == 0) {
this._having.length = 0;
} else if (Array.isArray(options)) {
const frag = this.$(options, ...params);
this._having.push(this.mergeParams(frag));
} else if (typeof options == "object") {
const frag = typeof options.build == "function" ? options.build(this.refs) : assertSql(options);
this._having.push(this.mergeParams(frag));
} else if (typeof options == "function") {
const frag = assertSql(options.call(this, ...this.refs));
this._having.push(this.mergeParams(frag));
} else
throw new Error(`Invalid Argument: ${typeof options}`);
return this;
}
orderBy(options, ...params) {
if (!options && params.length == 0) {
this._orderBy.length = 0;
} else if (Array.isArray(options)) {
const frag = this.$(options, ...params);
this._orderBy.push(this.mergeParams(frag));
} else if (typeof options == "object") {
const frag = typeof options.build == "function" ? options.build(this.refs) : assertSql(options);
this._orderBy.push(this.mergeParams(frag));
} else if (typeof options == "function") {
const frag = assertSql(options.call(this, ...this.refs));
this._orderBy.push(this.mergeParams(frag));
} else
throw new Error(`Invalid Argument: ${typeof options}`);
return this;
}
select(options, ...params) {

@@ -487,7 +1336,5 @@ if (!options && params.length === 0) {

if (o.sql) {
const sql = Array.isArray(o.sql) ? o.sql : [o.sql];
for (const fragment of sql) {
this._select.push(fragment.sql);
this.addParams(fragment.params);
}
const frag = o.sql;
this._select.push(frag.sql);
this.addParams(frag.params);
}

@@ -508,3 +1355,3 @@ if (o.props) {

} else if (typeof options == "function") {
const sql = Schema.assertSql(options.call(this, ...this.refs));
const sql = assertSql(options.call(this, ...this.refs));
this._select.push(this.mergeParams(sql));

@@ -519,14 +1366,28 @@ } else

skip(rows) {
this._skip = rows == null ? undefined : rows;
return this;
return this.limit(this._take, rows);
}
take(rows) {
this._take = rows == null ? undefined : rows;
return this;
return this.limit(rows, this._skip);
}
limit(skip, take) {
limit(take, skip) {
this._take = take == null ? undefined : take;
this._skip = skip == null ? undefined : skip;
this._take = take == null ? undefined : take;
if (take == null && skip == null) {
this._limit = undefined;
} else {
const frag = this.$.dialect.sqlLimit(this._skip, this._take);
this._limit = this.mergeParams(frag);
}
return this;
}
exists() {
const q = this.clone();
q._select = ["TRUE"];
q._limit = "LIMIT 1";
return q.into(Boolean);
}
rowCount() {
const { sql, params } = this.build();
return { sql: `SELECT COUNT(*) FROM (${sql}) AS COUNT`, params, into: Number };
}
buildSelect() {

@@ -539,3 +1400,3 @@ const sqlSelect = this._select.length > 0 ? this._select.join(", ") : this.meta.columns.map((x) => this.quoteColumn(x.name)).join(", ");

const quotedTable = this.quoteTable(this.meta.tableName);
let sql = `FROM ${quotedTable}`;
let sql = `\n FROM ${quotedTable}`;
const alias = this.refs[0].$ref.as;

@@ -548,47 +1409,56 @@ if (alias && alias != quotedTable) {

buildGroupBy() {
return "";
if (this._groupBy.length == 0)
return "";
return `\n GROUP BY ${this._groupBy.join(", ")}`;
}
buildHaving() {
return "";
if (this._having.length == 0)
return "";
return `\n HAVING ${this._having.join("\n AND ")}`;
}
buildOrderBy() {
if (this._orderBy.length == 0)
return "";
return `\n ORDER BY ${this._orderBy.join(", ")}`;
}
buildLimit() {
const sql = this.driver.sqlLimit(this._skip, this._take);
return sql;
return this._limit ? `\n ${this._limit}` : "";
}
build() {
const sql = `${this.buildSelect()} ${this.buildFrom()}${this.buildJoins()}${this.buildWhere()}${this.buildGroupBy()}${this.buildHaving()}`;
return { sql, params: this.params };
let sql = this.buildSelect() + this.buildFrom() + this.buildJoins() + this.buildWhere() + this.buildGroupBy() + this.buildHaving() + this.buildOrderBy() + this.buildLimit();
const params = this.params;
const into = this._select.length == 0 ? this.tables[0] : undefined;
return { sql, params, into };
}
}
// src/builders/update.ts
class UpdateQuery extends WhereQuery {
_set = [];
set(options) {
set(options, ...params) {
if (!options) {
this._set.length = 0;
} else if (options.sql) {
const sql = Array.isArray(options.sql) ? options.sql : [options.sql];
for (const fragment of sql) {
this._set.push(fragment.sql);
this.addParams(fragment.params);
}
}
if (options.rawSql) {
const sql = Array.isArray(options.rawSql) ? options.rawSql : [options.rawSql];
for (const fragment of sql) {
this._set.push(fragment);
if (isTemplateStrings(options)) {
const frag = this.$(options, ...params);
this._set.push(this.mergeParams(frag));
} else if (typeof options == "object") {
if ("sql" in options) {
const frag = options;
this._set.push(this.mergeParams(frag));
} else {
for (const [key, value] of Object.entries(options)) {
const prop = this.meta.props.find((x) => x.name === key);
if (!prop)
throw new Error(`Property ${key} not found in ${this.meta.name}`);
if (!prop.column)
throw new Error(`Property ${key} is not a column`);
this.params[prop.name] = value;
this._set.push(`${this.$.quote(prop.column.name)} = \$${prop.name}`);
}
}
}
if (options.values) {
for (const [key, value] of Object.entries(options.values)) {
const prop = this.meta.props.find((x) => x.name === key);
if (!prop)
throw new Error(`Property ${key} not found in ${this.meta.name}`);
if (!prop.column)
throw new Error(`Property ${key} is not a column`);
this.params[prop.name] = value;
this._set.push(`${this.driver.quote(prop.column.name)} = \$${prop.name}`);
}
}
} else if (typeof options == "function") {
const frag = assertSql(options.call(this, ...this.refs));
this._set.push(this.mergeParams(frag));
} else
throw new Error(`invalid argument: ${typeof options}`);
return this;

@@ -610,463 +1480,13 @@ }

// src/connection.ts
class Meta3 {
cls;
constructor(cls) {
this.cls = cls;
if (!cls)
throw new Error(`Class must be provided`);
if (!cls.$type)
throw new Error(`Class ${cls.name ?? cls} have a \$type property`);
}
get name() {
return this.cls.$type?.name ?? this.cls.name;
}
get tableName() {
const cls = this.cls;
const ret = cls.$type?.table?.alias ?? cls.$type?.name ?? cls.name;
if (!ret)
throw new Error(`Table name not found for ${cls.name}`);
return ret;
}
get type() {
return this.cls.$type;
}
get table() {
const ret = this.type.table;
if (!ret)
throw new Error(`Table definition not found for ${this.cls.name}`);
return ret;
}
get props() {
return this.cls.$props ?? [];
}
get columns() {
return this.props.filter((x) => x.column).map((x) => x.column);
}
}
class Schema {
static metadata = {};
static assertClass(table) {
if (!table)
throw new Error(`Class must be provided`);
const cls = table?.constructor?.$id ? table?.constructor : table.$id ? table : null;
if (!cls) {
const name = table?.name ?? table?.constructor?.name;
if (!name)
throw new Error(`Class or constructor function required`);
else if (typeof table === "function" || typeof table.constructor === "function")
throw new Error(`${name} is not a class or constructor function`);
else
throw new Error(`${name} does not contain metadata, missing @table?`);
}
return cls;
}
static assertTable(table) {
const cls = Schema.assertClass(table);
if (!cls.$type?.table) {
throw new Error(`${cls.name} does not have a @table annotation`);
}
if (!cls.$props || !cls.$props.find((x) => x.column)) {
throw new Error(`${cls.name} does not have any @column annotations`);
}
return cls;
}
static assertMeta(table) {
const cls = Schema.assertClass(table);
const id = cls.$id;
return Schema.metadata[id] ?? (Schema.metadata[id] = new Meta3(Schema.assertTable(cls)));
}
static assertSql(sql) {
if (typeof sql != "object" || !sql.sql) {
const desc = typeof sql == "symbol" ? sql.description : Array.isArray(sql) ? "Array" : `${sql}`;
throw new Error(`Expected sql\`...\` fragment, received: ${desc}`);
}
class DeleteQuery extends WhereQuery {
buildDelete() {
const sql = `DELETE FROM ${this.quoteTable(this.meta.tableName)}${this.buildWhere()}`;
return sql;
}
static dropTable(table, driver) {
const meta = Schema.assertMeta(table);
let sql = `DROP TABLE IF EXISTS ${driver.quoteTable(meta.tableName)}`;
return sql;
build() {
const sql = this.buildDelete();
return { sql, params: this.params };
}
static createTable(table, driver) {
const meta = Schema.assertMeta(table);
const columns = meta.columns;
let sqlColumns = columns.map((c) => `${driver.sqlColumnDefinition(c)}`).join(",\n ");
let sql = `CREATE TABLE ${driver.quoteTable(meta.tableName)} (\n ${sqlColumns}\n);\n`;
const indexes = columns.filter((c) => c.index).map((c) => `${driver.sqlIndexDefinition(meta.table, c)};`);
if (indexes.length > 0) {
sql += indexes.join("\n");
}
return sql;
}
static insert(table, driver, options) {
const meta = Schema.assertMeta(table);
let props = meta.props.filter((x) => x.column);
if (options?.onlyProps) {
props = props.filter((c) => options.onlyProps.includes(c.name));
}
let columns = props.map((x) => x.column).filter((c) => !c.autoIncrement);
let sqlColumns = columns.map((c) => `${driver.quoteColumn(c.name)}`).join(", ");
let sqlParams = columns.map((c) => `\$${c.name}`).join(", ");
let sql = `INSERT INTO ${driver.quoteTable(meta.tableName)} (${sqlColumns}) VALUES (${sqlParams})`;
return sql;
}
static update(table, driver, options) {
const meta = Schema.assertMeta(table);
let props = meta.props.filter((x) => x.column);
if (options?.onlyProps) {
props = props.filter((c) => options.onlyProps.includes(c.name));
}
const columns = props.map((x) => x.column);
const setColumns = columns.filter((c) => !c.primaryKey);
const whereColumns = columns.filter((c) => c.primaryKey);
const setSql = setColumns.map((c) => `${driver.quoteColumn(c.name)}=\$${c.name}`).join(", ");
const whereSql = whereColumns.map((c) => `${driver.quoteColumn(c.name)} = \$${c.name}`).join(" AND ");
let sql = `UPDATE ${driver.quoteTable(meta.tableName)} SET ${setSql}`;
if (whereSql) {
sql += ` WHERE ${whereSql}`;
} else if (!options?.force) {
throw new Error(`No WHERE clause exists for UPDATE ${meta.tableName}, force update with { force:true }`);
}
console.log("Schema.update", sql);
return sql;
}
static delete(table, driver, options) {
const meta = Schema.assertMeta(table);
let props = meta.props.filter((x) => x.column);
const columns = props.map((x) => x.column);
const whereColumns = columns.filter((c) => c.primaryKey);
let whereSql = whereColumns.map((c) => `${driver.quoteColumn(c.name)} = \$${c.name}`).join(" AND ");
if (options?.where) {
let sql2 = whereSql ? " AND " : " WHERE ";
const where5 = Array.isArray(options.where) ? options.where : [options.where];
whereSql += sql2 + where5.join(" AND ");
}
let sql = `DELETE FROM ${driver.quoteTable(meta.tableName)}`;
if (whereSql) {
sql += ` WHERE ${whereSql}`;
} else if (!options?.force) {
throw new Error(`No WHERE clause exists for DELETE ${meta.tableName}, force delete with { force:true }`);
}
console.log("Schema.delete", sql);
return sql;
}
static toDbBindings(table, driver) {
const values = [];
const meta = Schema.assertMeta(table.constructor);
const props = meta.props.filter((x) => x.column);
props.forEach((x) => {
const value = table[x.column.name];
const converter = driver.converters[x.column.type];
if (converter) {
const dbValue = converter.toDb(value);
values.push(dbValue);
} else {
values.push(value);
}
});
return values;
}
static toDbObject(table, driver, options) {
const values = {};
const meta = Schema.assertMeta(table.constructor);
const props = meta.props.filter((x) => x.column);
for (const x of props) {
if (options?.onlyProps && !options.onlyProps.includes(x.name))
continue;
const value = table[x.name];
const converter = driver.converters[x.column.type];
if (converter) {
const dbValue = converter.toDb(value);
values[x.column.name] = dbValue;
} else {
values[x.column.name] = value;
}
}
return values;
}
}
class ConnectionBase {
driver;
$;
constructor(driver) {
this.driver = driver;
if (!driver.$)
throw new Error(`\$ not in Driver: ${driver}`);
this.$ = driver.$;
}
quote(symbol) {
return this.driver.quote(symbol);
}
from(table) {
return new SelectQuery(this.driver, [table], [Schema.assertMeta(table)], [this.$.ref(table, "")]);
}
updateFor(table) {
return new UpdateQuery(this.driver, [table], [Schema.assertMeta(table)], [this.$.ref(table, "")]);
}
deleteFrom(table) {
return new DeleteQuery(this.driver, [table], [Schema.assertMeta(table)], [this.$.ref(table, "")]);
}
}
class Connection extends ConnectionBase {
get sync() {
if (this.driver.sync == null) {
throw new Error(`${this.driver.name} does not support sync APIs`);
}
return this.driver.sync;
}
quote(symbol) {
return this.driver.quote(symbol);
}
async insert(row, options) {
return Promise.resolve(this.sync.insert(row, options));
}
async insertAll(rows, options) {
return Promise.resolve(this.sync.insertAll(rows, options));
}
async listTables() {
return Promise.resolve(this.sync.listTables());
}
async dropTable(table) {
return Promise.resolve(this.sync.dropTable(table));
}
async createTable(table) {
return Promise.resolve(this.sync.createTable(table));
}
async all(strings, ...params) {
return Promise.resolve(this.sync.all(strings, ...params));
}
async single(strings, ...params) {
return Promise.resolve(this.sync.single(strings, ...params));
}
}
class SyncConnection extends ConnectionBase {
insert(row, options) {
if (!row)
return;
const cls = row.constructor;
if (options?.onlyProps || options?.onlyWithValues) {
const onlyProps = options?.onlyProps ?? propsWithValues(row);
const onlyOptions = { onlyProps };
let stmt = this.driver.prepareRaw(Schema.insert(cls, this.driver, onlyOptions));
const dbRow = Schema.toDbObject(row, this.driver, onlyOptions);
return stmt.exec(dbRow);
} else {
let stmt = this.driver.prepareRaw(Schema.insert(cls, this.driver));
const dbRow = Schema.toDbObject(row, this.driver);
return stmt.exec(dbRow);
}
}
insertAll(rows, options) {
if (rows.length == 0)
return;
const cls = rows[0].constructor;
if (options?.onlyProps || options?.onlyWithValues) {
for (const row of rows) {
this.insert(row, options);
}
} else {
let last = null;
let stmt = this.driver.prepareRaw(Schema.insert(cls, this.driver));
for (const row of rows) {
const dbRow = Schema.toDbObject(row, this.driver);
last = stmt.exec(dbRow);
}
return last;
}
}
update(row, options) {
if (!row)
return;
const cls = row.constructor;
if (options?.onlyProps || options?.onlyWithValues) {
const onlyProps = options?.onlyProps ?? propsWithValues(row);
const onlyOptions = { onlyProps };
let stmt = this.driver.prepareRaw(Schema.update(cls, this.driver, onlyOptions));
const dbRow = Schema.toDbObject(row, this.driver, onlyOptions);
return stmt.exec(dbRow);
} else {
let stmt = this.driver.prepareRaw(Schema.update(cls, this.driver));
const dbRow = Schema.toDbObject(row, this.driver);
return stmt.exec(dbRow);
}
}
delete(row, options) {
if (!row)
return;
const cls = row.constructor;
let stmt = this.driver.prepareRaw(Schema.delete(cls, this.driver, options));
const meta = Schema.assertMeta(cls);
const pkColumns = meta.props.filter((p) => p.column?.primaryKey);
const onlyProps = pkColumns.map((p) => p.name);
const dbRow = Schema.toDbObject(row, this.driver, { onlyProps });
return stmt.exec(dbRow);
}
listTables() {
let stmt = this.driver.prepareRaw(this.driver.sqlTableNames());
const ret = stmt.columnSync();
return ret;
}
dropTable(table) {
let stmt = this.driver.prepareRaw(Schema.dropTable(table, this.driver));
return stmt.exec();
}
createTable(table) {
let stmt = this.driver.prepareRaw(Schema.createTable(table, this.driver));
return stmt.exec();
}
createStatment(strings, ...params) {
if (typeof strings == "object" && "build" in strings) {
let query2 = strings.build();
let stmt = this.driver.prepareRaw(query2.sql);
return [stmt, query2.params];
} else {
let stmt = this.driver.prepare(strings, ...params);
return [stmt, params];
}
}
all(strings, ...params) {
const [stmt, p] = this.createStatment(strings, ...params);
return Array.isArray(p) ? stmt.allSync(...p) : stmt.allSync(p);
}
single(strings, ...params) {
const [stmt, p] = this.createStatment(strings, ...params);
return Array.isArray(p) ? stmt.firstSync(...p) : stmt.firstSync(p);
}
column(strings, ...params) {
const [stmt, p] = this.createStatment(strings, ...params);
return Array.isArray(p) ? stmt.columnSync(...p) : stmt.columnSync(p);
}
scalar(strings, ...params) {
const [stmt, p] = this.createStatment(strings, ...params);
return Array.isArray(p) ? stmt.scalarSync(...p) : stmt.scalarSync(p);
}
exec(sql, params) {
if (!sql)
throw new Error("query is required");
const query2 = typeof sql == "object" && "build" in sql ? sql.build() : { sql, params };
let stmt = this.driver.prepareRaw(query2.sql);
return stmt.exec(query2.params);
}
}
class NamingStrategy {
tableName(table) {
return table;
}
columnName(column) {
return column;
}
tableFromDef(def) {
return def.alias ?? def.name;
}
}
// src/inspect.ts
var alignLeft = function(str, len, pad = " ") {
if (len < 0)
return "";
let aLen = len + 1 - str.length;
if (aLen <= 0)
return str;
return pad + str + pad.repeat(len + 1 - str.length);
};
var alignCenter = function(str, len, pad = " ") {
if (len < 0)
return "";
if (!str)
str = "";
let nLen = str.length;
let half = Math.floor(len / 2 - nLen / 2);
let odds = Math.abs(nLen % 2 - len % 2);
return pad.repeat(half + 1) + str + pad.repeat(half + 1 + odds);
};
var alignRight = function(str, len, pad = " ") {
if (len < 0)
return "";
let aLen = len + 1 - str.length;
if (aLen <= 0)
return str;
return pad.repeat(len + 1 - str.length) + str + pad;
};
var alignAuto = function(obj, len, pad = " ") {
let str = `${obj}`;
if (str.length <= len) {
return typeof obj === "number" ? alignRight(str, len, pad) : alignLeft(str, len, pad);
}
return str;
};
class Inspect {
static dump(obj) {
let to = JSON.stringify(obj, null, 4);
return to.replace(/"/g, "");
}
static printDump(obj) {
console.log(Inspect.dump(obj));
}
static dumpTable(rows) {
let mapRows = rows;
let keys = uniqueKeys(mapRows);
let colSizes = {};
keys.forEach((k) => {
let max = k.length;
mapRows.forEach((row) => {
let col = row[k];
if (col != null) {
let valSize = `${col}`.length;
if (valSize > max) {
max = valSize;
}
}
});
colSizes[k] = max;
});
let colSizesLength = Object.keys(colSizes).length;
let rowWidth = Object.keys(colSizes).map((k) => colSizes[k]).reduce((p, c) => p + c, 0) + colSizesLength * 2 + (colSizesLength + 1);
let sb = [];
sb.push(`+${"-".repeat(rowWidth - 2)}+`);
let head = "|";
keys.forEach((k) => head += alignCenter(k, colSizes[k]) + "|");
sb.push(head);
sb.push(`|${"-".repeat(rowWidth - 2)}|`);
mapRows.forEach((row) => {
let to = "|";
keys.forEach((k) => to += "" + alignAuto(row[k], colSizes[k]) + "|");
sb.push(to);
});
sb.push(`+${"-".repeat(rowWidth - 2)}+`);
return sb.join("\n");
}
static printDumpTable(rows) {
console.log(Inspect.dumpTable(rows));
}
}
// src/converters.ts
function converterFor(converter, ...dataTypes) {
const to = {};
for (const dataType of dataTypes) {
to[dataType] = converter;
}
return to;
}
class DateTimeConverter {
static instance = new DateTimeConverter;
toDb(value) {
const d = toDate(value);
return d ? d.toISOString() : null;
}
fromDb(value) {
if (!value)
return null;
return toDate(value);
}
}
// src/model.ts

@@ -1131,3 +1551,3 @@ function table(options) {

var DataType;
(function(DataType2) {
((DataType2) => {
DataType2["INTEGER"] = "INTEGER";

@@ -1162,3 +1582,3 @@ DataType2["SMALLINT"] = "SMALLINT";

DataType2["XML"] = "XML";
})(DataType || (DataType = {}));
})(DataType ||= {});
var DefaultValues = {

@@ -1171,19 +1591,376 @@ NOW: "{NOW}",

};
// src/sqlite/dialect.ts
class SqliteDialect {
$;
strategy = new DefaultStrategy;
constructor() {
this.$ = Sql.create(this);
}
quote(name) {
return `"${name}"`;
}
quoteTable(name) {
return this.quote(this.strategy.tableName(name));
}
quoteColumn(name) {
return this.quote(this.strategy.columnName(name));
}
sqlLimit(offset, limit) {
if (offset == null && limit == null)
throw new Error(`Invalid argument sqlLimit(${offset}, ${limit})`);
const frag = offset ? this.$.fragment(`LIMIT \$limit OFFSET \$offset`, { offset, limit: limit ?? -1 }) : this.$.fragment(`LIMIT \$limit`, { limit });
return frag;
}
}
// src/sqlite/schema.ts
class SqliteSchema extends Schema {
driver;
constructor(driver) {
super(driver.dialect);
this.driver = driver;
}
sqlTableNames() {
return "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%'";
}
sqlIndexDefinition(table2, column2) {
const unique = column2.unique ? "UNIQUE INDEX" : "INDEX";
return `CREATE ${unique} idx_${table2.name}_${column2.name} ON ${this.dialect.quoteTable(table2.name)} (${this.dialect.quoteColumn(column2.name)})`;
}
sqlColumnDefinition(column2) {
let dataType = column2.type;
let type = this.driver.types.native.includes(dataType) ? dataType : undefined;
if (!type) {
for (const [sqliteType, typeMapping] of Object.entries(this.driver.types.map)) {
if (typeMapping.includes(dataType)) {
type = sqliteType;
break;
}
}
}
if (!type)
type = dataType;
let sb = `${this.dialect.quoteColumn(column2.name)} ${type}`;
if (column2.primaryKey) {
sb += " PRIMARY KEY";
}
if (column2.autoIncrement) {
sb += " AUTOINCREMENT";
}
if (column2.required) {
sb += " NOT NULL";
}
if (column2.unique && !column2.index) {
sb += " UNIQUE";
}
if (column2.defaultValue) {
const val = this.driver.variables[column2.defaultValue] ?? column2.defaultValue;
sb += ` DEFAULT ${val}`;
}
return sb;
}
sqlLimit(offset, limit) {
if (offset == null && limit == null)
throw new Error(`Invalid argument sqlLimit(${offset}, ${limit})`);
const frag = offset ? this.driver.$.fragment(`LIMIT \$limit OFFSET \$offset`, { offset, limit: limit ?? -1 }) : this.driver.$.fragment(`LIMIT \$limit`, { limit });
return frag;
}
}
// src/sqlite/driver.ts
class SqliteTypes {
native = [
"INTEGER" /* INTEGER */,
"SMALLINT" /* SMALLINT */,
"BIGINT" /* BIGINT */,
"REAL" /* REAL */,
"DOUBLE" /* DOUBLE */,
"FLOAT" /* FLOAT */,
"NUMERIC" /* NUMERIC */,
"DECIMAL" /* DECIMAL */,
"BOOLEAN" /* BOOLEAN */,
"DATE" /* DATE */,
"DATETIME" /* DATETIME */
];
map = {
INTEGER: ["INTERVAL" /* INTERVAL */],
REAL: ["REAL" /* REAL */],
NUMERIC: ["DECIMAL" /* DECIMAL */, "NUMERIC" /* NUMERIC */, "MONEY" /* MONEY */],
BLOB: ["BLOB" /* BLOB */, "BYTES" /* BYTES */, "BIT" /* BIT */],
TEXT: [
"UUID" /* UUID */,
"JSON" /* JSON */,
"JSONB" /* JSONB */,
"XML" /* XML */,
"TIME" /* TIME */,
"TIMEZ" /* TIMEZ */,
"TIMESTAMP" /* TIMESTAMP */,
"TIMESTAMPZ" /* TIMESTAMPZ */
]
};
}
class Sqlite {
static connection;
static driver;
static schema;
static init() {
const c = Sqlite.connection = new SqliteConnection(new Sqlite);
const { driver, schema } = c;
Object.assign(Sqlite, { driver, schema });
return c;
}
name;
dialect;
schema;
strategy = new DefaultStrategy;
$;
variables = {
[DefaultValues.NOW]: "CURRENT_TIMESTAMP",
[DefaultValues.MAX_TEXT]: "TEXT",
[DefaultValues.MAX_TEXT_UNICODE]: "TEXT",
[DefaultValues.TRUE]: "1",
[DefaultValues.FALSE]: "0"
};
types;
converters = {
...converterFor(DateTimeConverter.instance, "DATE" /* DATE */, "DATETIME" /* DATETIME */, "TIMESTAMP" /* TIMESTAMP */, "TIMESTAMPZ" /* TIMESTAMPZ */)
};
constructor() {
this.name = this.constructor.name;
this.dialect = new SqliteDialect;
this.$ = this.dialect.$;
this.types = new SqliteTypes;
this.schema = new SqliteSchema(this);
}
}
class SqliteConnection extends ConnectionBase {
}
// src/mysql/dialect.ts
class MySqlDialect {
$;
strategy = new DefaultStrategy;
constructor() {
this.$ = Sql.create(this);
}
quote(name) {
return "`" + name + "`";
}
quoteTable(name) {
return this.quote(this.strategy.tableName(name));
}
quoteColumn(name) {
return this.quote(this.strategy.columnName(name));
}
sqlLimit(offset, limit) {
if (offset == null && limit == null)
throw new Error(`Invalid argument sqlLimit(${offset}, ${limit})`);
const frag = offset ? limit ? this.$.fragment(`LIMIT \$offset, \$limit`, { offset, limit }) : this.$.fragment(`LIMIT \$offset, 18446744073709551615`, { offset }) : this.$.fragment(`LIMIT \$limit`, { limit });
return frag;
}
}
// src/mysql/schema.ts
class MySqlSchema extends SqliteSchema {
}
// src/mysql/driver.ts
class MySqlTypes {
native = [
"INTEGER" /* INTEGER */,
"SMALLINT" /* SMALLINT */,
"BIGINT" /* BIGINT */,
"REAL" /* REAL */,
"DOUBLE" /* DOUBLE */,
"FLOAT" /* FLOAT */,
"DECIMAL" /* DECIMAL */,
"NUMERIC" /* NUMERIC */,
"DECIMAL" /* DECIMAL */,
"MONEY" /* MONEY */,
"BOOLEAN" /* BOOLEAN */,
"DATE" /* DATE */,
"DATETIME" /* DATETIME */,
"TIME" /* TIME */,
"TIMEZ" /* TIMEZ */,
"TIMESTAMP" /* TIMESTAMP */,
"TIMESTAMPZ" /* TIMESTAMPZ */,
"INTERVAL" /* INTERVAL */,
"UUID" /* UUID */,
"JSON" /* JSON */,
"JSONB" /* JSONB */,
"XML" /* XML */,
"BLOB" /* BLOB */,
"BYTES" /* BYTES */,
"BIT" /* BIT */
];
map = {
["DOUBLE" /* DOUBLE */]: ["REAL" /* REAL */],
["MONEY" /* MONEY */]: ["DECIMAL" /* DECIMAL */],
["TIME" /* TIME */]: ["TIMEZ" /* TIMEZ */],
["TIMESTAMP" /* TIMESTAMP */]: ["TIMESTAMPZ" /* TIMESTAMPZ */],
["INTEGER" /* INTEGER */]: ["INTERVAL" /* INTERVAL */],
["JSON" /* JSON */]: ["JSONB" /* JSONB */],
["TEXT" /* TEXT */]: ["XML" /* XML */],
BINARY: ["BYTES" /* BYTES */],
"BINARY(1)": ["BIT" /* BIT */]
};
}
class MySql extends Sqlite {
static connection;
static driver;
static schema;
static init() {
const c = MySql.connection = new MySqlConnection(new MySql);
const { driver, schema } = c;
Object.assign(MySql, { driver, schema });
return c;
}
constructor() {
super();
this.dialect = new MySqlDialect;
this.$ = this.dialect.$;
this.types = new MySqlTypes;
this.schema = new MySqlSchema(this);
}
}
class MySqlConnection extends ConnectionBase {
}
// src/postgres/dialect.ts
class PostgreSqlDialect {
$;
strategy = new DefaultStrategy;
constructor() {
this.$ = Sql.create(this);
}
quote(name) {
return `"${name}"`;
}
quoteTable(name) {
return this.quote(this.strategy.tableName(name));
}
quoteColumn(name) {
return this.quote(this.strategy.columnName(name));
}
sqlLimit(offset, limit) {
if (offset == null && limit == null)
throw new Error(`Invalid argument sqlLimit(${offset}, ${limit})`);
const frag = offset ? limit ? this.$.fragment(`LIMIT \$limit OFFSET \$offset`, { offset, limit }) : this.$.fragment(`OFFSET \$offset`, { offset }) : this.$.fragment(`LIMIT \$limit`, { limit });
return frag;
}
}
// src/postgres/schema.ts
class PostgreSqlSchema extends SqliteSchema {
}
// src/postgres/driver.ts
class PostgreSqlTypes {
native = [
"INTEGER" /* INTEGER */,
"SMALLINT" /* SMALLINT */,
"BIGINT" /* BIGINT */,
"REAL" /* REAL */,
"DOUBLE" /* DOUBLE */,
"FLOAT" /* FLOAT */,
"DECIMAL" /* DECIMAL */,
"NUMERIC" /* NUMERIC */,
"DECIMAL" /* DECIMAL */,
"MONEY" /* MONEY */,
"BOOLEAN" /* BOOLEAN */,
"DATE" /* DATE */,
"DATETIME" /* DATETIME */,
"TIME" /* TIME */,
"TIMEZ" /* TIMEZ */,
"TIMESTAMP" /* TIMESTAMP */,
"TIMESTAMPZ" /* TIMESTAMPZ */,
"INTERVAL" /* INTERVAL */,
"UUID" /* UUID */,
"JSON" /* JSON */,
"JSONB" /* JSONB */,
"XML" /* XML */,
"BLOB" /* BLOB */,
"BYTES" /* BYTES */,
"BIT" /* BIT */
];
map = {};
}
class PostgreSql extends Sqlite {
static connection;
static driver;
static schema;
static init() {
const c = PostgreSql.connection = new PostgreSqlConnection(new PostgreSql);
const { driver, schema } = c;
Object.assign(PostgreSql, { driver, schema });
return c;
}
constructor() {
super();
this.dialect = new PostgreSqlDialect;
this.$ = this.dialect.$;
this.types = new PostgreSqlTypes;
this.schema = new PostgreSqlSchema(this);
}
}
class PostgreSqlConnection extends ConnectionBase {
}
// src/index.ts
var sqlite = (() => {
return Sqlite.init().$;
})();
var mysql = (() => {
return MySql.init().$;
})();
var postgres = (() => {
return PostgreSql.init().$;
})();
export {
useFilter,
toStr,
table,
sqlite,
snakeCase,
postgres,
pick,
omit,
nextParam,
mysql,
mergeParams,
isTemplateStrings,
converterFor,
column,
WhereQuery,
UpdateQuery,
Table,
SyncConnection,
SyncDbConnection,
SqliteSchema,
SqliteDialect,
Sqlite,
Sql,
SnakeCaseStrategy,
SelectQuery,
NamingStrategy,
Schema,
PostgreSqlSchema,
PostgreSqlDialect,
PostgreSql,
MySqlSchema,
MySqlDialect,
MySql,
Meta,
Inspect,
DeleteQuery,
DefaultValues,
DefaultStrategy,
DbConnection,
DateTimeConverter,
DataType,
ConnectionBase,
Connection
DataType
};
{
"name": "litdb",
"type": "module",
"version": "0.0.3",
"version": "0.0.4",
"main": "./dist/index.cjs",

@@ -16,4 +16,6 @@ "module": "./dist/index.js",

"build": "bun run build.ts",
"minify": "npx -y uglify-js dist/index.js --compress --mangle -o dist/index.min.js",
"compress": "npm run minify && brotli ./dist/index.min.js",
"prepublishOnly": "bun run build",
"release": "bump patch --commit --push --tag && npm publish --access public"
"release": "rm -rf ./dist && npm run build && npm run minify && bump patch --commit --push --tag && npm publish --access public"
},

@@ -40,7 +42,7 @@ "files": [

"bun-plugin-dts": "^0.3.0",
"@types/bun": "^1.1.10"
"@types/bun": "^1.1.13"
},
"dependencies": {
"@types/node": "^22.8.6"
"@types/node": "^22.9.0"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc