Skip to content

Commit

Permalink
Finish first test release
Browse files Browse the repository at this point in the history
  • Loading branch information
BigDataSamuli committed Aug 15, 2016
1 parent e942153 commit 71f0d9e
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 24 deletions.
8 changes: 8 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.gitignore
.npmignore
.vscode
typings
src
node_modules
typings.json
tsconfig.json
22 changes: 19 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
{
"name": "simple-typed-sql",
"version": "0.0.1",
"description": "",
"private": true,
"description": "Simple SQL library for Typescript",
"license": "MIT",
"keywords": [
"typescript",
"sql",
"orm",
"node"
],
"repository": {
"type": "git",
"url": "https://github.com/smphhh/simple-typed-sql"
},
"main": "lib/index.js",
"author": {
"name": "Samuli Holopainen",
"email": "[email protected]"
},
"dependencies": {
"bluebird": "^3.4.1",
"knex": "^0.11.9",
Expand All @@ -21,5 +36,6 @@
"build": "tsc",
"test": "mocha lib/**/__tests__/**/*.js",
"typings-install": "typings install"
}
},
"typings": "./lib/index.d.ts"
}
45 changes: 44 additions & 1 deletion src/__tests__/core.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe("Simple typed SQL", function () {
table.string('external_id').notNullable().unique();
});

mapper = new Mapper(knexClient);
mapper = new Mapper(knexClient, { stringifyJson: true });
});

it("should allow inserting and selecting simple data", async function () {
Expand Down Expand Up @@ -84,6 +84,49 @@ describe("Simple typed SQL", function () {

expect(data).to.deep.equal([]);
});

it("should support basic ordering", async function () {
await mapper.insertInto(testModel, testObject1);
await mapper.insertInto(testModel, testObject2);

let data = await mapper.selectAllFrom(testModel).orderBy(testModel.id, 'asc');
expect(data).to.deep.equal([testObject1, testObject2]);

data = await mapper.selectAllFrom(testModel).orderBy(testModel.id, 'desc');
expect(data).to.deep.equal([testObject2, testObject1]);
});

it("should support less-than where clauses", async function () {
await mapper.insertInto(testModel, testObject1);
await mapper.insertInto(testModel, testObject2);

let data = await mapper.selectAllFrom(testModel).whereLess(testModel.id, 2);

expect(data).to.deep.equal([testObject1]);
});

it("should support greater-than where clauses", async function () {
await mapper.insertInto(testModel, testObject1);
await mapper.insertInto(testModel, testObject2);

let data = await mapper.selectAllFrom(testModel).whereGreater(testModel.id, 1);

expect(data).to.deep.equal([testObject2]);
});

it("should findOneByKey", async function () {
await mapper.insertInto(testModel, testObject1);
await mapper.insertInto(testModel, testObject2);

let data = await mapper.tryFindOneByKey(testModel, { id: 1 });
expect(data).to.deep.equal(testObject1);

data = await mapper.tryFindOneByKey(testModel, { externalId: 'b' });
expect(data).to.deep.equal(testObject2);

data = await mapper.tryFindOneByKey(testModel, { externalId: 'not_found' });
expect(data).to.be.null;
});
});


Expand Down
95 changes: 79 additions & 16 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {

export class BaseMapper {
constructor(
private knexBuilder: knex.QueryInterface
private knexBuilder: knex.QueryInterface,
private options: SerializationOptions
) {
}

Expand All @@ -26,36 +27,71 @@ export class BaseMapper {

let query = this.knexBuilder.select(absoluteFieldNames).from(tableName);

return new Query(model, query, {});
return new Query(model, query, this.options);
}

insertInto<T extends U, U>(model: ModelDefinition<T>, data: T) {
let query = this.knexBuilder
.insert(serializeData(model, data, {}))
.insert(serializeData(model, data, this.options))
.into(model.__metadata.tableName);

return new InsertQuery(model, query, {});
return new InsertQuery(model, query, this.options);
}

async tryFindOneByKey<T extends U, U>(model: ModelDefinition<T>, key: U) {
let attributeNames = getAttributes(model);
let whereConditions = serializeData(model, key, this.options);
let fieldNames = getFieldNames(model);
let query = this.knexBuilder.columns(fieldNames).select().from(model.__metadata.tableName);

if (Object.keys(whereConditions).length > 0) {
query = query.where(whereConditions);
}

let data = await query.limit(1);
if (data.length === 1) {
return deserializeData(model, data[0], this.options);
} else {
return null as T;
}
}

async findOneByKey<T extends U, U>(model: ModelDefinition<T>, key: U) {
let data = await this.tryFindOneByKey(model, key);
if (!data) {
throw new Error("Expected to find exactly one row");
} else {
return data;
}
}
}

export class Mapper extends BaseMapper {
//private query: knex.QueryBuilder;

constructor(
private knexClient: knex
private knexClient: knex,
options: SerializationOptions
) {
super(knexClient);
super(knexClient, options);
}

transaction(callback: (transactionMapper: BaseMapper) => Promise<void>) {
this.knexClient.transaction(function (trx) {
let t: knex.Transaction;
let transactionMapper = new BaseMapper(trx);
let transactionMapper = new BaseMapper(trx, this.options);
return callback(transactionMapper);
});
}
}

type ComparisonOperator = '<' | '>' | '<=' | '>=' | '=';

export interface WhereClause {
operator: string;
operands: WhereClause[];
}

export class Query<ResultType> {
constructor(
private resultModel: ModelDefinition<ResultType>,
Expand All @@ -64,9 +100,44 @@ export class Query<ResultType> {
) {
}

where(clause: WhereClause) {
throw new Error("Not implemented");
}

whereEqual<T>(attribute: T, value: T) {
return this.whereOperator(attribute, '=', value);
}

whereLess<T>(attribute: T, value: T) {
return this.whereOperator(attribute, '<', value);
}

whereLessOrEqual<T>(attribute: T, value: T) {
return this.whereOperator(attribute, '<=', value);
}

whereGreater<T>(attribute: T, value: T) {
return this.whereOperator(attribute, '>', value);
}

whereGreaterOrEqual<T>(attribute: T, value: T) {
return this.whereOperator(attribute, '>=', value);
}

limit(count: number) {
this.query = this.query.limit(count);
return this;
}

orderBy(attribute: any, direction: 'asc' | 'desc') {
let attributeDefinition: AttributeDefinition = attribute;
this.query = this.query.orderBy(attributeDefinition.fieldName, direction);
return this;
}

private whereOperator<T>(attribute: T, operator: ComparisonOperator, value: T) {
let attributeDefinition: AttributeDefinition = attribute as any;
this.query = this.query.andWhere(attributeDefinition.fieldName, value as any);
this.query = this.query.andWhere(attributeDefinition.fieldName, operator, value as any);
return this;
}

Expand All @@ -88,14 +159,6 @@ export class InsertQuery<InsertDataType> implements PromiseLike<void> {
) {
}

/*into<T extends InsertDataType>(model: ModelDefinition<T>) {
let query = this.knexClient
.insert(serializeData(model, this.data, this.serializationOptions))
.into(model.__metadata.tableName);
return new Query(model, query, this.serializationOptions);
}*/

async execute() {
let queryResults: any[] = await this.knexQuery;
return;
Expand Down
6 changes: 3 additions & 3 deletions src/definition.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

interface Metadata {
export interface Metadata {
tableName: string;
attributes: {
[attributeName: string]: AttributeDefinition
Expand Down Expand Up @@ -73,11 +73,11 @@ export function defineDatetime(options?: AttributeOptions) {

export type DataMapperOptions = SerializationOptions;

interface AttributeOptions {
export interface AttributeOptions {
fieldName?: string
}

type DataType = 'number' | 'string' | 'json' | 'datetime';
export type DataType = 'number' | 'string' | 'json' | 'datetime';

export interface AttributeDefinition {
dataType: DataType;
Expand Down
12 changes: 12 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

export {
defineDatetime,
defineJson,
defineModel,
defineNumber,
defineString
} from './definition';

export {
Mapper
} from './core';
4 changes: 3 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
"compilerOptions": {
"module": "commonjs",
"target": "es2015",
"declaration": true,
"outDir": "lib",
"rootDir": "src",
"sourceMap": true
},
"exclude": [
"node_modules"
"node_modules",
"lib"
]
}

0 comments on commit 71f0d9e

Please sign in to comment.