From e81267fb86d972c161b74aaa6b02ac96650d449c Mon Sep 17 00:00:00 2001 From: Hieuzest Date: Sat, 6 Apr 2024 18:23:53 +0800 Subject: [PATCH] fix(mongo): existence check -> equality check --- packages/mongo/src/builder.ts | 7 +++++-- packages/mysql/src/builder.ts | 3 --- packages/postgres/src/builder.ts | 10 +--------- packages/sql-utils/src/index.ts | 10 +++++----- packages/tests/src/model.ts | 10 +++++++--- packages/tests/src/update.ts | 1 + 6 files changed, 19 insertions(+), 22 deletions(-) diff --git a/packages/mongo/src/builder.ts b/packages/mongo/src/builder.ts index 293b4401..b73d5e02 100644 --- a/packages/mongo/src/builder.ts +++ b/packages/mongo/src/builder.ts @@ -24,7 +24,7 @@ function transformFieldQuery(query: Query.FieldQuery, key: string, filters: Filt } else if (query instanceof RegExp) { return { $regex: query } } else if (isNullable(query)) { - return { $exists: false } + return null } // query operators @@ -52,7 +52,7 @@ function transformFieldQuery(query: Query.FieldQuery, key: string, filters: Filt } else if (prop === '$el') { const child = transformFieldQuery(query[prop], key, filters) if (child === false) return false - if (child !== true) result.$elemMatch = child + if (child !== true) result.$elemMatch = child! } else if (prop === '$regexFor') { filters.push({ $expr: { @@ -62,6 +62,9 @@ function transformFieldQuery(query: Query.FieldQuery, key: string, filters: Filt }, }, }) + } else if (prop === '$exists') { + if (query[prop]) return { $ne: null } + else return null } else { result[prop] = query[prop] } diff --git a/packages/mysql/src/builder.ts b/packages/mysql/src/builder.ts index b18960bc..89c0a190 100644 --- a/packages/mysql/src/builder.ts +++ b/packages/mysql/src/builder.ts @@ -48,7 +48,6 @@ export class MySQLBuilder extends Builder { } this.transformers['date'] = { - encode: value => value, decode: value => `cast(${value} as date)`, load: value => { if (isNullable(value) || typeof value === 'object') return value @@ -67,14 +66,12 @@ export class MySQLBuilder extends Builder { } this.transformers['time'] = { - encode: value => value, decode: value => `cast(${value} as time)`, load: value => this.driver.types['time'].load(value), dump: value => isNullable(value) ? value : Time.template('yyyy-MM-dd hh:mm:ss.SSS', value), } this.transformers['timestamp'] = { - encode: value => value, decode: value => `cast(${value} as datetime)`, load: value => { if (isNullable(value) || typeof value === 'object') return value diff --git a/packages/postgres/src/builder.ts b/packages/postgres/src/builder.ts index 57631b71..f669b64d 100644 --- a/packages/postgres/src/builder.ts +++ b/packages/postgres/src/builder.ts @@ -91,17 +91,12 @@ export class PostgresBuilder extends Builder { } this.transformers['boolean'] = { - encode: value => value, decode: value => `(${value})::boolean`, - load: value => value, - dump: value => value, } this.transformers['decimal'] = { - encode: value => value, decode: value => `(${value})::double precision`, load: value => isNullable(value) ? value : +value, - dump: value => value, } this.transformers['binary'] = { @@ -112,7 +107,6 @@ export class PostgresBuilder extends Builder { } this.transformers['date'] = { - encode: value => value, decode: value => `cast(${value} as date)`, load: value => { if (isNullable(value) || typeof value === 'object') return value @@ -125,15 +119,13 @@ export class PostgresBuilder extends Builder { } this.transformers['time'] = { - encode: value => value, decode: value => `cast(${value} as time)`, load: value => this.driver.types['time'].load(value), dump: value => this.driver.types['time'].dump(value), } this.transformers['timestamp'] = { - encode: value => value, - decode: value => `cast(${value} as datetime)`, + decode: value => `cast(${value} as timestamp)`, load: value => { if (isNullable(value) || typeof value === 'object') return value return new Date(value) diff --git a/packages/sql-utils/src/index.ts b/packages/sql-utils/src/index.ts index 5ec7ae67..bee248b1 100644 --- a/packages/sql-utils/src/index.ts +++ b/packages/sql-utils/src/index.ts @@ -24,10 +24,10 @@ export type EvalOperators = { } & { $: (expr: any) => string } interface Transformer { - encode(value: string): string - decode(value: string): string - load(value: S): T - dump(value: T): S + encode?(value: string): string + decode?(value: string): string + load?(value: S | null): T | null + dump?(value: T | null): S | null } interface State { @@ -312,7 +312,7 @@ export class Builder { protected transform(value: string, type: Type | Eval.Expr | undefined, method: 'encode' | 'decode' | 'load' | 'dump', miss?: any) { type = Type.isType(type) ? type : Type.fromTerm(type) const transformer = this.transformers[type.type] ?? this.transformers[this.driver.database.types[type.type]?.type!] - return transformer ? transformer[method](value) : (miss ?? value) + return transformer?.[method] ? transformer[method](value) : (miss ?? value) } protected groupObject(_fields: any) { diff --git a/packages/tests/src/model.ts b/packages/tests/src/model.ts index 790eeb9d..059f68ae 100644 --- a/packages/tests/src/model.ts +++ b/packages/tests/src/model.ts @@ -1,4 +1,4 @@ -import { valueMap, isNullable } from 'cosmokit' +import { valueMap, isNullable, deduplicate } from 'cosmokit' import { $, Database, Field, Type, unravel } from 'minato' import { expect } from 'chai' @@ -264,7 +264,7 @@ function ModelOperations(database: Database) { function getValue(obj: any, path: string) { if (path.includes('.')) { const index = path.indexOf('.') - return getValue(obj[path.slice(0, index)] ??= {}, path.slice(index + 1)) + return getValue(obj[path.slice(0, index)] ?? {}, path.slice(index + 1)) } else { return obj[path] } @@ -566,7 +566,11 @@ namespace ModelOperations { it('project with dot notation', async () => { const table = await setup(database, 'dobjects', dobjectTable) - const keys = Object.keys(database.tables['dobjects'].fields).flatMap(k => k.split('.').reduce((arr, c) => arr.length ? [`${arr[0]}.${c}`, ...arr] : [c], [])) + const keys = deduplicate([ + 'foo.nested.object', + 'foo.nested.object.embed', + ...Object.keys(database.tables['dobjects'].fields).flatMap(k => k.split('.').reduce((arr, c) => arr.length ? [`${arr[0]}.${c}`, ...arr] : [c], [])), + ]) await Promise.all(keys.map(key => expect(database.select('dobjects').project([key as any]).execute()).to.eventually.have.deep.members(table.map(row => unravel({ [key]: getValue(row, key) }))) )) diff --git a/packages/tests/src/update.ts b/packages/tests/src/update.ts index a7cca709..1fdd2960 100644 --- a/packages/tests/src/update.ts +++ b/packages/tests/src/update.ts @@ -188,6 +188,7 @@ namespace OrmOperations { data.text = null as never await database.set('temp2', { timestamp: { $exists: true } }, { text: null }) await expect(database.get('temp2', {})).to.eventually.have.shape(table) + await expect(database.get('temp2', { text: { $exists: false } })).to.eventually.have.length(1) }) it('noop', async () => {