Skip to content

Commit

Permalink
More pg boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
ClaireNeveu committed Apr 24, 2024
1 parent dca3c12 commit 1605493
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 97 deletions.
2 changes: 1 addition & 1 deletion packages/sij-dialect-postgresql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
"scripts": {
"prepublish": "npm run build",
"build": "npx tsc && copyfiles -u 2 \"src/types/*.d.ts\" dist",
"build": "npx tsc",
"format": "npx prettier . --write",
"test": "ava -v && tsd",
"docs": "npx typedoc src/ --out docs/ --includeDeclarations --excludeExternals --excludeNotExported --excludePrivate && touch docs/.nojekyll"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ interface SetColumnCompression
extends Tagged<
'SetColumnCompression',
{
readonly;
readonly method: Ident;
}
> {}
const SetColumnCompression = (args: UnTag<SetColumnCompression>): SetColumnCompression =>
Expand Down
18 changes: 17 additions & 1 deletion packages/sij-dialect-postgresql/src/builder/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import { PgExtension } from '../ast';
import { TableOf, TypedAst, UnQualifiedTable, WithAlias } from 'sij-core/util';
import { Expr } from 'sij-core/ast';

class PgDeleteBuilder<Schema, Table, Return> extends DeleteBuilder<Schema, Table, Return, PgExtension> {}
class PgDeleteBuilder<Schema, Table, Return> extends DeleteBuilder<Schema, Table, Return, PgExtension> {
override lit<Return extends number | string | boolean | null>(
l: Return,
): TypedAst<Schema, Return, Expr<PgExtension>> {
return super.lit(l);
}

override where(
clause: { [K in keyof Table]?: Table[K] } | TypedAst<Schema, any, Expr<PgExtension>>,
): PgDeleteBuilder<Schema, Table, Return> {
return super.where(clause);
}
}
// Merges with above class to provide calling as a function
interface PgDeleteBuilder<Schema, Table, Return> extends DeleteBuilder<Schema, Table, Return, PgExtension> {
<T>(fn: (arg: PgDeleteBuilder<Schema, Table, Return>) => T): T;
}

export { PgDeleteBuilder };
22 changes: 16 additions & 6 deletions packages/sij-dialect-postgresql/src/builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,21 @@ class PgBuilder<Schema> extends CoreBuilder<Schema, PgExtension> {
override insertInto<TableName extends keyof Schema & string>(
table: TableName,
): PgInsertBuilder<Schema, Schema[TableName] & QualifiedTable<Schema, TableName>, number> {
return super.insertInto(table) as PgInsertBuilder<Schema, Schema[TableName] & QualifiedTable<Schema, TableName>, number>
return super.insertInto(table) as PgInsertBuilder<
Schema,
Schema[TableName] & QualifiedTable<Schema, TableName>,
number
>;
}

override update<TableName extends keyof Schema & string>(table: TableName): PgUpdateBuilder<Schema, Schema[TableName] & QualifiedTable<Schema, TableName>, number> {
return super.update(table) as PgUpdateBuilder<Schema, Schema[TableName] & QualifiedTable<Schema, TableName>, number>
override update<TableName extends keyof Schema & string>(
table: TableName,
): PgUpdateBuilder<Schema, Schema[TableName] & QualifiedTable<Schema, TableName>, number> {
return super.update(table) as PgUpdateBuilder<
Schema,
Schema[TableName] & QualifiedTable<Schema, TableName>,
number
>;
}

override deleteFrom<TableName extends keyof Schema & string>(table: TableName) {
Expand All @@ -61,11 +71,11 @@ class PgBuilder<Schema> extends CoreBuilder<Schema, PgExtension> {
}

override get schema(): PgSchemaBuilder<Schema, number> {
return super.schema() as PgSchemaBuilder<Schema, number>
return super.schema() as PgSchemaBuilder<Schema, number>;
}

override get type(): PgTypeBuilder {
return super.type
return super.type;
}

override get constraint(): PgConstraintBuilder<Schema> {
Expand All @@ -77,4 +87,4 @@ class PgBuilder<Schema> extends CoreBuilder<Schema, PgExtension> {
}
}

export { PgBuilder }
export { PgBuilder };
42 changes: 39 additions & 3 deletions packages/sij-dialect-postgresql/src/builder/insert.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
import { InsertBuilder } from 'sij-core';
import { InsertBuilder, QueryBuilder } from 'sij-core';
import { PgExtension } from '../ast';
import { TableOf, TypedAst, UnQualifiedTable, WithAlias } from 'sij-core/util';
import { Expr } from 'sij-core/ast';
import { DefaultValue, Expr } from 'sij-core/ast';

class PgInsertBuilder<Schema, Table, Return> extends InsertBuilder<Schema, Table, Return, PgExtension> {}
class PgInsertBuilder<Schema, Table, Return> extends InsertBuilder<Schema, Table, Return, PgExtension> {
override apply<T>(fn: (arg: PgInsertBuilder<Schema, Table, Return>) => T): T {
return fn(this);
}

override lit<Return extends number | string | boolean | null>(
l: Return,
): TypedAst<Schema, Return, Expr<PgExtension>> {
return super.lit(l);
}

override values(
...vs: Array<{ [Key in keyof Table]?: Table[Key] | DefaultValue | TypedAst<Schema, Table[Key], Expr<PgExtension>> }>
): Omit<PgInsertBuilder<Schema, Table, Return>, 'fromQuery' | 'columns'> {
return super.values(...vs);
}

override values1(
...vs: Array<{ [Key in keyof Table]?: Table[Key] | DefaultValue | TypedAst<Schema, Table[Key], Expr<PgExtension>> }>
): Omit<PgInsertBuilder<Schema, Table, Return>, 'fromQuery' | 'columns'> {
return super.values1(...vs);
}

override columns(...columns: Array<keyof Table>): Omit<PgInsertBuilder<Schema, Table, Return>, 'columns'> {
return super.columns(...columns);
}

override fromQuery<QReturn extends { [Key in keyof Table]?: Table[Key] }>(
query: QueryBuilder<Schema, any, QReturn, PgExtension>,
): Omit<PgInsertBuilder<Schema, Table, Return>, 'values' | 'values1' | 'columns'> {
return super.fromQuery(query);
}
}
// Merges with above class to provide calling as a function
interface PgInsertBuilder<Schema, Table, Return> extends InsertBuilder<Schema, Table, Return, PgExtension> {
<T>(fn: (arg: PgInsertBuilder<Schema, Table, Return>) => T): T;
}

export { PgInsertBuilder };
156 changes: 71 additions & 85 deletions packages/sij-dialect-postgresql/src/builder/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ import { Expr, JoinKind } from 'sij-core/ast';

class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table, Return, PgExtension> {
override selectAs<
Alias extends string,
Ret,
Id extends keyof Table & string,
Col extends Id | TypedAst<Schema, Ret, Expr<PgExtension>>,
>(
alias: Alias,
col: Col,
): PgQueryBuilder<
Schema,
TableOf<Table, AstToAlias<Col, Alias>> & Table,
UnQualifiedTable<TableOf<Table, AstToAlias<Col, Alias>>> & Return
> {
return super.selectAs(alias, col) as PgQueryBuilder<
Schema,
TableOf<Table, AstToAlias<Col, Alias>> & Table,
UnQualifiedTable<TableOf<Table, AstToAlias<Col, Alias>>> & Return
>
}
Alias extends string,
Ret,
Id extends keyof Table & string,
Col extends Id | TypedAst<Schema, Ret, Expr<PgExtension>>,
>(
alias: Alias,
col: Col,
): PgQueryBuilder<
Schema,
TableOf<Table, AstToAlias<Col, Alias>> & Table,
UnQualifiedTable<TableOf<Table, AstToAlias<Col, Alias>>> & Return
> {
return super.selectAs(alias, col) as PgQueryBuilder<
Schema,
TableOf<Table, AstToAlias<Col, Alias>> & Table,
UnQualifiedTable<TableOf<Table, AstToAlias<Col, Alias>>> & Return
>;
}
// We need to override all of the superclass methods with new return types to expose our added methods on the builder
override select<
Alias extends string,
Expand All @@ -41,16 +41,12 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,

override selectExpr<Alias extends string, ColType>(
...cols: Array<WithAlias<Alias, TypedAst<Schema, ColType, Expr<PgExtension>>>>
): PgQueryBuilder<
Schema,
{ [K in Alias]: ColType } & Table,
UnQualifiedTable<{ [K in Alias]: ColType }> & Return
> {
): PgQueryBuilder<Schema, { [K in Alias]: ColType } & Table, UnQualifiedTable<{ [K in Alias]: ColType }> & Return> {
return super.selectExpr(...cols) as PgQueryBuilder<
Schema,
{ [K in Alias]: ColType } & Table,
UnQualifiedTable<{ [K in Alias]: ColType }> & Return
>;
Schema,
{ [K in Alias]: ColType } & Table,
UnQualifiedTable<{ [K in Alias]: ColType }> & Return
>;
}

override join<
Expand All @@ -66,7 +62,11 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
TypedAst<Schema, any, Expr<PgExtension>>
>,
): PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return> {
return super.join(kind, table, on) as PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return>
return super.join(kind, table, on) as PgQueryBuilder<
Schema,
Table & MakeJoinTable<Schema, JoinTable, Alias>,
Return
>;
}

override leftJoin<
Expand All @@ -84,7 +84,7 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
return super.leftJoin(table, on) as PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return>;
}

rightJoin<
override rightJoin<
TableName extends keyof Schema & string,
Alias extends string,
SubTable,
Expand All @@ -96,10 +96,14 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
TypedAst<Schema, any, Expr<PgExtension>>
>,
): PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return> {
return super.rightJoin(table, on) as PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return>
return super.rightJoin(table, on) as PgQueryBuilder<
Schema,
Table & MakeJoinTable<Schema, JoinTable, Alias>,
Return
>;
}

fullOuterJoin<
override fullOuterJoin<
TableName extends keyof Schema & string,
Alias extends string,
SubTable,
Expand All @@ -111,10 +115,14 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
TypedAst<Schema, any, Expr<PgExtension>>
>,
): PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return> {
return super.fullOuterJoin(table, on) as PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return>;
return super.fullOuterJoin(table, on) as PgQueryBuilder<
Schema,
Table & MakeJoinTable<Schema, JoinTable, Alias>,
Return
>;
}

innerJoin<
override innerJoin<
TableName extends keyof Schema & string,
Alias extends string,
SubTable,
Expand All @@ -126,96 +134,74 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
TypedAst<Schema, any, Expr<PgExtension>>
>,
): PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return> {
return super.innerJoin(table, on) as PgQueryBuilder<Schema, Table & MakeJoinTable<Schema, JoinTable, Alias>, Return>
return super.innerJoin(table, on) as PgQueryBuilder<
Schema,
Table & MakeJoinTable<Schema, JoinTable, Alias>,
Return
>;
}

with<Table2, TableName extends string>(
override with<Table2, TableName extends string>(
alias: TableName,
sub: QueryBuilder<Schema, Table2, Return, PgExtension>,
): PgQueryBuilder<Schema, Table & { [K in StringKeys<Table2> as `${TableName}.${K}`]: Table2[K] }, Return> {
return super.with(alias, sub) as PgQueryBuilder<Schema, Table & { [K in StringKeys<Table2> as `${TableName}.${K}`]: Table2[K] }, Return>;
return super.with(alias, sub) as PgQueryBuilder<
Schema,
Table & { [K in StringKeys<Table2> as `${TableName}.${K}`]: Table2[K] },
Return
>;
}

orderBy<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
override orderBy<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
col: Col,
opts?: { order?: 'ASC' | 'DESC'; nullHandling?: 'NULLS FIRST' | 'NULLS LAST' },
): PgQueryBuilder<Schema, Table, Return> {
return super.orderBy(col, opts) as PgQueryBuilder<Schema, Table, Return>;
}

orderByAsc<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
override orderByAsc<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
col: Col,
opts?: { nullHandling?: 'NULLS FIRST' | 'NULLS LAST' },
): PgQueryBuilder<Schema, Table, Return> {
return super.orderByAsc(col, opts) as PgQueryBuilder<Schema, Table, Return>
return super.orderByAsc(col, opts) as PgQueryBuilder<Schema, Table, Return>;
}

orderByDesc<Id extends keyof Table & string, Exp extends Expr<Ext>, Col extends Id | Exp>(
override orderByDesc<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
col: Col,
opts?: { nullHandling?: 'NULLS FIRST' | 'NULLS LAST' },
): PgQueryBuilder<Schema, Table, Return> {
return super.orderByDesc(col, opts) as PgQueryBuilder<Schema, Table, Return>
return super.orderByDesc(col, opts) as PgQueryBuilder<Schema, Table, Return>;
}

limit(expr: Expr<PgExtension> | number): PgQueryBuilder<Schema, Table, Return> {
return super.limit(expr) as PgQueryBuilder<Schema, Table, Return>
override limit(expr: Expr<PgExtension> | number): PgQueryBuilder<Schema, Table, Return> {
return super.limit(expr) as PgQueryBuilder<Schema, Table, Return>;
}

offset(expr: Expr<PgExtension> | number): PgQueryBuilder<Schema, Table, Return> {
return super.offset(expr) as PgQueryBuilder<Schema, Table, Return>
override offset(expr: Expr<PgExtension> | number): PgQueryBuilder<Schema, Table, Return> {
return super.offset(expr) as PgQueryBuilder<Schema, Table, Return>;
}

where(
override where(
clause: { [K in keyof Table]?: Table[K] } | TypedAst<Schema, any, Expr<PgExtension>>,
): PgQueryBuilder<Schema, Table, Return> {
return super.where(clause) as PgQueryBuilder<Schema, Table, Return>;
}

groupBy<Id extends keyof Table & string, Exp extends Expr<Ext>, Col extends Id | Exp>(
override groupBy<Id extends keyof Table & string, Exp extends Expr<PgExtension>, Col extends Id | Exp>(
...cols: Array<Col>
): QueryBuilder<Schema, Table, Return, Ext> {
const makeColumn = (col: Col): Expr<Ext> => {
if (typeof col === 'object') {
return col as Expr<Ext>;
}
return Ident(col);
};
const columns = cols.map(makeColumn);
return new (this.constructor as typeof QueryBuilder)(
lens<Query<Ext>>().selection.groupBy.set(e => [...e, ...columns])(this._statement),
this.fn as any,
);
): PgQueryBuilder<Schema, Table, Return> {
return super.groupBy(...cols) as PgQueryBuilder<Schema, Table, Return>;
}

/**
* `having [expr]`
* @param clause Either an expression that evaluates to a boolean or a
* shorthand equality object mapping columns to values.
*/
having(
clause: { [K in keyof Table]?: Table[K] } | TypedAst<Schema, any, Expr<Ext>>,
): QueryBuilder<Schema, Table, Return, Ext> {
const expr: Expr<Ext> = (() => {
if (typeof clause === 'object' && !('ast' in clause)) {
return Object.keys(clause)
.map(k => {
const val: any = (clause as any)[k] as any;
return this.fn.eq(k as any, ast<Schema, any, Expr<Ext>>(makeLit(val)));
})
.reduce((acc, val) => this.fn.and(acc, val)).ast;
}
return clause.ast;
})();
const updateHaving = (old: Expr<Ext> | null): Expr<Ext> => {
if (old === null) {
return expr;
}
return this.fn.and(ast<Schema, boolean, Expr<Ext>>(old), ast<Schema, boolean, Expr<Ext>>(expr)).ast;
};
return new (this.constructor as typeof QueryBuilder)(
lens<Query<Ext>>().selection.having.set(e => updateHaving(e))(this._statement),
this.fn as any,
);
override having(
clause: { [K in keyof Table]?: Table[K] } | TypedAst<Schema, any, Expr<PgExtension>>,
): PgQueryBuilder<Schema, Table, Return> {
return super.groupBy(clause as any) as PgQueryBuilder<Schema, Table, Return>;
}

/**
Expand All @@ -224,12 +210,12 @@ class PgQueryBuilder<Schema, Table, Return> extends QueryBuilder<Schema, Table,
* builder includes a complete typing of SQL but in situations where SIJ has a bug
* you can continue using it while waiting for the upstream to be fixed.
*/
unTyped(): QueryBuilder<any, any, any, Ext> {
unTyped(): PgQueryBuilder<any, any, any> {
return this;
}

get foo() {
return 5
return 5;
}
}

Expand Down
Loading

0 comments on commit 1605493

Please sign in to comment.