-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Guillaume Robin
committed
Jul 7, 2024
1 parent
412b554
commit 93422db
Showing
6 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { nany } from "../ninja.ts"; | ||
|
||
export class InternalOptions { | ||
skipUndefined: boolean; | ||
keepImplicitJoinProps: boolean; | ||
returnImmediatelyValue?: nany; | ||
isInternalQuery: boolean; | ||
debug: boolean; | ||
schema?: nany; | ||
|
||
constructor() { | ||
this.skipUndefined = false; | ||
this.keepImplicitJoinProps = false; | ||
this.returnImmediatelyValue = undefined; | ||
this.isInternalQuery = false; | ||
this.debug = false; | ||
this.schema = undefined; | ||
} | ||
|
||
clone() { | ||
const copy = new InternalOptions(); | ||
|
||
copy.skipUndefined = this.skipUndefined; | ||
copy.keepImplicitJoinProps = this.keepImplicitJoinProps; | ||
copy.returnImmediatelyValue = this.returnImmediatelyValue; | ||
copy.isInternalQuery = this.isInternalQuery; | ||
copy.debug = this.debug; | ||
copy.schema = this.schema; | ||
|
||
return copy; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { nany } from "../ninja.ts"; | ||
import { QueryBuilderContextBase } from "./QueryBuilderContextBase.ts"; | ||
|
||
export class QueryBuilderContext extends QueryBuilderContextBase { | ||
runBefore: nany[]; | ||
runAfter: nany[]; | ||
onBuild: nany[]; | ||
|
||
constructor(builder?: nany) { | ||
super(builder); | ||
|
||
this.runBefore = []; | ||
this.runAfter = []; | ||
this.onBuild = []; | ||
} | ||
|
||
clone() { | ||
const ctx = new QueryBuilderContext(); | ||
super.cloneInto(ctx); | ||
|
||
ctx.runBefore = this.runBefore.slice(); | ||
ctx.runAfter = this.runAfter.slice(); | ||
ctx.onBuild = this.onBuild.slice(); | ||
|
||
return ctx; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { Knex } from "knex"; | ||
import { nany } from "../ninja.ts"; | ||
import { InternalOptions } from "./InternalOptions.ts"; | ||
import { QueryBuilderUserContext } from "./QueryBuilderUserContext.ts"; | ||
|
||
export class QueryBuilderContextBase { | ||
userContext?: QueryBuilderUserContext; | ||
options?: InternalOptions; | ||
knex?: Knex; | ||
aliasMap?: Map<nany, nany>; | ||
tableMap?: Map<nany, nany>; | ||
|
||
constructor(builder?: nany) { | ||
this.userContext = builder | ||
? new QueryBuilderUserContext(builder) | ||
: undefined; | ||
this.options = builder ? new InternalOptions() : undefined; | ||
} | ||
|
||
static get InternalOptions() { | ||
return InternalOptions; | ||
} | ||
|
||
cloneInto( | ||
newContext: QueryBuilderContextBase, | ||
): void { | ||
newContext.userContext = this.userContext; | ||
newContext.options = this.options?.clone(); | ||
newContext.knex = this.knex; | ||
newContext.aliasMap = this.aliasMap; | ||
newContext.tableMap = this.tableMap; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { nany } from "../ninja.ts"; | ||
import { Knex } from "knex"; | ||
|
||
export class QueryBuilderUserContext { | ||
#builder: nany; | ||
|
||
constructor(builder: nany) { | ||
this.#builder = builder; | ||
} | ||
|
||
get transaction(): Knex { | ||
return this.#builder.knex(); | ||
} | ||
|
||
newFromObject(builder: nany, obj: unknown): QueryBuilderUserContext { | ||
const ctx = new QueryBuilderUserContext(builder); | ||
Object.assign(ctx, obj); | ||
return ctx; | ||
} | ||
|
||
newMerge(builder: nany, obj: unknown): QueryBuilderUserContext { | ||
const ctx = new QueryBuilderUserContext(builder); | ||
Object.assign(ctx, this, obj); | ||
return ctx; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { isPlainObject } from "../utils/object.ts"; | ||
import { buildArg } from "../utils/build.ts"; | ||
import { nany } from "../ninja.ts"; | ||
import { Knex } from "knex"; | ||
|
||
export interface BuilderWithKnex { | ||
knex(): Knex; | ||
} | ||
|
||
export class RawBuilder { | ||
#sql: string; | ||
#args: nany[]; | ||
#as?: string; | ||
|
||
constructor(sql: string, args: nany[]) { | ||
this.#sql = `${sql}`; | ||
this.#args = args; | ||
} | ||
|
||
get alias(): string | undefined { | ||
return this.#as; | ||
} | ||
|
||
as(as: string) { | ||
this.#as = as; | ||
return this; | ||
} | ||
|
||
toKnexRaw(builder: BuilderWithKnex): Knex.Raw { | ||
let args = null; | ||
let sql = this.#sql; | ||
|
||
if (this.#args.length === 1 && isPlainObject(this.#args[0])) { | ||
args = buildObject(this.#args[0], builder); | ||
|
||
if (this.#as) { | ||
args.__alias__ = this.#as; | ||
sql += " as :__alias__:"; | ||
} | ||
} else { | ||
args = buildArray(this.#args, builder); | ||
|
||
if (this.#as) { | ||
args.push(this.#as); | ||
sql += " as ??"; | ||
} | ||
} | ||
|
||
return builder.knex().raw(sql, args); | ||
} | ||
} | ||
|
||
export function buildArray(arr: nany[], builder: nany) { | ||
return arr.map((it) => buildArg(it, builder)); | ||
} | ||
|
||
export function buildObject(obj: nany, builder: nany) { | ||
return Object.keys(obj).reduce((args, key) => { | ||
args[key] = buildArg(obj[key], builder); | ||
return args; | ||
}, {} as nany); | ||
} | ||
|
||
export function normalizeRawArgs(argsIn: [string, ...nany[]]) { | ||
const [sql, ...restArgs] = argsIn; | ||
|
||
if (restArgs.length === 1 && Array.isArray(restArgs[0])) { | ||
return { | ||
sql, | ||
args: restArgs[0], | ||
}; | ||
} else { | ||
return { | ||
sql, | ||
args: restArgs, | ||
}; | ||
} | ||
} | ||
|
||
export function raw(...argsIn: [string, ...nany[]]) { | ||
const { sql, args } = normalizeRawArgs(argsIn); | ||
return new RawBuilder(sql, args); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Knex } from "knex"; | ||
import { nany } from "../ninja.ts"; | ||
import { isFunction, isObject } from "./object.ts"; | ||
|
||
export interface ToKnexRaw { | ||
toKnexRaw(builder: nany): Knex.Raw; | ||
} | ||
export type Arg = number | string | boolean | ToKnexRaw | nany; // TODO: add QueryBuilderBase type | ||
|
||
// deno-lint-ignore no-explicit-any | ||
function isToKnexRaw(arg: any): arg is ToKnexRaw { | ||
return isFunction(arg.toKnexRaw); | ||
} | ||
|
||
export function buildArg(arg: Arg, builder: nany) { | ||
if (!isObject(arg)) { | ||
return arg; | ||
} | ||
|
||
if (isToKnexRaw(arg)) { | ||
return arg.toKnexRaw(builder); | ||
} else if (arg.isObjectionQueryBuilderBase === true) { // TODO: replace with instance check | ||
return arg.subqueryOf(builder).toKnexQuery(); | ||
} else { | ||
return arg; | ||
} | ||
} |