Skip to content

Commit

Permalink
test: level tests
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Dec 31, 2019
1 parent 95f6517 commit 7f9756c
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 43 deletions.
23 changes: 15 additions & 8 deletions packages/database-level/src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,21 +76,28 @@ export class LevelDatabase {
}

async create <K extends TableType> (table: K, data: Partial<TableData[K]>) {
const id = 1 + await new Promise<number>((resolve, reject) => {
this.tables[table].createKeyStream({ reverse: true, limit: 1 })
.on('data', key => resolve(key))
.on('error', error => reject(error))
.on('end', () => resolve(0))
})
if (!data.id) data.id = id
await (this.tables[table] as any).put(id, data)
if (typeof data.id !== 'number') {
data.id = 1 + await new Promise<number>((resolve, reject) => {
this.tables[table].createKeyStream({ reverse: true, limit: 1 })
.on('data', key => resolve(key))
.on('error', error => reject(error))
.on('end', () => resolve(0))
})
}
await (this.tables[table] as any).put(data.id, data)
return data as TableData[K]
}

async remove <K extends TableType> (table: K, id: number) {
return this.tables[table].del(id)
}

async update <K extends TableType> (table: K, id: number, data: Partial<TableData[K]>) {
const sub = this.tables[table] as LevelUp
const originalData = await sub.get(id)
return sub.put(id, { ...originalData, ...data })
}

count (table: TableType) {
return new Promise<number>((resolve, reject) => {
let userNum = 0
Expand Down
16 changes: 8 additions & 8 deletions packages/database-level/src/group.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSelfIds, injectMethods, GroupData, createGroup } from 'koishi-core'
import { getSelfIds, injectMethods, GroupData, createGroup, Group } from 'koishi-core'
import { noop, observe } from 'koishi-utils'
import {} from './database'

Expand Down Expand Up @@ -35,20 +35,20 @@ injectMethods('level', 'group', {
},

async setGroup (groupId, data) {
const originalData = await this.tables.group.get(groupId)
const newData: GroupData = { ...originalData, ...data }
await this.tables.group.put(groupId, newData)
return this.update('group', groupId, data)
},

async observeGroup (group, selfId) {
if (typeof group === 'number') {
selfId = typeof selfId === 'number' ? selfId : 0
const data = await this.getGroup(group, selfId)
return data && observe(data, diff => this.setGroup(group, diff), `group ${group}`)
} else if ('_diff' in group) {
return group
}

const data = await this.getGroup(group.id, selfId)
if ('_diff' in group) {
return (group as Group)._merge(data)
} else {
return observe(group, diff => this.setGroup(group.id, diff), `group ${group.id}`)
return observe(Object.assign(group, data), diff => this.setGroup(group.id, diff), `group ${group.id}`)
}
},

Expand Down
22 changes: 11 additions & 11 deletions packages/database-level/src/user.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { injectMethods, UserData, createUser } from 'koishi-core'
import { injectMethods, UserData, createUser, User } from 'koishi-core'
import { observe, noop } from 'koishi-utils'
import {} from './database'

Expand All @@ -21,7 +21,7 @@ injectMethods('level', 'user', {
},

async getUsers (...args) {
if (args.length > 1 || args.length && typeof args[0][0] === 'number') {
if (args.length > 1 || args.length && typeof args[0][0] !== 'string') {
if (!args[0].length) return []
const users = await Promise.all(args[0].map(id => this.tables.user.get(id).catch(noop)))
return users.filter(Boolean) as UserData[]
Expand All @@ -36,20 +36,20 @@ injectMethods('level', 'user', {
},

async setUser (userId, data) {
const originalData = await this.getUser(userId)
const newData: UserData = { ...originalData, ...data }
await this.tables.user.put(userId, newData)
return this.update('user', userId, data)
},

async observeUser (user, authority) {
if (typeof user === 'number') {
authority = typeof authority === 'number' ? authority : 0
const dasDatum = await this.getUser(user, authority)
return dasDatum && observe(dasDatum, diff => this.setUser(user, diff), `user ${user}`)
} else if ('_diff' in user) {
return user
const data = await this.getUser(user, authority)
return data && observe(data, diff => this.setUser(user, diff), `user ${user}`)
}

const data = await this.getUser(user.id, authority)
if ('_diff' in user) {
return (user as User)._merge(data)
} else {
return observe(user, diff => this.setUser(user.id, diff), `user ${user}`)
return observe(Object.assign(user, data), diff => this.setUser(user.id, diff), `user ${user.id}`)
}
},

Expand Down
6 changes: 4 additions & 2 deletions packages/database-level/tests/level.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ describe('other methods', () => {
await expect(db.getFooCount()).resolves.toBe(1)
await expect(db.createFoo()).resolves.toMatchObject({ id: 3 })
await expect(db.getFooCount()).resolves.toBe(2)
await expect(db.createFoo({ id: 100 })).resolves.toMatchObject({ id: 100 })
await expect(db.getFooCount()).resolves.toBe(3)
await expect(db.removeFoo(3)).resolves.toBeUndefined()
await expect(db.getFooCount()).resolves.toBe(1)
await expect(db.createFoo()).resolves.toMatchObject({ id: 3 })
await expect(db.getFooCount()).resolves.toBe(2)
await expect(db.createFoo()).resolves.toMatchObject({ id: 3 })
await expect(db.getFooCount()).resolves.toBe(3)
})
})
4 changes: 2 additions & 2 deletions packages/database-mysql/src/group.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { contain, observe, difference, Observed } from 'koishi-utils'
import { getSelfIds, injectMethods, GroupData, createGroup, groupFields, GroupField } from 'koishi-core'
import { getSelfIds, injectMethods, GroupData, createGroup, groupFields, GroupField, Group } from 'koishi-core'

declare module './database' {
interface MysqlDatabaseConfig {
Expand Down Expand Up @@ -79,7 +79,7 @@ injectMethods('mysql', 'group', {
? await this.getGroup(group.id, selfId, difference(fields, Object.keys(group)))
: {} as Partial<GroupData>
if ('_diff' in group) {
return (group as Observed<GroupData>)._merge(additionalData)
return (group as Group)._merge(additionalData)
} else {
return observe(Object.assign(group, additionalData), diff => this.setGroup(group.id, diff), `group ${group.id}`)
}
Expand Down
28 changes: 17 additions & 11 deletions packages/koishi-utils/src/observe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const builtinClasses = ['Date', 'RegExp', 'Set', 'Map', 'WeakSet', 'WeakMap', 'A
const refs: Record<string | number, any> = {}

function observeObject <T extends object> (target: T, label: string, update?: () => void): T {
Object.defineProperty(target, '_proxy', { value: {} })
Object.defineProperty(target, '__proxyGetters__', { value: {} })

if (!update) {
Object.defineProperty(target, '_diff', {
Expand All @@ -19,20 +19,20 @@ function observeObject <T extends object> (target: T, label: string, update?: ()

return new Proxy(target as Observed<T, any>, {
get (target, key) {
if (key in target._proxy) return target._proxy[key]
if (key in target.__proxyGetters__) return target.__proxyGetters__[key]
const value = target[key]
if (!value || staticTypes.includes(typeof value) || typeof key === 'string' && key.startsWith('_')) return value
const _update = update || (() => {
const hasKey = key in target._diff
target._diff[key] = target._proxy[key]
target._diff[key] = target.__proxyGetters__[key]
if (!hasKey && label) {
showObserverLog(`[diff] ${label}: ${String(key)} (deep)`)
}
})
if (Array.isArray(value)) {
return target._proxy[key] = observeArray(value, label, _update)
return target.__proxyGetters__[key] = observeArray(value, label, _update)
} else {
return target._proxy[key] = observeObject(value, label, _update)
return target.__proxyGetters__[key] = observeObject(value, label, _update)
}
},
set (target, key, value) {
Expand All @@ -42,7 +42,7 @@ function observeObject <T extends object> (target: T, label: string, update?: ()
} else if (typeof key !== 'string' || !key.startsWith('_')) {
const hasKey = key in target._diff
target._diff[key] = value
delete target._proxy[key]
delete target.__proxyGetters__[key]
if (!hasKey && label) {
showObserverLog(`[diff] ${label}: ${String(key)}`)
}
Expand Down Expand Up @@ -95,9 +95,10 @@ function observeArray <T> (target: T[], label: string, update: () => void) {

export type Observed <T, R = any> = T & {
_diff: Partial<T>
_proxy: Partial<T>
_update: () => R
_merge: (value: Partial<T>) => Observed <T, R>
_merge: (value: Partial<T>) => Observed<T, R>
__proxyGetters__: Partial<T>
__updateCallback__: UpdateFunction<T, R>
}

type UpdateFunction <T, R> = (diff: Partial<T>) => R
Expand All @@ -120,7 +121,12 @@ export function observe <T extends object, R> (target: T, ...args: [(string | nu
if (typeof args[0] === 'function') update = args.shift() as UpdateFunction<T, R>
if (typeof args[0] === 'string') label = args[0]

if (label && label in refs) return refs[label]._merge(target)
if (label && label in refs) {
refs[label].__updateCallback__ = update
return refs[label]._merge(target)
}

Object.defineProperty(target, '__updateCallback__', { value: update, writable: true })

Object.defineProperty(target, '_update', {
value (this: Observed<T, R>) {
Expand All @@ -129,7 +135,7 @@ export function observe <T extends object, R> (target: T, ...args: [(string | nu
if (fields.length) {
if (label) showObserverLog(`[update] ${label}: ${fields.join(', ')}`)
this._diff = {}
return update(diff)
return this.__updateCallback__(diff)
}
},
})
Expand All @@ -139,7 +145,7 @@ export function observe <T extends object, R> (target: T, ...args: [(string | nu
for (const key in value) {
if (!(key in this._diff)) {
target[key] = value[key]
delete this._proxy[key]
delete this.__proxyGetters__[key]
}
}
return this
Expand Down
23 changes: 22 additions & 1 deletion packages/test-utils/src/database.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { App, DatabaseConfig, createUser, createGroup } from 'koishi-core'
import { App, DatabaseConfig, createUser, createGroup, GroupData, UserData } from 'koishi-core'
import { createArray } from './utils'

type TestHook = (app: App) => any
Expand Down Expand Up @@ -95,6 +95,7 @@ export function testDatabase (config: DatabaseConfig, options: TestDatabaseOptio
await expect(db.getUsers([48], ['id'])).resolves.toHaveLength(0)
await expect(db.getUsers([49], ['id'])).resolves.toHaveLength(1)
await expect(db.getUsers([1, 2, 3, 4])).resolves.toHaveLength(3)
await expect(db.getUsers([])).resolves.toHaveLength(0)
})

test('observeUser update', async () => {
Expand All @@ -108,6 +109,16 @@ export function testDatabase (config: DatabaseConfig, options: TestDatabaseOptio
expect(user.id).toBe(id)
expect(user.flag).toBe(flag)
})

test('observeUser merge', async () => {
const user: UserData = { id: 1000, flag: 3, name: '', authority: 1, usage: {} }
const observedUser = await db.observeUser(user, 1)
expect(observedUser).toMatchObject(user)
observedUser.flag = 5
await observedUser._update()
await expect(db.observeUser(observedUser)).resolves.toBe(observedUser)
await expect(db.getUser(user.id)).resolves.toMatchObject({ flag: 5 })
})
})

describe('group operations', () => {
Expand Down Expand Up @@ -184,6 +195,16 @@ export function testDatabase (config: DatabaseConfig, options: TestDatabaseOptio
expect(group.id).toBe(id)
expect(group.flag).toBe(flag)
})

test('observeGroup merge', async () => {
const group: GroupData = { id: 5, flag: 3, assignee: 2 }
const observedGroup = await db.observeGroup(group, 1)
expect(observedGroup).toMatchObject(group)
observedGroup.flag = 5
await observedGroup._update()
await expect(db.observeGroup(observedGroup)).resolves.toBe(observedGroup)
await expect(db.getGroup(group.id)).resolves.toMatchObject({ flag: 5 })
})
})

return app
Expand Down

0 comments on commit 7f9756c

Please sign in to comment.