Setup eslint and enforce rules
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2021-06-02 22:36:25 -05:00
parent 82e7a1f299
commit 1d5056b753
149 changed files with 6104 additions and 3114 deletions

View File

@@ -1,19 +1,19 @@
import {Inject} from "../../di";
import {DatabaseService} from "../DatabaseService";
import {Inject} from '../../di'
import {DatabaseService} from '../DatabaseService'
import {
Constraint, ConstraintConnectionOperator,
ConstraintOperator,
OrderDirection,
OrderStatement, QueryResult,
QuerySource,
SpecifiedField
} from "../types";
import {Connection} from "../connection/Connection";
import {deepCopy, ErrorWithContext} from "../../util";
import {EscapeValue, QuerySafeValue, raw} from "../dialect/SQLDialect";
import {ResultCollection} from "./result/ResultCollection";
import {AbstractResultIterable} from "./result/AbstractResultIterable";
import {AppClass} from "../../lifecycle/AppClass";
SpecifiedField,
} from '../types'
import {Connection} from '../connection/Connection'
import {deepCopy, ErrorWithContext} from '../../util'
import {EscapeValue, QuerySafeValue, raw} from '../dialect/SQLDialect'
import {ResultCollection} from './result/ResultCollection'
import {AbstractResultIterable} from './result/AbstractResultIterable'
import {AppClass} from '../../lifecycle/AppClass'
/**
* Type alias for a function that applies some constraints to a builder group.
@@ -35,25 +35,25 @@ export abstract class AbstractBuilder<T> extends AppClass {
protected source?: QuerySource
/** The fields to query from the table. */
protected _fields: SpecifiedField[] = []
protected registeredFields: SpecifiedField[] = []
/** The number of records to skip before the result set. */
protected _skip?: number
protected registeredSkip?: number
/** The max number of records to include in the result set. */
protected _take?: number
protected registeredTake?: number
/** If true, the query should refer to distinct records. */
protected _distinct: boolean = false
protected registeredDistinct = false
/** Array of SQL group-by clauses. */
protected _groupings: string[] = []
protected registeredGroupings: string[] = []
/** Array of SQL order-by clauses. */
protected _orders: OrderStatement[] = []
protected registeredOrders: OrderStatement[] = []
/** The connection on which the query should be executed. */
protected _connection?: Connection
protected registeredConnection?: Connection
/**
* Create a new, empty, instance of the current builder.
@@ -73,50 +73,53 @@ export abstract class AbstractBuilder<T> extends AppClass {
bldr.constraints = deepCopy(this.constraints)
bldr.source = deepCopy(this.source)
bldr._fields = deepCopy(this._fields)
bldr._skip = deepCopy(this._skip)
bldr._take = deepCopy(this._take)
bldr._distinct = deepCopy(this._distinct)
bldr._groupings = deepCopy(this._groupings)
bldr._orders = deepCopy(this._orders)
bldr._connection = this._connection
bldr.registeredFields = deepCopy(this.registeredFields)
bldr.registeredSkip = deepCopy(this.registeredSkip)
bldr.registeredTake = deepCopy(this.registeredTake)
bldr.registeredDistinct = deepCopy(this.registeredDistinct)
bldr.registeredGroupings = deepCopy(this.registeredGroupings)
bldr.registeredOrders = deepCopy(this.registeredOrders)
bldr.registeredConnection = this.registeredConnection
return bldr
}
/** Get the constraints applied to this query. */
public get appliedConstraints() {
public get appliedConstraints(): Constraint[] {
return deepCopy(this.constraints)
}
/** Get the fields that should be included in this query. */
public get appliedFields() {
return deepCopy(this._fields)
public get appliedFields(): SpecifiedField[] {
return deepCopy(this.registeredFields)
}
/** Get the skip/take values of this query. */
public get appliedPagination() {
return { skip: this._skip, take: this._take }
public get appliedPagination(): { skip: number | undefined, take: number | undefined} {
return { skip: this.registeredSkip,
take: this.registeredTake }
}
/** True if the query should be DISTINCT */
public get appliedDistinction() {
return this._distinct
public get appliedDistinction(): boolean {
return this.registeredDistinct
}
/** Get the SQL group-by clauses applied to this query. */
public get appliedGroupings() {
return deepCopy(this._groupings)
public get appliedGroupings(): string[] {
return deepCopy(this.registeredGroupings)
}
/** Get the SQL order-by clauses applied to this query. */
public get appliedOrder() {
return deepCopy(this._orders)
public get appliedOrder(): OrderStatement[] {
return deepCopy(this.registeredOrders)
}
/** Get the source table for this query. */
public get querySource() {
if ( this.source ) return deepCopy(this.source)
public get querySource(): QuerySource | undefined {
if ( this.source ) {
return deepCopy(this.source)
}
}
/**
@@ -124,9 +127,10 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param table
* @param alias
*/
from(table: string, alias?: string) {
from(table: string, alias?: string): this {
if ( alias ) {
this.source = { table, alias }
this.source = { table,
alias }
} else {
this.source = table
}
@@ -138,7 +142,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param table
* @param alias
*/
table(table: string, alias?: string) {
table(table: string, alias?: string): this {
return this.from(table, alias)
}
@@ -147,11 +151,12 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param alias
*/
field(field: string | QuerySafeValue, alias?: string) {
field(field: string | QuerySafeValue, alias?: string): this {
if ( alias ) {
this._fields.push({ field, alias })
this.registeredFields.push({ field,
alias })
} else {
this._fields.push(field)
this.registeredFields.push(field)
}
return this
}
@@ -161,7 +166,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param fields
*/
fields(...fields: SpecifiedField[]): this {
this._fields = [...this._fields, ...fields]
this.registeredFields = [...this.registeredFields, ...fields]
return this
}
@@ -184,8 +189,8 @@ export abstract class AbstractBuilder<T> extends AppClass {
/**
* Remove all selected fields from this query.
*/
clearFields() {
this._fields = []
clearFields(): this {
this.registeredFields = []
return this
}
@@ -195,7 +200,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
where(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue) {
where(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue): this {
this.createConstraint('AND', field, operator, operand)
return this
}
@@ -206,7 +211,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
whereRaw(field: string, operator: ConstraintOperator, operand: string) {
whereRaw(field: string, operator: ConstraintOperator, operand: string): this {
this.createConstraint('AND', field, operator, raw(operand))
return this
}
@@ -217,7 +222,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
whereNot(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue) {
whereNot(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue): this {
this.createConstraint('AND NOT', field, operator, operand)
return this
}
@@ -228,7 +233,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
orWhere(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue) {
orWhere(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue): this {
this.createConstraint('OR', field, operator, operand)
return this
}
@@ -239,7 +244,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
orWhereNot(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue) {
orWhereNot(field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: EscapeValue): this {
this.createConstraint('OR NOT', field, operator, operand)
return this
}
@@ -250,7 +255,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operator
* @param operand
*/
orWhereRaw(field: string, operator: ConstraintOperator, operand: string) {
orWhereRaw(field: string, operator: ConstraintOperator, operand: string): this {
this.createConstraint('OR', field, operator, raw(operand))
return this
}
@@ -260,7 +265,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param values
*/
whereIn(field: string, values: EscapeValue) {
whereIn(field: string, values: EscapeValue): this {
this.constraints.push({
field,
operator: 'IN',
@@ -275,7 +280,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param values
*/
whereNotIn(field: string, values: EscapeValue) {
whereNotIn(field: string, values: EscapeValue): this {
this.constraints.push({
field,
operator: 'NOT IN',
@@ -290,12 +295,12 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param values
*/
orWhereIn(field: string, values: EscapeValue) {
orWhereIn(field: string, values: EscapeValue): this {
this.constraints.push({
field,
operator: 'IN',
operand: values,
preop: 'OR'
preop: 'OR',
})
return this
}
@@ -305,12 +310,12 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param values
*/
orWhereNotIn(field: string, values: EscapeValue) {
orWhereNotIn(field: string, values: EscapeValue): this {
this.constraints.push({
field,
operator: 'NOT IN',
operand: values,
preop: 'OR'
preop: 'OR',
})
return this
}
@@ -319,8 +324,8 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Limit the query to a maximum number of rows.
* @param rows
*/
limit(rows: number) {
this._take = rows
limit(rows: number): this {
this.registeredTake = rows
return this
}
@@ -328,7 +333,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Alias of `limit()`.
* @param rows
*/
take(rows: number) {
take(rows: number): this {
return this.limit(rows)
}
@@ -336,8 +341,8 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Skip the first `rows` many rows in the result set.
* @param rows
*/
skip(rows: number) {
this._skip = rows
skip(rows: number): this {
this.registeredSkip = rows
return this
}
@@ -345,23 +350,23 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Alias of `skip()`.
* @param rows
*/
offset(rows: number) {
offset(rows: number): this {
return this.skip(rows)
}
/**
* Make the query return only distinct rows.
*/
distinct() {
this._distinct = true
distinct(): this {
this.registeredDistinct = true
return this
}
/**
* Allow the query to return non-distinct rows. (Undoes `distinct()`.)
*/
notDistinct() {
this._distinct = false
notDistinct(): this {
this.registeredDistinct = false
return this
}
@@ -371,7 +376,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param pageNum
* @param pageSize
*/
page(pageNum: number = 1, pageSize: number = 20) {
page(pageNum = 1, pageSize = 20): this {
this.skip(pageSize * (pageNum - 1))
this.take(pageSize)
return this
@@ -381,8 +386,8 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Apply one or more GROUP-BY clauses to the query.
* @param groupings
*/
groupBy(...groupings: string[]) {
this._groupings = groupings
groupBy(...groupings: string[]): this {
this.registeredGroupings = groupings
return this
}
@@ -391,8 +396,9 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param field
* @param direction
*/
orderBy(field: string, direction: OrderDirection = 'ASC') {
this._orders.push({ field, direction })
orderBy(field: string, direction: OrderDirection = 'ASC'): this {
this.registeredOrders.push({ field,
direction })
return this
}
@@ -400,7 +406,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Order the query by the given field, ascending.
* @param field
*/
orderByAscending(field: string) {
orderByAscending(field: string): this {
return this.orderBy(field, 'ASC')
}
@@ -408,7 +414,7 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Order the query by the given field, descending.
* @param field
*/
orderByDescending(field: string) {
orderByDescending(field: string): this {
return this.orderBy(field, 'DESC')
}
@@ -416,11 +422,11 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Specify the connection name or instance to execute the query on.
* @param nameOrInstance
*/
connection(nameOrInstance: string | Connection) {
connection(nameOrInstance: string | Connection): this {
if ( nameOrInstance instanceof Connection ) {
this._connection = nameOrInstance
this.registeredConnection = nameOrInstance
} else {
this._connection = this.databaseService.get(nameOrInstance)
this.registeredConnection = this.databaseService.get(nameOrInstance)
}
return this
@@ -430,11 +436,11 @@ export abstract class AbstractBuilder<T> extends AppClass {
* Get a result iterable for the rows of this query.
*/
iterator(): AbstractResultIterable<T> {
if ( !this._connection ) {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to fetch iterator for query.`)
}
return this.getResultIterable();
return this.getResultIterable()
}
/**
@@ -469,12 +475,12 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param data
*/
async update(data: {[key: string]: EscapeValue}): Promise<QueryResult> {
if ( !this._connection ) {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to execute update query.`)
}
const query = this._connection.dialect().renderUpdate(this, data)
return this._connection.query(query)
const query = this.registeredConnection.dialect().renderUpdate(this, data)
return this.registeredConnection.query(query)
}
/**
@@ -495,12 +501,12 @@ export abstract class AbstractBuilder<T> extends AppClass {
*
*/
async delete(): Promise<QueryResult> {
if ( !this._connection ) {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to execute update query.`)
}
const query = this._connection.dialect().renderDelete(this)
return this._connection.query(query)
const query = this.registeredConnection.dialect().renderDelete(this)
return this.registeredConnection.query(query)
}
/**
@@ -527,26 +533,26 @@ export abstract class AbstractBuilder<T> extends AppClass {
*
* @param rowOrRows
*/
async insert(rowOrRows: {[key: string]: EscapeValue}|{[key: string]: EscapeValue}[]) {
if ( !this._connection ) {
async insert(rowOrRows: {[key: string]: EscapeValue}|{[key: string]: EscapeValue}[]): Promise<QueryResult> {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to execute update query.`)
}
const query = this._connection.dialect().renderInsert(this, rowOrRows)
return this._connection.query(query)
const query = this.registeredConnection.dialect().renderInsert(this, rowOrRows)
return this.registeredConnection.query(query)
}
/**
* Returns true if at least one row matches the current query.
*/
async exists() {
if ( !this._connection ) {
async exists(): Promise<boolean> {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to execute update query.`)
}
const query = this._connection.dialect().renderExistential(this)
const result = await this._connection.query(query)
return !!result.rows.first()
const query = this.registeredConnection.dialect().renderExistential(this)
const result = await this.registeredConnection.query(query)
return Boolean(result.rows.first())
}
/**
@@ -557,17 +563,20 @@ export abstract class AbstractBuilder<T> extends AppClass {
* @param operand
* @private
*/
private createConstraint(preop: ConstraintConnectionOperator, field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: any) {
private createConstraint(preop: ConstraintConnectionOperator, field: string | ConstraintGroupClosure<T>, operator?: ConstraintOperator, operand?: any): void {
if ( typeof field === 'function' ) {
const builder = this.getNewInstance()
field(builder)
this.constraints.push({
preop,
items: builder.appliedConstraints
items: builder.appliedConstraints,
})
} else if ( field && operator && typeof operand !== 'undefined' ) {
this.constraints.push({
field, operator, operand, preop, // FIXME escape operand
field,
operator,
operand,
preop, // FIXME escape operand
})
}
}

View File

@@ -1,23 +1,23 @@
import {ErrorWithContext} from "../../util";
import {Container} from "../../di";
import {ResultIterable} from "./result/ResultIterable";
import {QueryRow} from "../types";
import {AbstractBuilder} from "./AbstractBuilder";
import {AbstractResultIterable} from "./result/AbstractResultIterable";
import {ErrorWithContext} from '../../util'
import {Container} from '../../di'
import {ResultIterable} from './result/ResultIterable'
import {QueryRow} from '../types'
import {AbstractBuilder} from './AbstractBuilder'
import {AbstractResultIterable} from './result/AbstractResultIterable'
/**
* Implementation of the abstract builder class that returns simple QueryRow objects.
*/
export class Builder extends AbstractBuilder<QueryRow> {
public getNewInstance(): AbstractBuilder<QueryRow> {
return Container.getContainer().make<Builder>(Builder);
return Container.getContainer().make<Builder>(Builder)
}
public getResultIterable(): AbstractResultIterable<QueryRow> {
if ( !this._connection ) {
if ( !this.registeredConnection ) {
throw new ErrorWithContext(`No connection specified to fetch iterator for query.`)
}
return Container.getContainer().make<ResultIterable>(ResultIterable, this, this._connection)
return Container.getContainer().make<ResultIterable>(ResultIterable, this, this.registeredConnection)
}
}

View File

@@ -1,6 +1,6 @@
import {Collection, Iterable} from "../../../util"
import {Connection} from "../../connection/Connection";
import {AbstractBuilder} from "../AbstractBuilder";
import {Collection, Iterable} from '../../../util'
import {Connection} from '../../connection/Connection'
import {AbstractBuilder} from '../AbstractBuilder'
/**
* Base Iterable class that generates the results of a Builder query.
@@ -12,7 +12,9 @@ export abstract class AbstractResultIterable<T> extends Iterable<T> {
/** The connection on which to execute the builder. */
public readonly connection: Connection,
) { super() }
) {
super()
}
/**
* Get the SQL string for the SELECT query for this iterable.

View File

@@ -1,5 +1,5 @@
import {AsyncCollection} from "../../../util";
import {AbstractResultIterable} from "./AbstractResultIterable";
import {AsyncCollection} from '../../../util'
import {AbstractResultIterable} from './AbstractResultIterable'
/**
* Async collection class that iterates AbstractResultIterables in chunks.
@@ -10,7 +10,7 @@ export class ResultCollection<T> extends AsyncCollection<T> {
iterator: AbstractResultIterable<T>,
/** The max number of records to request per-query, by default. */
chunkSize: number = 500
chunkSize = 500,
) {
super(iterator, chunkSize)
}

View File

@@ -1,8 +1,8 @@
import {QueryRow} from "../../types";
import {Builder} from "../Builder";
import {Connection} from "../../connection/Connection";
import {AbstractResultIterable} from "./AbstractResultIterable";
import {Collection} from "../../../util";
import {QueryRow} from '../../types'
import {Builder} from '../Builder'
import {Connection} from '../../connection/Connection'
import {AbstractResultIterable} from './AbstractResultIterable'
import {Collection} from '../../../util'
/**
* Implementation of AbstractResultIterable that yields simple QueryRow instances (objects).
@@ -11,9 +11,11 @@ export class ResultIterable extends AbstractResultIterable<QueryRow> {
constructor(
public readonly builder: Builder,
public readonly connection: Connection,
) { super(builder, connection) }
) {
super(builder, connection)
}
public get selectSQL() {
public get selectSQL(): string {
return this.connection.dialect().renderSelect(this.builder)
}
@@ -27,7 +29,7 @@ export class ResultIterable extends AbstractResultIterable<QueryRow> {
return (await this.connection.query(query)).rows
}
async count() {
async count(): Promise<number> {
const query = this.connection.dialect().renderCount(this.selectSQL)
const result = (await this.connection.query(query)).rows.first()
return result?.extollo_render_count ?? 0
@@ -38,7 +40,7 @@ export class ResultIterable extends AbstractResultIterable<QueryRow> {
return result.rows
}
clone() {
clone(): ResultIterable {
return new ResultIterable(this.builder, this.connection)
}
}