Skip to content

Commit

Permalink
fix(mysql): time field should give Date (#512)
Browse files Browse the repository at this point in the history
  • Loading branch information
DDEle authored Feb 15, 2022
1 parent df0771d commit 6129625
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 21 deletions.
11 changes: 11 additions & 0 deletions plugins/database/mysql/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ declare module 'koishi' {

const logger = new Logger('mysql')

const DEFAULT_DATE = new Date('1970-01-01')

export type TableType = keyof Tables

function getIntegerType(length = 11) {
Expand Down Expand Up @@ -128,6 +130,15 @@ class MysqlDatabase extends Database {
} else if (meta?.type === 'list') {
const source = field.string()
return source ? source.split(',') : []
} else if (meta?.type === 'time') {
const source = field.string()
if (!source) return meta.initial
const time = new Date(DEFAULT_DATE)
const [h, m, s] = source.split(':')
time.setHours(parseInt(h))
time.setMinutes(parseInt(m))
time.setSeconds(parseInt(s))
return time
}

if (field.type === 'BIT') {
Expand Down
36 changes: 33 additions & 3 deletions plugins/database/tests/src/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ interface Foo {
text?: string
value?: number
list?: number[]
timestamp?: Date
date?: Date
time?: Date
regex?: string
}

Expand All @@ -22,7 +24,9 @@ function QueryOperators(app: App) {
text: 'string',
value: 'integer',
list: 'list',
date: 'timestamp',
timestamp: 'timestamp',
date: 'date',
time: 'time',
regex: 'string',
}, {
autoInc: true,
Expand All @@ -33,7 +37,12 @@ namespace QueryOperators {
export const comparison = function Comparison(app: App) {
before(async () => {
await app.database.remove('temp1', {})
await app.database.create('temp1', { text: 'awesome foo', date: new Date('2000-01-01') })
await app.database.create('temp1', {
text: 'awesome foo',
timestamp: new Date('2000-01-01'),
date: new Date('2020-01-01'),
time: new Date('2020-01-01 12:00:00'),
})
await app.database.create('temp1', { text: 'awesome bar' })
await app.database.create('temp1', { text: 'awesome baz' })
})
Expand Down Expand Up @@ -64,6 +73,16 @@ namespace QueryOperators {
})).eventually.to.have.length(2).with.nested.property('0.text').equal('awesome foo')
})

it('timestamp comparisons', async () => {
await expect(app.database.get('temp1', {
timestamp: { $gt: new Date('1999-01-01') },
})).eventually.to.have.length(1).with.nested.property('0.text').equal('awesome foo')

await expect(app.database.get('temp1', {
timestamp: { $lte: new Date('1999-01-01') },
})).eventually.to.have.length(0)
})

it('date comparisons', async () => {
await expect(app.database.get('temp1', {
date: { $gt: new Date('1999-01-01') },
Expand All @@ -74,13 +93,24 @@ namespace QueryOperators {
})).eventually.to.have.length(0)
})

it('time comparisons', async () => {
await expect(app.database.get('temp1', {
// date should not matter
time: { $gt: new Date('2022-01-01 11:00:00') },
})).eventually.to.have.length(1).with.nested.property('0.text').equal('awesome foo')

await expect(app.database.get('temp1', {
time: { $lte: new Date('2022-01-01 11:00:00') },
})).eventually.to.have.length(0)
})

it('shorthand syntax', async () => {
await expect(app.database.get('temp1', {
id: 2,
})).eventually.to.have.length(1).with.nested.property('0.text').equal('awesome bar')

await expect(app.database.get('temp1', {
date: new Date('2000-01-01'),
timestamp: new Date('2000-01-01'),
})).eventually.to.have.length(1).with.nested.property('0.text').equal('awesome foo')
})
}
Expand Down
70 changes: 52 additions & 18 deletions plugins/database/tests/src/update.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { App, omit, Tables } from 'koishi'
import { App, Model, omit, Tables } from 'koishi'
import { expect } from 'chai'
export const DEFAULT_DATE = new Date('1970-01-01')

interface Bar {
id?: number
text?: string
num?: number
list?: string[]
timestamp?: Date
date?: Date
time?: Date
meta?: {
a?: string
b?: number
Expand All @@ -32,7 +35,9 @@ function OrmOperations(app: App) {
text: 'string',
num: 'integer',
list: 'list',
date: 'timestamp',
timestamp: 'timestamp',
date: 'date',
time: 'time',
meta: { type: 'json' },
}, {
autoInc: true,
Expand All @@ -47,6 +52,30 @@ function OrmOperations(app: App) {
})
}

function normalizeDate<T extends Tables[keyof Tables]>(row: T, model: Model.Config<T>): T {
const normalized = { ...row }
for (const k in row) {
if (!row[k]) continue
if (model.fields[k]?.type === 'time') {
const raw: Date = row[k] as any,
h = raw.getHours(),
m = raw.getMinutes(),
s = raw.getSeconds()
const date = new Date(DEFAULT_DATE)
date.setHours(h, m, s)
normalized[k] = date as any
}
}
return normalized
}

function expectShapeNormalized<T extends Tables[keyof Tables]>(t1: T[], t2: T[], model: Model.Config<T>) {
expect(t1.length).to.equal(t2.length)
t1.forEach((_, i) => {
expect(normalizeDate(t1[i], model)).to.have.shape(normalizeDate(t2[i], model))
})
}

namespace OrmOperations {
const merge = <T>(a: T, b: Partial<T>): T => ({ ...a, ...b })

Expand All @@ -57,8 +86,10 @@ namespace OrmOperations {
{ id: 2, text: 'pku' },
{ id: 3, num: 1989 },
{ id: 4, list: ['1', '1', '4'] },
{ id: 5, date: magicBorn },
{ id: 5, timestamp: magicBorn },
{ id: 6, meta: { a: 'foo', b: 233 } },
{ id: 7, date: magicBorn },
{ id: 8, time: new Date('2020-01-01 12:00:00') },
]

const bazTable: Baz[] = [
Expand All @@ -79,16 +110,17 @@ namespace OrmOperations {

export const create = function Create(app: App) {
it('auto increment primary key', async () => {
const model = app.model.config['temp2']
const table = barTable.map(bar => merge(app.model.create('temp2'), bar))
for (const index in barTable) {
const bar = await app.database.create('temp2', omit(barTable[index], ['id']))
barTable[index].id = bar.id
expect(bar).to.have.shape(table[index])
}
for (const obj of table) {
await expect(app.database.get('temp2', { id: obj.id })).eventually.shape([obj])
expectShapeNormalized(await app.database.get('temp2', { id: obj.id }), [obj], model)
}
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, model)
})

it('specify primary key', async () => {
Expand Down Expand Up @@ -127,9 +159,10 @@ namespace OrmOperations {
}

export const set = function Set(app: App) {
const modelTemp2 = app.model.config['temp2']
it('basic support', async () => {
const table = await setup(app, 'temp2', barTable)
const data = table.find(bar => bar.date)
const data = table.find(bar => bar.timestamp)
data.text = 'thu'
const magicIds = table.slice(0, 2).map((data) => {
data.text = 'thu'
Expand All @@ -138,10 +171,10 @@ namespace OrmOperations {
await expect(app.database.set('temp2', {
$or: [
{ id: magicIds },
{ date: magicBorn },
{ timestamp: magicBorn },
],
}, { text: 'thu' })).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('using expressions', async () => {
Expand All @@ -151,7 +184,7 @@ namespace OrmOperations {
await expect(app.database.set('temp2', [table[1].id, table[2].id, 9], {
num: { $multiply: [2, { $: 'id' }] },
})).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('using object literals', async () => {
Expand All @@ -162,7 +195,7 @@ namespace OrmOperations {
await expect(app.database.set('temp2', [data1.id, data2.id, 9], {
meta: { b: 114514 },
})).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('nested property', async () => {
Expand All @@ -174,11 +207,12 @@ namespace OrmOperations {
await expect(app.database.set('temp2', [data1.id, data2.id, 9], {
'meta.a': { $concat: [{ $ifNull: [{ $: 'meta.a' }, ''] }, 'bar'] },
})).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})
}

export const upsert = function Upsert(app: App) {
const modelTemp2 = app.model.config['temp2']
it('update existing records', async () => {
const table = await setup(app, 'temp2', barTable)
const data = [
Expand All @@ -190,18 +224,18 @@ namespace OrmOperations {
table[index] = merge(table[index], update)
})
await expect(app.database.upsert('temp2', data)).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('insert new records', async () => {
const table = await setup(app, 'temp2', barTable)
const data = [
{ id: table[5].id + 1, text: 'wmlake' },
{ id: table[5].id + 2, text: 'bytower' },
{ id: table[table.length - 1].id + 1, text: 'wmlake' },
{ id: table[table.length - 1].id + 2, text: 'bytower' },
]
table.push(...data.map(bar => merge(app.model.create('temp2'), bar)))
await expect(app.database.upsert('temp2', data)).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('using expressions', async () => {
Expand All @@ -218,7 +252,7 @@ namespace OrmOperations {
{ id: 3, num: { $add: [3, { $: 'num' }] } },
{ id: 9, num: 999 },
])).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('using object literals', async () => {
Expand All @@ -235,7 +269,7 @@ namespace OrmOperations {
{ id: 6, meta: { b: 514 } },
{ id: 9, meta: { b: 114514 } },
])).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})

it('nested property', async () => {
Expand All @@ -252,7 +286,7 @@ namespace OrmOperations {
{ id: 6, 'meta.b': 666 },
{ id: 9, 'meta.b': 999 },
])).eventually.fulfilled
await expect(app.database.get('temp2', {})).eventually.shape(table)
expectShapeNormalized(await app.database.get('temp2', {}), table, modelTemp2)
})
}

Expand Down

0 comments on commit 6129625

Please sign in to comment.