Skip to content

Commit

Permalink
Add work for query builders
Browse files Browse the repository at this point in the history
  • Loading branch information
Guillaume Robin committed Jul 7, 2024
1 parent 412b554 commit 93422db
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/queryBuilder/InternalOptions.ts
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;
}
}
27 changes: 27 additions & 0 deletions src/queryBuilder/QueryBuilderContext.ts
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;
}
}
33 changes: 33 additions & 0 deletions src/queryBuilder/QueryBuilderContextBase.ts
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;
}
}
26 changes: 26 additions & 0 deletions src/queryBuilder/QueryBuilderUserContext.ts
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;
}
}
83 changes: 83 additions & 0 deletions src/queryBuilder/RawBuilder.ts
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);
}
27 changes: 27 additions & 0 deletions src/utils/build.ts
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;
}
}

0 comments on commit 93422db

Please sign in to comment.