diff --git a/packages/mysql/src/builder.ts b/packages/mysql/src/builder.ts index 7a2c6b5b..ffcf27f2 100644 --- a/packages/mysql/src/builder.ts +++ b/packages/mysql/src/builder.ts @@ -6,6 +6,7 @@ export interface Compat { maria?: boolean maria105?: boolean mysql57?: boolean + timezone?: string } export class MySQLBuilder extends Builder { @@ -23,16 +24,28 @@ export class MySQLBuilder extends Builder { '\\': '\\\\', } + readonly _localTimezone = `+${(new Date()).getTimezoneOffset() / -60}:00`.replace('+-', '-') + readonly _dbTimezone: string + prequeries: string[] = [] constructor(protected driver: Driver, tables?: Dict, private compat: Compat = {}) { super(driver, tables) + this._dbTimezone = compat.timezone ?? 'SYSTEM' this.evalOperators.$sum = (expr) => this.createAggr(expr, value => `ifnull(sum(${value}), 0)`, undefined, value => `ifnull(minato_cfunc_sum(${value}), 0)`) this.evalOperators.$avg = (expr) => this.createAggr(expr, value => `avg(${value})`, undefined, value => `minato_cfunc_avg(${value})`) this.evalOperators.$min = (expr) => this.createAggr(expr, value => `min(${value})`, undefined, value => `minato_cfunc_min(${value})`) this.evalOperators.$max = (expr) => this.createAggr(expr, value => `max(${value})`, undefined, value => `minato_cfunc_max(${value})`) + this.evalOperators.$number = (arg) => { + const value = this.parseEval(arg) + const type = Type.fromTerm(arg) + const res = type.type === 'time' ? `unix_timestamp(convert_tz(addtime('1970-01-01 00:00:00', ${value}), '${this._localTimezone}', '${this._dbTimezone}'))` + : ['timestamp', 'date'].includes(type.type!) ? `unix_timestamp(convert_tz(${value}, '${this._localTimezone}', '${this._dbTimezone}'))` : `(0+${value})` + return this.asEncoded(`ifnull(${res}, 0)`, false) + } + this.transformers['boolean'] = { encode: value => `if(${value}=b'1', 1, 0)`, decode: value => `if(${value}=1, b'1', b'0')`, diff --git a/packages/mysql/src/index.ts b/packages/mysql/src/index.ts index a1c5e894..d255e4e7 100644 --- a/packages/mysql/src/index.ts +++ b/packages/mysql/src/index.ts @@ -72,7 +72,7 @@ export class MySQLDriver extends Driver { ...this.config, }) - const version = Object.values((await this.query(`SELECT version()`))[0])[0] as string + const [version, timezone] = Object.values((await this.query(`SELECT version(), @@GLOBAL.time_zone`))[0]) as string[] // https://jira.mariadb.org/browse/MDEV-30623 this._compat.maria = version.includes('MariaDB') // https://jira.mariadb.org/browse/MDEV-26506 @@ -80,6 +80,8 @@ export class MySQLDriver extends Driver { // For json_table this._compat.mysql57 = !!version.match(/5.7.\d+/) + this._compat.timezone = timezone + if (this._compat.mysql57 || this._compat.maria) { await this._setupCompatFunctions() } diff --git a/packages/sql-utils/src/index.ts b/packages/sql-utils/src/index.ts index c705253a..ac79eb3a 100644 --- a/packages/sql-utils/src/index.ts +++ b/packages/sql-utils/src/index.ts @@ -65,8 +65,6 @@ export class Builder { protected modifiedTable?: string protected transformers: Dict = Object.create(null) - protected readonly _timezone = `+${(new Date()).getTimezoneOffset() / -60}:00`.replace('+-', '-') - constructor(protected driver: Driver, tables?: Dict) { this.state.tables = tables @@ -167,13 +165,6 @@ export class Builder { // typecast $literal: ([value, type]) => this.escape(value, type as any), - $number: (arg) => { - const value = this.parseEval(arg) - const type = Type.fromTerm(arg) - const res = type.type === 'time' ? `unix_timestamp(convert_tz(addtime('1970-01-01 00:00:00', ${value}), '${this._timezone}', '+0:00'))` - : ['timestamp', 'date'].includes(type.type!) ? `unix_timestamp(convert_tz(${value}, '${this._timezone}', '+0:00'))` : `(0+${value})` - return this.asEncoded(`ifnull(${res}, 0)`, false) - }, // aggregation $sum: (expr) => this.createAggr(expr, value => `ifnull(sum(${value}), 0)`),