Commit 6e0d3159 authored by William Naslund's avatar William Naslund

Finished condition implementation

parent 7ac36b1a
import { DBCompoundCondition } from "./compound-condition";
import { DBModel } from "../model";
/** A condition where all contained conditions must be met */
export class DBAnd extends DBCompoundCondition {
export class DBAnd<T extends DBModel> extends DBCompoundCondition<T> {
joiningSQL() {
return 'AND';
......
import { DBCondition } from "./db-condition";
import { DBModel } from "../model";
/** A condition that combines other conditions */
export abstract class DBCompoundCondition implements DBCondition {
export abstract class DBCompoundCondition<T extends DBModel> implements DBCondition<T> {
/** The parameters from each condition */
private conditionParameters: any[];
constructor(
protected readonly conditions: DBCondition[]
protected readonly conditions: DBCondition<T>[]
) { }
/** Returns the SQL to be placed in between each condition */
......
import { DBModel } from "../model";
/** Base interface for classes that are used to filter based on a certain condition */
export interface DBCondition {
export interface DBCondition<T extends DBModel> {
/** Returns the SQL for this condition, to be used in a the WHERE section of a SELECT */
sql(): string;
......
import { DBCondition } from "./db-condition";
import { DBModel, DBModelConstructor } from "../model";
import { DBFieldInformation } from "../decorators";
import { getFieldInformation } from "../internal/meta-keys";
/** A condition where a value is exactly equal */
export class DBEquals implements DBCondition {
export class DBEquals<T extends DBModel> implements DBCondition<T> {
private readonly field: DBFieldInformation;
constructor(
model: DBModelConstructor<T>, propertyKey: keyof T,
private readonly value: any
) { }
) {
this.field = getFieldInformation(model, propertyKey);
}
sql() {
return `= $1`;
return `${String(this.field.name)} = $1`;
}
parameters() {
......
import { DBCondition } from "./db-condition";
import { DBModel, DBModelConstructor } from "../model";
import { getFieldInformation } from "../internal/meta-keys";
import { DBFieldInformation } from "../decorators";
/** A condition where a value is in a collection of values */
export class DBIn implements DBCondition {
export class DBIn<T extends DBModel> implements DBCondition<T> {
/** The values for the condition */
private readonly values: any[];
constructor(values: any[]);
constructor(iterable: IterableIterator<any>);
constructor(values: any) {
/** The name of the field being queried */
private readonly field: DBFieldInformation;
constructor(model: DBModelConstructor<T>, propertyKey: keyof T, values: any[]);
constructor(model: DBModelConstructor<T>, propertyKey: keyof T, iterable: IterableIterator<any>);
constructor(model: DBModelConstructor<T>, propertyKey: keyof T, values: any) {
if(values == null) {
this.values = [];
}
......@@ -24,10 +30,13 @@ export class DBIn implements DBCondition {
else {
throw new Error(`Unsupported argument for DBIn: ${values}`);
}
this.field = getFieldInformation(model, propertyKey);
}
sql() {
return `IN $1`;
return `${this.field.name} IN $1`;
}
parameters() {
......
import { DBCompoundCondition } from "./compound-condition";
import { DBModel } from "../model";
/** A condition where any of the containing conditions is met */
export class DBOr extends DBCompoundCondition {
export class DBOr<T extends DBModel> extends DBCompoundCondition<T> {
joiningSQL() {
return 'OR';
......
import { DBModelConstructor } from "../model";
import { DBModelConstructor, DBModel } from "../model";
import { DBTableInformation, DBFieldInformation, DBLookupInformation } from "../decorators";
/** Identifier for table information */
......@@ -64,8 +64,8 @@ export function getTableFields(modelType: DBModelConstructor<any>): DBFieldInfor
}
/** Loads the information for a field */
export function getFieldInformation(modelType: DBModelConstructor<any>, propertyKey: string | symbol): DBFieldInformation {
return Reflect.getMetadata(FIELD_INFO, modelType, propertyKey);
export function getFieldInformation<T extends DBModel>(modelType: DBModelConstructor<T>, propertyKey: keyof T): DBFieldInformation {
return Reflect.getMetadata(FIELD_INFO, modelType, propertyKey as any);
}
/** Loads the parent lookups on the child table */
......
......@@ -46,7 +46,7 @@ export class DBModel {
const db = this.getDB();
const tableInfo = getTableInformation(this.constructor);
const id = this[tableInfo.options.id];
const idInfo = getFieldInformation(this.constructor, tableInfo.options.id);
const idInfo = getFieldInformation(this.constructor, tableInfo.options.id as any);
if(id == null) {
throw new Error(`Attempt to update a model that has no id`);
......
......@@ -4,11 +4,12 @@ import { Database } from './database';
import { getTableFields, TABLE_PARENT_LOOKUPS, getFieldInformation, LOOKUP_INFO } from './internal/meta-keys';
import { DBLookupInformation, DBTableInformation } from './decorators';
import { DBQueryResponse } from "./adapter";
import { DBCondition } from "./conditions";
export class DBQuery<T extends DBModel> {
/** The base table that is being selected */
private readonly req: DBQueryRequest;
private readonly req: DBQueryRequest<T>;
/** The property names of the fields to select */
private fieldPropertyNames: any[] = [];
......@@ -20,6 +21,7 @@ export class DBQuery<T extends DBModel> {
this.req = {
model: model,
fields: [ ],
condition: null,
parents: { },
children: { }
};
......@@ -84,6 +86,12 @@ export class DBQuery<T extends DBModel> {
return this;
}
/** Adds the condition to this query */
public where(condition: DBCondition<T>): this {
this.req.condition = condition;
return this;
}
/** Adds a related record to be queried */
public parent<P extends DBModel>(model: DBModelConstructor<P>, lookupProperty: keyof T, ...fields: (keyof P)[]): DBQueryParent<P> {
const parentLookup = new DBQueryParent(model, lookupProperty, fields);
......@@ -134,6 +142,7 @@ export class DBQuery<T extends DBModel> {
export interface DBQueryRequest<T extends DBModel = any> {
model: DBModelConstructor<T>;
fields: any[];
condition: DBCondition<T>;
parents: { [name: string]: DBQueryParent<any>; }
children: { [name: string]: DBQueryRequest; }
}
......@@ -161,6 +170,7 @@ export class DBQueryParent<T extends DBModel> {
this.req = {
model: model,
fields: fieldsToSelect,
condition: null,
parents: { },
children: { }
};
......
......@@ -2,6 +2,7 @@ import { getTestAdapter } from "./db/adapter";
import { Account } from "./db/account";
import { Database } from "@swirl/db";
import { Contact } from "./db/contact";
import { Organization } from "./db/org";
describe('Database', function() {
......@@ -13,11 +14,11 @@ describe('Database', function() {
});
it('Creates the schema for a brand new database', async () => {
await db.register(Account).register(Contact).migrate();
await db.register(Account).register(Contact).register(Organization).migrate();
});
it('Does not change anything when updating the existing schema', async () => {
await db.register(Account).register(Contact).migrate();
await db.register(Account).register(Contact).register(Organization).migrate();
await db.migrate();
});
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment