Commit 16765d8c authored by nanahira's avatar nanahira

add field mixin

parent 6746196e
import { Context, Keys, Model } from 'koishi';
import { Context, Dict, Flatten, Keys, Model, Tables } from 'koishi';
import { ModelClassType } from './def';
import { reflector } from './meta/meta';
import _ from 'lodash';
class ModelRegistrar<T = any> {
constructor(private cls: ModelClassType<T>, private prefix = '') {}
......@@ -170,3 +171,23 @@ export function registerModel(
ctx.model.extend(tableName, ...registrar.getModelResult());
Object.assign(ctx.model.config[tableName].internal, registrar.getInternal());
}
export function mixinModel<K extends Keys<Tables>>(
ctx: Context,
tableName: K,
classDict: {
[F in Keys<Tables[K]>]?: ModelClassType<Flatten<Tables[K][F]>>;
},
) {
for (const _key in classDict) {
const key = _key as Keys<Tables[K]>;
const cls = classDict[key];
const registrar = new ModelRegistrar<any>(cls, key + '.');
const result = registrar.getModelResult();
ctx.model.extend(tableName, ...result);
Object.assign(
ctx.model.config[tableName].internal,
registrar.getInternal(),
);
}
}
import { ChildModel, DefineModel, ModelField } from '../src/decorators';
import { App } from 'koishi';
import { registerModel } from '../src/register';
import { mixinModel, registerModel } from '../src/register';
import MemoryDatabase from '@koishijs/plugin-database-memory';
import exp from 'constants';
declare module 'koishi' {
// eslint-disable-next-line @typescript-eslint/no-empty-interface
......@@ -11,30 +12,38 @@ declare module 'koishi' {
}
}
class Dress {
class WearingPreference {
@ModelField('string(8)')
color: string;
@ModelField('integer(7)')
size: string;
@ModelField('string(12)')
shape: string;
format() {
return `${this.color} ${this.shape}`;
}
}
class Shirt {
@ModelField('string(8)')
color: string;
@ModelField('integer(7)')
class Wearing {
@ModelField('string(3)')
size: string;
}
@DefineModel('user')
class UserMixin1 {
getSize() {
return this.size;
}
@ChildModel()
dress: Dress;
preference: WearingPreference;
}
@DefineModel('user')
class UserMixin2 {
@ChildModel()
shirt: Shirt;
class Dress extends Wearing {
getDressSize() {
return this.getSize();
}
}
class Shirt extends Wearing {
getShirtSize() {
return this.getSize();
}
}
describe('Model test', () => {
......@@ -43,22 +52,63 @@ describe('Model test', () => {
beforeEach(async () => {
app = new App();
app.plugin(MemoryDatabase);
mixinModel(app, 'user', { dress: Dress, shirt: Shirt });
await app.start();
});
it('should register model fields', () => {
registerModel(app, UserMixin1);
registerModel(app, UserMixin2);
const { user } = app.model.config;
expect(user.fields['dress.color'].type).toBe('string');
expect(user.fields['dress.size'].type).toBe('integer');
expect(user.fields['dress.color'].length).toBe(8);
expect(user.fields['dress.size'].length).toBe(7);
expect(user.fields['shirt.color'].type).toBe('string');
expect(user.fields['shirt.size'].type).toBe('integer');
expect(user.fields['shirt.color'].length).toBe(8);
expect(user.fields['shirt.size'].length).toBe(7);
expect(user.fields['dress.size'].type).toBe('string');
expect(user.fields['dress.size'].length).toBe(3);
expect(user.fields['shirt.size'].type).toBe('string');
expect(user.fields['shirt.size'].length).toBe(3);
expect(user.fields['dress.preference.color'].type).toBe('string');
expect(user.fields['dress.preference.color'].length).toBe(8);
expect(user.fields['shirt.preference.color'].type).toBe('string');
expect(user.fields['shirt.preference.color'].length).toBe(8);
expect(user.fields['dress.preference.shape'].type).toBe('string');
expect(user.fields['dress.preference.shape'].length).toBe(12);
expect(user.fields['shirt.preference.shape'].type).toBe('string');
expect(user.fields['shirt.preference.shape'].length).toBe(12);
expect(user.internal['dress.']).toEqual(Dress.prototype);
expect(user.internal['shirt.']).toEqual(Shirt.prototype);
expect(user.internal['dress.preference.']).toEqual(
WearingPreference.prototype,
);
expect(user.internal['shirt.preference.']).toEqual(
WearingPreference.prototype,
);
});
it('should make class instance', async () => {
await app.database.upsert('user', [
{
id: '111111',
dress: {
size: 'S',
preference: {
color: 'red',
shape: 'round',
},
},
shirt: {
size: 'M',
preference: {
color: 'blue',
shape: 'square',
},
},
},
]);
const [user] = await app.database.get('user', { id: '111111' });
expect(user.dress).toBeInstanceOf(Dress);
expect(user.dress.getDressSize()).toBe('S');
expect(user.dress.preference).toBeInstanceOf(WearingPreference);
expect(user.dress.preference.format()).toBe('red round');
expect(user.shirt).toBeInstanceOf(Shirt);
expect(user.shirt.getShirtSize()).toBe('M');
expect(user.shirt.preference).toBeInstanceOf(WearingPreference);
expect(user.shirt.preference.format()).toBe('blue square');
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment