@contember/database
Advanced tools
Comparing version 0.10.0-alpha.2 to 0.10.0-alpha.3
@@ -165,3 +165,4 @@ "use strict"; | ||
.appendString(' do update set ') | ||
.append(this.createSet(onConflict.values)); | ||
.append(this.createSet(onConflict.values)) | ||
.append(onConflict.where.compile()); | ||
default: | ||
@@ -168,0 +169,0 @@ return utils_1.assertNever(onConflict); |
@@ -17,3 +17,3 @@ import { Returning } from './internal/Returning'; | ||
using(tableName: string, alias?: string): DeleteBuilder<Result>; | ||
returning(column: QueryBuilder.ColumnIdentifier | Literal): DeleteBuilder<Returning.Result[]>; | ||
returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): DeleteBuilder<R[]>; | ||
createQuery(context: Compiler.Context): Literal; | ||
@@ -20,0 +20,0 @@ execute(db: Client): Promise<Result>; |
@@ -34,4 +34,4 @@ "use strict"; | ||
} | ||
returning(column) { | ||
return this.withOption('returning', new Returning_1.Returning(column)); | ||
returning(...columns) { | ||
return this.withOption('returning', new Returning_1.Returning(columns)); | ||
} | ||
@@ -38,0 +38,0 @@ createQuery(context) { |
@@ -10,2 +10,3 @@ import { Returning } from './internal/Returning'; | ||
import { SubQueryExpression } from './internal/Subqueries'; | ||
import { Where } from './internal/Where'; | ||
declare class InsertBuilder<Result extends InsertBuilder.InsertResult> implements With.Aware, QueryBuilder { | ||
@@ -18,5 +19,5 @@ private readonly options; | ||
values(columns: QueryBuilder.Values): InsertBuilder<Result>; | ||
onConflict(type: ConflictActionType.update, target: InsertBuilder.ConflictTarget, values: QueryBuilder.Values): InsertBuilder<Result>; | ||
onConflict(type: ConflictActionType.doNothing, target?: InsertBuilder.ConflictTarget): InsertBuilder<Result>; | ||
returning(column: string | Literal): InsertBuilder<Returning.Result[]>; | ||
onConflict(action: ConflictActionType.update, target: InsertBuilder.ConflictTarget, values: QueryBuilder.Values, where?: Where.Expression): InsertBuilder<Result>; | ||
onConflict(action: ConflictActionType.doNothing, target?: InsertBuilder.ConflictTarget): InsertBuilder<Result>; | ||
returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): InsertBuilder<R[]>; | ||
from(from: SelectBuilder.Callback): InsertBuilder<Result>; | ||
@@ -45,7 +46,7 @@ createQuery(context: Compiler.Context): Literal; | ||
target?: ConflictTarget; | ||
} | { | ||
} | (Where.Options & { | ||
type: ConflictActionType.update; | ||
values: QueryBuilder.ResolvedValues; | ||
target: ConflictTarget; | ||
}; | ||
}); | ||
type IndexColumns = string[]; | ||
@@ -52,0 +53,0 @@ type ConflictTarget = IndexColumns | { |
@@ -11,2 +11,3 @@ "use strict"; | ||
const Subqueries_1 = require("./internal/Subqueries"); | ||
const Where_1 = require("./internal/Where"); | ||
class InsertBuilder { | ||
@@ -35,9 +36,15 @@ constructor(options) { | ||
} | ||
onConflict(type, target, values) { | ||
onConflict(action, target, values, where) { | ||
let conflictAction; | ||
if (type === ConflictActionType_1.ConflictActionType.update && values && target) { | ||
conflictAction = { type, values: utils_1.resolveValues(values), target }; | ||
if (action === ConflictActionType_1.ConflictActionType.update && values && target) { | ||
const whereStm = new Where_1.Where.Statement([]); | ||
conflictAction = { | ||
type: action, | ||
values: utils_1.resolveValues(values), | ||
target, | ||
where: where ? whereStm.withWhere(where) : whereStm, | ||
}; | ||
} | ||
else if (type === ConflictActionType_1.ConflictActionType.doNothing) { | ||
conflictAction = { type, target }; | ||
else if (action === ConflictActionType_1.ConflictActionType.doNothing) { | ||
conflictAction = { type: action, target }; | ||
} | ||
@@ -49,4 +56,4 @@ else { | ||
} | ||
returning(column) { | ||
return this.withOption('returning', new Returning_1.Returning(column)); | ||
returning(...columns) { | ||
return this.withOption('returning', new Returning_1.Returning(columns)); | ||
} | ||
@@ -53,0 +60,0 @@ from(from) { |
@@ -5,4 +5,4 @@ import { QueryBuilder } from '../'; | ||
declare class Returning { | ||
private readonly column; | ||
constructor(column?: QueryBuilder.ColumnIdentifier | Literal | null); | ||
private readonly columns; | ||
constructor(columns?: (QueryBuilder.ColumnIdentifier | Literal)[]); | ||
compile(): Literal; | ||
@@ -13,7 +13,8 @@ parseResponse<ProcessedResult extends number | Returning.Result[]>(result: Connection.Result): ProcessedResult; | ||
interface Aware { | ||
returning(column: QueryBuilder.ColumnIdentifier | Literal): any; | ||
returning(...columns: ReturningColumn[]): any; | ||
} | ||
type Result = number | string; | ||
type Result = Record<string, any>; | ||
type ReturningColumn = QueryBuilder.ColumnIdentifier | Literal; | ||
} | ||
export { Returning }; | ||
//# sourceMappingURL=Returning.d.ts.map |
@@ -7,24 +7,17 @@ "use strict"; | ||
class Returning { | ||
constructor(column = null) { | ||
this.column = column; | ||
constructor(columns = []) { | ||
this.columns = columns; | ||
} | ||
compile() { | ||
if (this.column === null) { | ||
if (this.columns.length === 0) { | ||
return new Literal_1.Literal(''); | ||
} | ||
if (this.column instanceof Literal_1.Literal) { | ||
return new Literal_1.Literal(' returning ').append(this.column); | ||
} | ||
return new Literal_1.Literal(' returning ' + utils_1.toFqnWrap(this.column)); | ||
const columns = this.columns.map(it => (it instanceof Literal_1.Literal ? it : new Literal_1.Literal(utils_1.toFqnWrap(it)))); | ||
return new Literal_1.Literal(' returning ').appendAll(columns, ', '); | ||
} | ||
parseResponse(result) { | ||
const returningColumn = this.column; | ||
if (returningColumn) { | ||
return (typeof returningColumn === 'string' | ||
? result.rows.map(it => it[returningColumn]) | ||
: result.rows); | ||
} | ||
else { | ||
if (this.columns.length === 0) { | ||
return result.rowCount; | ||
} | ||
return result.rows; | ||
} | ||
@@ -31,0 +24,0 @@ } |
@@ -39,5 +39,3 @@ import { With } from './internal/With'; | ||
type Callback = (qb: SelectBuilder<any>) => SelectBuilder<any>; | ||
type Result = { | ||
[columnName: string]: any; | ||
}; | ||
type Result = Record<string, any>; | ||
type Options = Readonly<With.Options & Where.Options & { | ||
@@ -44,0 +42,0 @@ select: Literal[]; |
@@ -17,3 +17,3 @@ import { Returning } from './internal/Returning'; | ||
values(columns: QueryBuilder.Values): UpdateBuilder<Result>; | ||
returning(column: string | Literal): UpdateBuilder<Returning.Result[]>; | ||
returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): UpdateBuilder<R[]>; | ||
from(from: SelectBuilder.Callback): UpdateBuilder<Result>; | ||
@@ -20,0 +20,0 @@ where(where: Where.Expression): UpdateBuilder<Result>; |
@@ -35,4 +35,4 @@ "use strict"; | ||
} | ||
returning(column) { | ||
return this.withOption('returning', new Returning_1.Returning(column)); | ||
returning(...columns) { | ||
return this.withOption('returning', new Returning_1.Returning(columns)); | ||
} | ||
@@ -39,0 +39,0 @@ from(from) { |
@@ -20,2 +20,4 @@ export declare class ConnectionError extends Error { | ||
} | ||
export declare class TransactionAbortedError extends ConnectionError { | ||
} | ||
//# sourceMappingURL=errors.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.InvalidDataError = exports.SerializationFailureError = exports.UniqueViolationError = exports.ForeignKeyViolationError = exports.NotNullViolationError = exports.ConnectionError = void 0; | ||
exports.TransactionAbortedError = exports.InvalidDataError = exports.SerializationFailureError = exports.UniqueViolationError = exports.ForeignKeyViolationError = exports.NotNullViolationError = exports.ConnectionError = void 0; | ||
class ConnectionError extends Error { | ||
@@ -36,2 +36,5 @@ constructor(sql, parameters, previous) { | ||
exports.InvalidDataError = InvalidDataError; | ||
class TransactionAbortedError extends ConnectionError { | ||
} | ||
exports.TransactionAbortedError = TransactionAbortedError; | ||
//# sourceMappingURL=errors.js.map |
@@ -51,2 +51,4 @@ "use strict"; | ||
throw new errors_1.InvalidDataError(sql, parameters, error); | ||
case '25P02': | ||
throw new errors_1.TransactionAbortedError(sql, parameters, error); | ||
default: | ||
@@ -53,0 +55,0 @@ throw new errors_1.ConnectionError(sql, parameters, error); |
@@ -157,2 +157,31 @@ "use strict"; | ||
}); | ||
uvu_1.test('query builder: construct insert with on conflict update with where', async () => { | ||
await execute({ | ||
query: async (wrapper) => { | ||
const builder = wrapper | ||
.insertBuilder() | ||
.into('author') | ||
.values({ | ||
id: expr => expr.selectValue('123'), | ||
title: expr => expr.select('title'), | ||
}) | ||
.from(qb => { | ||
return qb.from('foo'); | ||
}) | ||
.returning('id') | ||
.onConflict(src_1.ConflictActionType.update, ['id'], { | ||
id: expr => expr.selectValue('123'), | ||
title: expr => expr.select('title'), | ||
}, expr => expr.raw('true')); | ||
await builder.execute(wrapper); | ||
}, | ||
sql: tags_1.SQL `insert into "public"."author" ("id", "title") | ||
select | ||
?, | ||
"title" | ||
from "public"."foo" | ||
on conflict ("id") do update set "id" = ?, "title" = "title" where true returning "id"`, | ||
parameters: ['123', '123'], | ||
}); | ||
}); | ||
uvu_1.test('query builder: construct insert with on conflict do nothing', async () => { | ||
@@ -246,3 +275,3 @@ await execute({ | ||
.where(cond => cond.compare(['data', 'a'], src_1.Operator.gte, 1)) | ||
.returning('xyz'); | ||
.returning('abc', 'xyz'); | ||
await qb.execute(wrapper); | ||
@@ -254,3 +283,3 @@ }, | ||
using "data" as "data" | ||
where "data"."a" >= ? returning "xyz"`, | ||
where "data"."a" >= ? returning "abc", "xyz"`, | ||
parameters: [1], | ||
@@ -257,0 +286,0 @@ }); |
{ | ||
"name": "@contember/database", | ||
"version": "0.10.0-alpha.2", | ||
"version": "0.10.0-alpha.3", | ||
"license": "Apache-2.0", | ||
@@ -11,6 +11,6 @@ "main": "dist/src/index.js", | ||
"dependencies": { | ||
"@contember/queryable": "^0.10.0-alpha.2" | ||
"@contember/queryable": "^0.10.0-alpha.3" | ||
}, | ||
"devDependencies": { | ||
"@contember/database-tester": "^0.10.0-alpha.2", | ||
"@contember/database-tester": "^0.10.0-alpha.3", | ||
"@types/node": "^14.6.4", | ||
@@ -17,0 +17,0 @@ "pg": "^8.5.0", |
@@ -214,2 +214,3 @@ import { assertNever, aliasLiteral, prependSchema, wrapIdentifier } from '../utils' | ||
.append(this.createSet(onConflict.values)) | ||
.append(onConflict.where.compile()) | ||
default: | ||
@@ -216,0 +217,0 @@ return assertNever(onConflict) |
@@ -40,4 +40,4 @@ import { Returning } from './internal/Returning' | ||
public returning(column: QueryBuilder.ColumnIdentifier | Literal): DeleteBuilder<Returning.Result[]> { | ||
return this.withOption('returning', new Returning(column)) as DeleteBuilder<Returning.Result[]> | ||
public returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): DeleteBuilder<R[]> { | ||
return this.withOption('returning', new Returning(columns)) as DeleteBuilder<any> | ||
} | ||
@@ -44,0 +44,0 @@ |
@@ -11,2 +11,3 @@ import { Returning } from './internal/Returning' | ||
import { createSubQueryLiteralFactory, SubQueryExpression } from './internal/Subqueries' | ||
import { Where } from './internal/Where' | ||
@@ -40,17 +41,25 @@ class InsertBuilder<Result extends InsertBuilder.InsertResult> implements With.Aware, QueryBuilder { | ||
public onConflict( | ||
type: ConflictActionType.update, | ||
action: ConflictActionType.update, | ||
target: InsertBuilder.ConflictTarget, | ||
values: QueryBuilder.Values, | ||
where?: Where.Expression, | ||
): InsertBuilder<Result> | ||
public onConflict(type: ConflictActionType.doNothing, target?: InsertBuilder.ConflictTarget): InsertBuilder<Result> | ||
public onConflict(action: ConflictActionType.doNothing, target?: InsertBuilder.ConflictTarget): InsertBuilder<Result> | ||
public onConflict( | ||
type: ConflictActionType, | ||
action: ConflictActionType, | ||
target?: InsertBuilder.ConflictTarget, | ||
values?: QueryBuilder.Values, | ||
where?: Where.Expression, | ||
): InsertBuilder<Result> { | ||
let conflictAction: InsertBuilder.ConflictAction | ||
if (type === ConflictActionType.update && values && target) { | ||
conflictAction = { type, values: resolveValues(values), target } | ||
} else if (type === ConflictActionType.doNothing) { | ||
conflictAction = { type, target } | ||
if (action === ConflictActionType.update && values && target) { | ||
const whereStm = new Where.Statement([]) | ||
conflictAction = { | ||
type: action, | ||
values: resolveValues(values), | ||
target, | ||
where: where ? whereStm.withWhere(where) : whereStm, | ||
} | ||
} else if (action === ConflictActionType.doNothing) { | ||
conflictAction = { type: action, target } | ||
} else { | ||
@@ -62,4 +71,4 @@ throw Error() | ||
public returning(column: string | Literal): InsertBuilder<Returning.Result[]> { | ||
return this.withOption('returning', new Returning(column)) as InsertBuilder<Returning.Result[]> | ||
public returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): InsertBuilder<R[]> { | ||
return this.withOption('returning', new Returning(columns)) as InsertBuilder<any> | ||
} | ||
@@ -127,3 +136,7 @@ | ||
| { type: ConflictActionType.doNothing; target?: ConflictTarget } | ||
| { type: ConflictActionType.update; values: QueryBuilder.ResolvedValues; target: ConflictTarget } | ||
| (Where.Options & { | ||
type: ConflictActionType.update | ||
values: QueryBuilder.ResolvedValues | ||
target: ConflictTarget | ||
}) | ||
@@ -130,0 +143,0 @@ export type IndexColumns = string[] |
@@ -7,12 +7,10 @@ import { QueryBuilder } from '../' | ||
class Returning { | ||
constructor(private readonly column: QueryBuilder.ColumnIdentifier | Literal | null = null) {} | ||
constructor(private readonly columns: (QueryBuilder.ColumnIdentifier | Literal)[] = []) {} | ||
public compile(): Literal { | ||
if (this.column === null) { | ||
if (this.columns.length === 0) { | ||
return new Literal('') | ||
} | ||
if (this.column instanceof Literal) { | ||
return new Literal(' returning ').append(this.column) | ||
} | ||
return new Literal(' returning ' + toFqnWrap(this.column)) | ||
const columns = this.columns.map(it => (it instanceof Literal ? it : new Literal(toFqnWrap(it)))) | ||
return new Literal(' returning ').appendAll(columns, ', ') | ||
} | ||
@@ -23,10 +21,6 @@ | ||
): ProcessedResult { | ||
const returningColumn = this.column | ||
if (returningColumn) { | ||
return (typeof returningColumn === 'string' | ||
? result.rows.map(it => it[returningColumn]) | ||
: result.rows) as ProcessedResult | ||
} else { | ||
if (this.columns.length === 0) { | ||
return result.rowCount as ProcessedResult | ||
} | ||
return result.rows as ProcessedResult | ||
} | ||
@@ -37,8 +31,8 @@ } | ||
export interface Aware { | ||
returning(column: QueryBuilder.ColumnIdentifier | Literal): any | ||
returning(...columns: ReturningColumn[]): any | ||
} | ||
export type Result = number | string | ||
export type Result = Record<string, any> | ||
export type ReturningColumn = QueryBuilder.ColumnIdentifier | Literal | ||
} | ||
export { Returning } |
@@ -173,3 +173,3 @@ import { With } from './internal/With' | ||
export type Result = { [columnName: string]: any } | ||
export type Result = Record<string, any> | ||
@@ -176,0 +176,0 @@ export type Options = Readonly< |
@@ -38,4 +38,4 @@ import { Returning } from './internal/Returning' | ||
public returning(column: string | Literal): UpdateBuilder<Returning.Result[]> { | ||
return this.withOption('returning', new Returning(column)) as UpdateBuilder<Returning.Result[]> | ||
public returning<R = Returning.Result>(...columns: Returning.ReturningColumn[]): UpdateBuilder<R[]> { | ||
return this.withOption('returning', new Returning(columns)) as UpdateBuilder<any> | ||
} | ||
@@ -42,0 +42,0 @@ |
@@ -28,1 +28,3 @@ export class ConnectionError extends Error { | ||
export class InvalidDataError extends ConnectionError {} | ||
export class TransactionAbortedError extends ConnectionError {} |
@@ -10,2 +10,3 @@ import { ClientBase } from 'pg' | ||
SerializationFailureError, | ||
TransactionAbortedError, | ||
UniqueViolationError, | ||
@@ -71,2 +72,4 @@ } from './errors' | ||
throw new InvalidDataError(sql, parameters, error) | ||
case '25P02': | ||
throw new TransactionAbortedError(sql, parameters, error) | ||
default: | ||
@@ -73,0 +76,0 @@ throw new ConnectionError(sql, parameters, error) |
@@ -181,2 +181,37 @@ import { Client, ConflictActionType, LimitByGroupWrapper, LockType, Operator } from '../../../src' | ||
test('query builder: construct insert with on conflict update with where', async () => { | ||
await execute({ | ||
query: async wrapper => { | ||
const builder = wrapper | ||
.insertBuilder() | ||
.into('author') | ||
.values({ | ||
id: expr => expr.selectValue('123'), | ||
title: expr => expr.select('title'), | ||
}) | ||
.from(qb => { | ||
return qb.from('foo') | ||
}) | ||
.returning('id') | ||
.onConflict( | ||
ConflictActionType.update, | ||
['id'], | ||
{ | ||
id: expr => expr.selectValue('123'), | ||
title: expr => expr.select('title'), | ||
}, | ||
expr => expr.raw('true'), | ||
) | ||
await builder.execute(wrapper) | ||
}, | ||
sql: SQL`insert into "public"."author" ("id", "title") | ||
select | ||
?, | ||
"title" | ||
from "public"."foo" | ||
on conflict ("id") do update set "id" = ?, "title" = "title" where true returning "id"`, | ||
parameters: ['123', '123'], | ||
}) | ||
}) | ||
test('query builder: construct insert with on conflict do nothing', async () => { | ||
@@ -280,3 +315,3 @@ await execute({ | ||
.where(cond => cond.compare(['data', 'a'], Operator.gte, 1)) | ||
.returning('xyz') | ||
.returning('abc', 'xyz') | ||
await qb.execute(wrapper) | ||
@@ -288,3 +323,3 @@ }, | ||
using "data" as "data" | ||
where "data"."a" >= ? returning "xyz"`, | ||
where "data"."a" >= ? returning "abc", "xyz"`, | ||
parameters: [1], | ||
@@ -291,0 +326,0 @@ }) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
773376
5088