Skip to content

Commit

Permalink
Merge pull request #90 from teambition/fix/pred-provider
Browse files Browse the repository at this point in the history
fix(PredicateProvider): 令未在非顶层指定 $and, $or 的输入默认用 $and
  • Loading branch information
Saviio authored Jul 7, 2017
2 parents c254da6 + 33126a1 commit ea5f15a
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 92 deletions.
35 changes: 21 additions & 14 deletions src/storage/modules/PredicateProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,31 +89,38 @@ export class PredicateProvider<T> {

toString(): string | void {
const pred = this.getPredicate()
if (pred !== null) {
return pred.toString()
}
return pred ? JSON.stringify(this.meta) : ''
}

private normalizeMeta(meta: Predicate<T>, column?: lf.schema.Column) {
let predicates: lf.Predicate[] = []
private normalizeMeta(meta: Predicate<T>, column?: lf.schema.Column): lf.Predicate[] {
const buildSinglePred = (col: lf.schema.Column, val: any, key: string): lf.Predicate =>
this.checkMethod(key) ? predicateFactory[key](col, val) : col.eq(val as ValueLiteral)

const predicates: lf.Predicate[] = []

forEach(meta, (val, key) => {
let nestedPreds: lf.Predicate[]
let resultPred: lf.Predicate

if (this.checkCompound(key)) {
predicates.push(compoundPredicateFactory[key](this.normalizeMeta(val as Predicate<T>, column)))
nestedPreds = this.normalizeMeta(val as Predicate<T>, column)
resultPred = compoundPredicateFactory[key](nestedPreds)
} else if (this.checkPredicate(val)) {
predicates = predicates.concat(this.normalizeMeta(val as any, this.table[key]))
nestedPreds = this.normalizeMeta(val as any, this.table[key])
resultPred = compoundPredicateFactory['$and'](nestedPreds)
} else {
const _column = column || this.table[key]
if (!_column) {
warn(
`Failed to build predicate, since column: ${key} is not exist` +
`, on table: ${this.table.getName()}`
)
if (_column) {
resultPred = buildSinglePred(_column, val, key)
} else {
const predicate = this.checkMethod(key) ? predicateFactory[key](_column, val) : _column.eq(val as ValueLiteral)
predicates.push(predicate)
warn(`Failed to build predicate, since column: ${key} is not exist, on table: ${this.table.getName()}`)
return
}
}

predicates.push(resultPred)
})

return predicates
}

Expand Down
150 changes: 74 additions & 76 deletions test/specs/storage/modules/PredicateProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { PredicateProvider, lfFactory, DataStoreType } from '../../../index'

export default describe('PredicateProvider test', () => {
const dataLength = 1000

const execQuery = (db: any, table: any, pred?: any) =>
db.select()
.from(table)
.where(pred)
.exec()

let db: lf.Database
let table: lf.schema.Table
let version = 1
Expand Down Expand Up @@ -44,25 +51,30 @@ export default describe('PredicateProvider test', () => {
})

describe('PredicateProvider#getPredicate', () => {
it('invalid key should be ignored', function*() {
it('invalid key should be ignored', function* () {
const fn = () => new PredicateProvider(table, {
nonExist: 'whatever'
}).getPredicate()

const expectResult = yield db.select().from(table).exec()
const result = yield db.select().from(table).where(fn()).exec()
const expectResult = yield execQuery(db, table)
const result = yield execQuery(db, table, fn())

expect(result).deep.equal(expectResult)
})

it('empty meta should ok', function* () {
const predicate = new PredicateProvider(table, {}).getPredicate()
expect(predicate).to.be.null
const result = yield execQuery(db, table, predicate)
expect(result).to.have.lengthOf(1000)
})

it('literal value should ok', function* () {
const predicate = new PredicateProvider(table, {
time1: 20
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(1)
expect(result[0]['time1']).to.equal(20)
Expand All @@ -75,13 +87,9 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(dataLength - 1)

result.forEach((r: any) => expect(r['time1'] === 20).to.be.false)
})

Expand All @@ -92,10 +100,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(20)
result.forEach((r: any) => expect(r['time1'] < 20).to.be.true)
Expand All @@ -108,10 +113,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(20)
result.forEach((r: any) => expect(r['time1'] <= 19).to.be.true)
Expand All @@ -124,10 +126,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(dataLength - 20)
result.forEach((r: any) => expect(r['time2'] > 20).to.be.true)
Expand All @@ -140,10 +139,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(dataLength - 20)
result.forEach((r: any) => expect(r['time2'] >= 21).to.be.true)
Expand All @@ -157,10 +153,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(10)
result.forEach((r: any) => expect(regExp.test(r['name'])).to.be.true)
Expand All @@ -174,10 +167,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

// 上一个测试中结果长度是 10
expect(result).to.have.lengthOf(dataLength - 10)
Expand All @@ -191,10 +181,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(20)
result.forEach((r: any) => expect(r['time1'] > 0 && r['time1'] <= 20).to.be.true)
Expand All @@ -207,10 +194,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(3)
result.forEach((r: any) => {
Expand All @@ -226,10 +210,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(3)
result.forEach((r: any) => expect(seed.indexOf(r['time1']) !== -1).to.be.true)
Expand All @@ -242,10 +223,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(700)
result.forEach((r: any) => expect(r['nullable']).to.be.null)
Expand All @@ -258,10 +236,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(300)
result.forEach((r: any) => expect(r['nullable']).to.not.be.null)
Expand All @@ -274,10 +249,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(dataLength - 1)
})
Expand All @@ -292,10 +264,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(150)
result.forEach((r: any) => expect(r['time1'] >= 50 && r['time1'] < 200).to.be.true)
Expand All @@ -311,15 +280,31 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(100)
result.forEach((r: any) => expect(r['time1'] >= dataLength - 50 || r['time1'] < 50).to.be.true)
})

it('non-compound predicates should be combined with $and', function* () {
const predicate = new PredicateProvider(table, {
$or: {
time1: { $gte: 0, $lt: 50 },
time2: { $gt: 0, $lte: 50 }
}
}).getPredicate()

const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(100)
result.forEach((row: any) => {
expect(
(row.time1 >= 0 && row.time1 < 50)
|| (row.time2 <= 50 && row.time2 > 0)
).to.be.true
})
})

it('compoundPredicate should skip null/undefined property', function* () {
const predicate = new PredicateProvider(table, {
time1: {
Expand All @@ -330,10 +315,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(50)
result.forEach((r: any) => expect(r['time1'] >= dataLength - 50).to.be.true)
Expand All @@ -359,10 +341,7 @@ export default describe('PredicateProvider test', () => {
}
}).getPredicate()

const result = yield db.select()
.from(table)
.where(predicate)
.exec()
const result = yield execQuery(db, table, predicate)

expect(result).to.have.lengthOf(5)

Expand All @@ -375,4 +354,23 @@ export default describe('PredicateProvider test', () => {
})
})
})

describe('PredicateProvider#toString', () => {
it('convert empty PredicateProvider to empty string', () => {
expect(new PredicateProvider(table, {}).toString()).to.equal('')
})

it('convert to string representation of the predicate', () => {
expect(new PredicateProvider(table, { notExist: 20 }).toString()).to.equal('')

expect(new PredicateProvider(table, { time1: 20 }).toString()).to.equal('{"time1":20}')

expect(new PredicateProvider(table, {
$or: {
time1: { $gte: 0, $lt: 50 },
time2: { $gt: 0, $lte: 50 }
}
}).toString()).to.equal('{"$or":{"time1":{"$gte":0,"$lt":50},"time2":{"$gt":0,"$lte":50}}}')
})
})
})
4 changes: 2 additions & 2 deletions 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,7 +922,7 @@ export default describe('Selector test', () => {
.do(r => expect(r[75].name).equal(update3))
})

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

0 comments on commit ea5f15a

Please sign in to comment.