Commit f6f5cd84 authored by William Naslund's avatar William Naslund

Added model update and save functions

parent 7718370f
{
"name": "@swirl/db",
"version": "0.1.0",
"version": "1.0.0-alpha.1",
"main": "dist/module/index.js",
"scripts": {
"start": "concurrently npm:watch:module npm:watch:tests",
......
......@@ -5,4 +5,7 @@ export interface DBModelAdapter {
/** Inserts a models values, returning its id if there is one */
insert(model: DBModelConstructor<any>, values: { [field: string]: any }): Promise<any>;
/** Updates a models values */
update(model: DBModelConstructor<any>, values: { [field: string]: any }, id: any): Promise<any>;
}
......@@ -12,9 +12,11 @@ export class DBModel {
/** Inserts this record into the database */
async insert() {
const db = Reflect.getMetadata(MODEL_DATABASE, this.constructor) as Database;
if(db == null) {
throw new Error(`This model (${this.constructor}) has not been registered with a database`);
const db = this.getDB();
const tableInfo = getTableInformation(this.constructor);
if(this[tableInfo.options.id] != null) {
throw new Error(`Attempt to insert a model that already has an id`);
}
const saveData: any = { };
......@@ -33,13 +35,70 @@ export class DBModel {
}
}
const tableInfo = getTableInformation(this.constructor);
const newId = await db.adapter.model.insert(this.constructor, saveData);
if(tableInfo.options.id) {
this[tableInfo.options.id] = newId;
}
}
/** Updates this record in the database */
async update() {
const db = this.getDB();
const tableInfo = getTableInformation(this.constructor);
const id = this[tableInfo.options.id];
const idInfo = getFieldInformation(this.constructor, tableInfo.options.id);
if(id == null) {
throw new Error(`Attempt to update a model that has no id`);
}
const saveData: any = { };
for(const field in this._contents) {
if(field == idInfo.name) {
continue;
}
saveData[field] = this._contents[field];
}
for(const lookup of Reflect.getMetadata(TABLE_PARENT_LOOKUPS, this.constructor) as DBLookupInformation[] || []) {
const lookupValue = this[lookup.propertyKey];
if(lookupValue === undefined) continue;
if(lookupValue != null) {
const lookupTableInfo = getTableInformation(lookup.model);
saveData[lookup.name] = lookupValue[lookupTableInfo.options.id];
} else {
saveData[lookup.name] = null;
}
}
if(Object.keys(saveData).length > 0) {
await db.adapter.model.update(this.constructor, saveData, id);
}
}
/** Inserts the model, if its id is blank, or updates it, if its id is set */
async save() {
const tableInfo = getTableInformation(this.constructor);
const id = this[tableInfo.options.id];
if(id == null) {
await this.insert();
} else {
await this.update();
}
}
/** Returns the database that this model is registered in */
private getDB(): Database {
const db = Reflect.getMetadata(MODEL_DATABASE, this.constructor) as Database;
if(db == null) {
throw new Error(`This model (${this.constructor}) has not been registered with a database`);
}
return db;
}
toString(): string {
let str = `${this.constructor.name} {`;
......
......@@ -37,4 +37,22 @@ export class PGModelAdapter implements DBModelAdapter {
}
}
async update(model: DBModelConstructor<any>, values: { [field: string]: any }, id: any) {
const fieldValues = [];
const table = getTableInformation(model);
let sql = `UPDATE ${table.options.schema}.${table.name} SET `;
for(const fieldName in values) {
fieldValues.push(values[fieldName]);
sql += `${fieldName} = $${fieldValues.length}, `;
}
if(sql.endsWith(', ')) sql = sql.substring(0, sql.length - 2) + ' ';
fieldValues.push(id);
sql += `WHERE ${table.options.id as any} = $${fieldValues.length}`;
await this.db.command.query(sql, fieldValues);
}
}
import * as assert from "assert";
import { Database } from "@swirl/db";
import { getTestAdapter } from "./db/adapter";
import { Account } from "./db/account";
import { Contact } from "./db/contact";
import { Organization } from "./db/org";
describe('DBModel', function() {
let db: Database;
beforeEach('Setup the database', async () => {
db = new Database(getTestAdapter());
await db.register(Account).register(Contact).register(Organization).migrate();
});
describe('update()', function() {
it('Updates field values', async () => {
const acc = new Account();
acc.name = 'Test Account A';
await acc.insert();
acc.name = 'Test Account B';
await acc.update();
const query = db.query(Account);
query.select('id', 'name');
const queried = await query.getOne();
assert.equal('Test Account B', queried.name);
});
});
describe('save()', function() {
it('Updates when the id is set', async () => {
const acc = new Account();
acc.name = 'Test Save';
await acc.save();
assert(acc.id != null);
acc.name = 'Test Save (Updated)';
await acc.save();
const query = db.query(Account);
query.select('id', 'name');
const queried = await query.getOne();
assert.equal('Test Save (Updated)', queried.name);
});
});
afterEach('Reset the database', async () => {
await db.delete();
await db.close();
db = null;
});
});
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