Skip to content

Commit

Permalink
fix(storage): 修正 Database 上 get 方法对不含 where 字段 query 的处理
Browse files Browse the repository at this point in the history
...并在 concat selector 时进行的查询信息等价比较上,妥善处理
predicateProvider 为空而导致没有 toString 方法可调用,throw 的情况。

...resolves #93
  • Loading branch information
chuan6 committed Jul 14, 2017
1 parent ea5f15a commit 7c2b608
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/storage/Database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ export class Database {
mainTable: table!
}
const { limit, skip } = clause
const provider = new PredicateProvider(table!, clause.where!)
const provider = clause.where ? new PredicateProvider(table!, clause.where) : null

return new Selector<T>(db, query, matcher, provider, limit, skip, orderDesc)
})
Expand Down
39 changes: 27 additions & 12 deletions src/storage/modules/Selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,12 +201,19 @@ export class Selector <T> {

concat(... selectors: Selector<T>[]): Selector<T> {
const orderStr = Selector.stringifyOrder(this.orderDescriptions!)
const equal = selectors.every(m =>
m.select === this.select &&
m.predicateProvider!.toString() === this.predicateProvider!.toString() &&
Selector.stringifyOrder(m.orderDescriptions!) === orderStr &&
m.mapFn.toString() === this.mapFn.toString()
)
const equal = selectors.every(m => {
const hasEqualPredProvider =
m.predicateProvider == null && this.predicateProvider == null
|| (
m.predicateProvider && this.predicateProvider
&& m.predicateProvider.toString() === this.predicateProvider.toString()
)

return !!hasEqualPredProvider
&& m.select === this.select
&& Selector.stringifyOrder(m.orderDescriptions!) === orderStr
&& m.mapFn.toString() === this.mapFn.toString()
})
assert(equal, Exception.TokenConcatFailed())

return Selector.concatFactory(this, ...selectors)
Expand Down Expand Up @@ -236,19 +243,27 @@ export class Selector <T> {
}

private getQuery(additional?: lf.Predicate): lf.query.Select {
if (this.predicateBuildErr && !additional) {
return this.query
if (this.predicateBuildErr) {
return additional ? this.query.where(additional) : this.query
}
// !this.predicateBuildErr || additional
// !this.predicateBuildErr

const preds: lf.Predicate[] = []
if (this.predicateProvider && !this.predicateBuildErr) {
if (this.predicateProvider) {
preds.push(this.predicateProvider.getPredicate()!)
}
if (additional) {
preds.push(additional)
}
const pred = lf.op.and(...preds)
return this.query.where(pred)

switch (preds.length) {
case 0:
return this.query
case 1:
return this.query.where(preds[0])
default:
return this.query.where(lf.op.and(...preds))
}
}

private removeKey(data: any[], key: string) {
Expand Down
13 changes: 11 additions & 2 deletions test/specs/storage/Database.public.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Observable } from 'rxjs/Observable'
import { Observable, Scheduler } from 'rxjs'
import * as moment from 'moment'
import { describe, it, beforeEach, afterEach } from 'tman'
import { expect, assert, use } from 'chai'
Expand All @@ -10,7 +10,7 @@ import { TestFixture2 } from '../../schemas/Test'
import { scenarioGen, programGen, postGen, taskGen, subtaskGen } from '../../utils/generators'
import { RDBType, DataStoreType, Database, clone, forEach, JoinMode } from '../../index'
import { TaskSchema, ProjectSchema, PostSchema, ModuleSchema, ProgramSchema, SubtaskSchema } from '../../index'
import { InvalidQuery, NonExistentTable, InvalidType, PrimaryKeyNotProvided, NotConnected } from '../../index'
import { InvalidQuery, NonExistentTable, InvalidType, PrimaryKeyNotProvided, NotConnected, Selector } from '../../index'

use(SinonChai)

Expand Down Expand Up @@ -251,6 +251,15 @@ export default describe('Database Testcase: ', () => {
expect(_projectId).to.equal(target._projectId)
})

it('on query without `where`, should result in QueryToken whose Selector does not have predicateProvider', function* () {
yield database.get<TaskSchema>('Task', {}).selector$
.subscribeOn(Scheduler.async)
.do((x: Selector<TaskSchema>) => {
console.info(x.toString())
expect(x.predicateProvider).to.be.null
})
})

it('should get single record successfully', function* () {
const result = yield database.get<TaskSchema>('Task', {
where: { _id: target._id }
Expand Down
22 changes: 21 additions & 1 deletion test/specs/storage/modules/Selector.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export default describe('Selector test', () => {

const sql = selector.toString()

expect(sql).to.equal('SELECT * FROM TestSelectMetadata WHERE ((TestSelectMetadata.time > 50));')
expect(sql).to.equal('SELECT * FROM TestSelectMetadata WHERE (TestSelectMetadata.time > 50);')
})

it('should get correct results with orderBy', function* () {
Expand Down Expand Up @@ -922,6 +922,26 @@ export default describe('Selector test', () => {
.do(r => expect(r[75].name).equal(update3))
})

it('concat selector should ok when neither selectors have predicateProvider', function* () {
selector1 = new Selector(db,
db.select().from(table),
tableShape,
null,
20, 0
)
selector2 = new Selector(db,
db.select().from(table),
tableShape,
null,
20, 20
)
const result = yield selector1.concat(selector2).values()
expect(result).to.have.lengthOf(40)
result.forEach((r: any, index: number) => {
expect(r).to.deep.equal(storeData[index])
})
})

it('concat selector should ok with OrderDescription', function* () {
const selector6 = new Selector(db,
db.select().from(table),
Expand Down

0 comments on commit 7c2b608

Please sign in to comment.