tachybase_todo/packages/database/src/__tests__/model/model.test.ts

964 lines
24 KiB
TypeScript

import Database from '../..';
import { getDatabase } from '..';
import Model, { ModelCtor } from '../../model';
let db: Database;
beforeEach(async () => {
db = getDatabase();
});
afterEach(async () => {
await db.close();
});
describe('actions', () => {
beforeEach(async () => {
db.table({
name: 'users',
tableName: 'user1234',
fields: [
{
type: 'string',
name: 'name',
},
{
type: 'hasone',
name: 'profile',
},
{
type: 'hasMany',
name: 'posts',
},
{
type: 'hasMany',
name: 'posts_title1',
target: 'posts',
scope: {
title: 'title1',
},
}
]
});
db.table({
name: 'profiles',
tableName: 'profile1234',
fields: [
{
type: 'string',
name: 'name',
},
]
});
db.table({
name: 'posts',
tableName: 'post123456',
fields: [
{
type: 'string',
name: 'title',
},
{
type: 'belongsTo',
name: 'user',
},
{
type: 'belongsToMany',
name: 'tags',
},
{
type: 'belongsToMany',
name: 'tags_name1',
target: 'tags',
scope: {
name: 'name1',
},
},
{
type: 'hasmany',
name: 'comments',
},
{
type: 'hasmany',
name: 'current_user_comments',
target: 'comments',
},
]
});
db.table({
name: 'posts_tags',
tableName: 'posts_tags1234',
fields: [
{
type: 'string',
name: 'name',
},
]
});
db.table({
name: 'tags',
tableName: 'tag1234',
fields: [
{
type: 'string',
name: 'name',
},
{
type: 'belongsToMany',
name: 'posts',
},
],
});
db.table({
name: 'comments',
tableName: 'comment1234',
fields: [
{
type: 'belongsTo',
name: 'user',
},
{
type: 'belongsTo',
name: 'post',
},
{
type: 'string',
name: 'content',
}
]
});
db.table({
name: 'tables',
fields: [
{
type: 'string',
name: 'name',
primaryKey: true,
autoIncrement: false,
},
{
type: 'hasMany',
name: 'fields',
}
],
});
db.table({
name: 'fields',
fields: [
{
type: 'belongsTo',
name: 'table',
},
{
type: 'string',
name: 'name',
}
],
});
db.table({
name: 'rows',
fields: [
{
type: 'string',
name: 'name',
unique: true,
},
{
type: 'hasMany',
name: 'columns',
sourceKey: 'name',
}
],
});
db.table({
name: 'columns',
fields: [
{
type: 'belongsTo',
name: 'row',
targetKey: 'name',
},
{
type: 'string',
name: 'name',
}
],
});
await db.sync({
force: true,
});
});
it('through attributes', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tag = await Tag.create();
await post.updateAssociations({
tags: [{
name: 'xxx',
posts_tags: {
name: 'name134',
}
}, {
id: tag.id,
posts_tags: {
name: 'name234',
}
}],
});
const PostTag = db.getModel('posts_tags');
const [t1, t2] = await PostTag.findAll({
where: {
post_id: post.id,
},
order: ['tag_id'],
});
expect(t1.name).toBe('name234');
expect(t2.name).toBe('name134');
});
describe('scope', () => {
it('scope', async () => {
const [User, Post, Comment] = db.getModels(['users', 'posts', 'comments']);
const user1 = await User.create();
const user2 = await User.create();
const user3 = await User.create();
const user4 = await User.create();
const post = await Post.create();
const comment = await Comment.create();
comment.updateAssociations({
post: post,
user: user1,
});
await post.updateAssociations({
comments: [
{
content: 'content1',
user: user1,
},
{
content: 'content2',
user: user2,
},
{
content: 'content3',
user: user3,
},
{
content: 'content4',
user: user4,
},
],
});
const comments = await post.getCurrent_user_comments();
// TODO: no expect
});
});
describe('query', () => {
it('q', async () => {
db.getModel('tags').addScope('scopeName', (name, ctx) => {
expect(ctx.scopeName).toBe(name);
return {
where: {
name: name,
}
}
});
const [User, Post] = db.getModels(['users', 'posts']);
const postData = [];
for (let index = 0; index < 20; index++) {
postData.push({
title: `title${index}`,
});
}
const user = await User.create({
name: 'name112233',
});
await Post.create({
title: 'xxxx',
});
const post = await Post.create({
title: 'title112233',
});
await user.updateAssociations({
posts: post,
});
await post.updateAssociations({
tags: [
{name: 'tag1'},
{name: 'tag2'},
{name: 'tag3'},
],
});
// where & include
const options = Post.parseApiJson({
filter: {
title: 'title112233',
user: { // belongsTo
name: 'name112233',
},
tags: { // belongsToMany
scopeName: 'tag3',
},
},
fields: [
'title',
'tags_count',
'tags.name',
'user.name'
],
sort: '-tags_count,tags.name,user.posts_count',
context: {
scopeName: 'tag3',
},
});
console.log(options);
try{
// DatabaseError [SequelizeDatabaseError]: column tags.scopeName does not exist
// SELECT count("posts"."id") AS "count" FROM "post123456" AS "posts" INNER JOIN ( "posts_tags1234" AS "tags->posts_tags" INNER JOIN "tag1234" AS "tags" ON "tags"."id" = "tags->posts_tags"."tag_id") ON "posts"."id" = "tags->posts_tags"."post_id" AND "tags"."scopeName" = 'tag3' INNER JOIN "user1234" AS "user" ON "posts"."user_id" = "user"."id" AND "user"."name" = 'name112233' WHERE "posts"."title" = 'title112233';
const { rows, count } = await Post.findAndCountAll({
...options,
// group: ['id'],
// limit: 20,
// offset: 20,
});
// console.log(JSON.stringify(rows[0].toJSON(), null, 2));
rows.forEach(row => {
// expect(row.toJSON()).toEqual({ title: 'title112233', 'tags_count': 3, user: { name: 'name112233', posts_count: 1 } });
expect(row.get('title')).toBe('title112233');
expect(row.user.get('name')).toBe('name112233');
});
} catch(error) {
console.error(error);
}
// console.log(count);
// expect(count).toBe(1);
});
it('to be explained', async () => {
const [User, Post] = db.getModels(['users', 'posts']);
const postData = [];
for (let index = 0; index < 20; index++) {
postData.push({
title: `title${index}`,
});
}
const user = await User.create();
let posts = await Post.bulkCreate(postData);
await user.updateAssociations({
posts: posts,
});
const userOne = await User.findOne({
attributes: {
exclude: ['updated_at'],
include: [
User.withCountAttribute('posts'),
User.withCountAttribute('posts_title1'),
],
},
where: {
id: user.id,
},
});
expect(userOne.get('posts_count')).toBe(20);
expect(userOne.get('posts_title1_count')).toBe(1);
});
it('to be explained', async () => {
const [User, Post] = db.getModels(['users', 'posts']);
const postData = [];
for (let index = 0; index < 20; index++) {
postData.push({
title: `title${index}`,
});
}
const user = await User.create();
let posts = await Post.bulkCreate(postData);
await user.updateAssociations({
posts: posts,
});
const userOne = await User.findOne({
attributes: {
exclude: ['updated_at'],
include: [
User.withCountAttribute({
association: 'posts',
alias: 'posts2_count'
}),
],
},
where: {
id: user.id,
},
});
expect(userOne.get('posts2_count')).toBe(20);
});
it('to be explained', async () => {
const [Tag, Post, User] = db.getModels(['tags', 'posts', 'users']);
const tagData = [];
for (let index = 0; index < 5; index++) {
tagData.push({
name: `name${index}`,
});
}
let post = await Post.create();
let tags = await Tag.bulkCreate(tagData);
await post.updateAssociations({
user: {
name: 'user1',
},
tags,
});
post = await Post.findOne({
attributes: {
include: [
'id',
Post.withCountAttribute('tags'),
Post.withCountAttribute('tags_name1'),
],
},
where: {
id: post.id,
},
include: [
{
association: 'user',
attributes: ['id', 'name',
User.withCountAttribute({
sourceAlias: 'user',
association: 'posts',
}),
],
},
{
association: 'tags',
attributes: ['id', 'name', Tag.withCountAttribute('posts')],
},
],
});
expect(post.get('tags_count')).toBe(5);
expect(post.get('tags_name1_count')).toBe(1);
expect(post.user.get('posts_count')).toBe(1);
post.tags.forEach(tag => {
expect(tag.get('posts_count')).toBe(1);
});
});
});
describe('hasOne', () => {
it('shoud associated id when association is integer', async () => {
const [User, Profile] = db.getModels(['users', 'profiles']);
const user = await User.create();
const profile = await Profile.create();
await user.updateAssociations({
// 关联 id
profile,
});
const userProfile = await user.getProfile();
expect(userProfile.id).toBe(profile.id);
});
it('shoud associated id when association is integer', async () => {
const [User, Profile] = db.getModels(['users', 'profiles']);
const user = await User.create();
const profile = await Profile.create();
await user.updateAssociations({
// 关联 id
profile: profile.id,
});
const userProfile = await user.getProfile();
expect(userProfile.id).toBe(profile.id);
});
it('shoud associated id when association is integer', async () => {
const [User, Profile] = db.getModels(['users', 'profiles']);
const user = await User.create();
const profile = await Profile.create();
await user.updateAssociations({
// 关联 id
profile: {
id: profile.id,
},
});
const userProfile = await user.getProfile();
expect(userProfile.id).toBe(profile.id);
});
it('shoud associated id when association is integer', async () => {
const [User, Profile] = db.getModels(['users', 'profiles']);
const user = await User.create();
const profile = await Profile.create();
await user.updateAssociations({
// 关联 id
profile: {
id: profile.id,
name: 'profile1',
},
});
const userProfile = await user.getProfile();
expect(userProfile.id).toBe(profile.id);
expect(userProfile.name).toBe('profile1');
});
it('shoud associated id when association is integer', async () => {
const [User] = db.getModels(['users']);
const user = await User.create();
await user.updateAssociations({
// 关联 id
profile: {
name: 'profile2',
},
});
const userProfile = await user.getProfile();
expect(userProfile.name).toBe('profile2');
});
});
describe('hasMany', () => {
it('@1', async () => {
const [Comment, Post] = db.getModels(['comments', 'posts']);
const comment = await Comment.create();
const post = await Post.create();
await post.updateAssociations({
comments: comment,
});
const count = await post.countComments();
expect(count).toBe(1);
});
it('@2', async () => {
const [Comment, Post] = db.getModels(['comments', 'posts']);
const comment = await Comment.create();
const post = await Post.create();
await post.updateAssociations({
comments: [comment],
});
const count = await post.countComments();
expect(count).toBe(1);
});
it('@3', async () => {
const [Comment, Post] = db.getModels(['comments', 'posts']);
const comment = await Comment.create();
const post = await Post.create();
await post.updateAssociations({
comments: [comment.id],
});
const count = await post.countComments();
expect(count).toBe(1);
});
it('@4', async () => {
const [Comment, Post] = db.getModels(['comments', 'posts']);
const comment = await Comment.create();
const post = await Post.create();
await post.updateAssociations({
comments: comment.id,
});
const count = await post.countComments();
expect(count).toBe(1);
});
it('@5', async () => {
const [Post] = db.getModels(['posts']);
const post = await Post.create();
await post.updateAssociations({
comments: {
content: 'content1',
},
});
const count = await post.countComments();
expect(count).toBe(1);
});
it('@6', async () => {
const [Post, Comment] = db.getModels(['posts', 'comments']);
const post = await Post.create();
const comment1 = await Comment.create();
const comment2 = await Comment.create();
await post.updateAssociations({
comments: [
{
content: 'content2',
},
{
content: 'content3',
},
{
id: comment1.id,
},
comment2,
],
});
const count = await post.countComments();
expect(count).toBe(4);
});
it('shoud work1', async () => {
const [Table, Field] = db.getModels(['tables', 'fields']);
const table = await Table.create({
name: 'examples',
});
await table.updateAssociations({
fields: [
{name: 'name'},
]
});
const field = await Field.findOne({
where: {
table_name: 'examples',
name: 'name',
},
});
expect(field).toBeDefined();
expect(field.get('name')).toBe('name');
});
it('shoud work2', async () => {
const [Row, Column] = db.getModels(['rows', 'columns']);
const row = await Row.create({
name: 'examples',
});
await row.updateAssociations({
columns: [
{name: 'name'},
]
});
const column = await Column.findOne({
where: {
row_name: 'examples',
name: 'name',
},
});
expect(column).toBeDefined();
expect(column.get('name')).toBe('name');
});
it('shoud work3', async () => {
const [Table, Field] = db.getModels(['tables', 'fields']);
const table = await Table.create({
name: 'abcdef',
});
const field = await Field.create({name: 'name123'});
await table.updateAssociations({
fields: [
{
id: field.id,
name: 'nam1234',
},
]
});
const f = await Field.findOne({
where: {
table_name: 'abcdef',
name: 'nam1234',
},
});
expect(f).toBeDefined();
expect(f.id).toBe(field.id);
const options = Table.parseApiJson({
fields: ['name', 'fields_count'],
});
const t = await Table.findOne(options);
expect(t.get('fields_count')).toBe(1);
});
});
describe('blongsTo', () => {
it('shoud associated id when association is integer', async () => {
const [User, Post] = db.getModels(['users', 'posts']);
const user = await User.create();
const post = await Post.create();
await post.updateAssociations({
// 关联 id
user,
});
expect(user.id).toBe(post.user_id);
const postUser = await post.getUser();
expect(user.id).toBe(postUser.id);
});
it('shoud associated id when association is integer', async () => {
const [User, Post] = db.getModels(['users', 'posts']);
const user = await User.create();
const post = await Post.create();
await post.updateAssociations({
// 关联 id
user: user.id,
});
expect(user.id).toBe(post.user_id);
const postUser = await post.getUser();
expect(user.id).toBe(postUser.id);
});
it('shoud associated id when association is object only id attribute', async () => {
const [User, Tag, Post] = db.getModels(['users', 'tags', 'posts']);
const user = await User.create();
const post = await Post.create();
await post.updateAssociations({
// 关联 id
user: {
id: user.id,
},
});
expect(user.id).toBe(post.user_id);
const postUser = await post.getUser();
expect(user.id).toBe(postUser.id);
});
it('shoud associate and update other attributes', async () => {
const [User, Post] = db.getModels(['users', 'posts']);
const user = await User.create();
let post = await Post.create();
await post.updateAssociations({
// 关联并更新当前 id 的数据
user: {
id: user.id,
name: 'user1234',
},
});
expect(user.id).toBe(post.user_id);
const postUser = await post.getUser();
expect(user.id).toBe(postUser.id);
expect(postUser.name).toBe('user1234');
});
it('shoud work', async () => {
const [Post] = db.getModels(['posts']);
const post = await Post.create();
await post.updateAssociations({
// 新建并关联 user
user: {
name: 'user123456',
},
});
const postUser = await post.getUser();
expect(postUser.name).toBe('user123456');
});
it('shoud work', async () => {
const [Table, Field] = db.getModels(['tables', 'fields']);
const field = await Field.create({
name: 'fieldName',
});
await Table.create({name: 'demos'});
await field.updateAssociations({
table: 'demos',
});
expect(field.table_name).toBe('demos');
});
it('shoud work', async () => {
const [Row, Column] = db.getModels(['rows', 'columns']);
await Row.create({
name: 't1_examples',
});
const column = await Column.create();
await column.updateAssociations({
row: 't1_examples',
});
});
it('shoud work', async () => {
const [Row, Column] = db.getModels(['rows', 'columns']);
await Row.create({
name: 't2_examples',
});
const column = await Column.create();
await column.updateAssociations({
row: {
name: 't2_examples',
},
});
});
});
describe('belongsToMany', () => {
it('@', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tag = await Tag.create();
await post.updateAssociations({
tags: tag,
});
const count = await post.countTags();
expect(count).toBe(1);
});
it('@', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tag = await Tag.create();
await post.updateAssociations({
tags: [tag],
});
const count = await post.countTags();
expect(count).toBe(1);
});
it('@', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tag = await Tag.create();
await post.updateAssociations({
tags: tag.id,
});
const count = await post.countTags();
expect(count).toBe(1);
});
it('@', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tag = await Tag.create();
await post.updateAssociations({
tags: [tag.id],
});
const count = await post.countTags();
expect(count).toBe(1);
});
it('@', async () => {
const [Post, Tag] = db.getModels(['posts', 'tags']);
const post = await Post.create();
const tags = await Tag.bulkCreate([{}, {}]);
await post.updateAssociations({
tags: tags,
});
const count = await post.countTags();
expect(count).toBe(2);
});
it('@', async () => {
const [Post] = db.getModels(['posts']);
const post = await Post.create();
await post.updateAssociations({
tags: {
name: 'tag1'
},
});
const count = await post.countTags();
expect(count).toBe(1);
});
it('@', async () => {
const [Post] = db.getModels(['posts']);
const post = await Post.create();
await post.updateAssociations({
tags: [
{
name: 'tag2'
},
{
name: 'tag3'
},
],
});
const count = await post.countTags();
expect(count).toBe(2);
});
});
});
describe('belongsToMany', () => {
let post: Model;
let tag1: Model;
let tag2: Model;
beforeEach(async () => {
db.table({
name: 'posts',
tableName: 't333333_posts',
fields: [
{
type: 'string',
name: 'slug',
unique: true,
},
{
type: 'belongsToMany',
name: 'tags',
sourceKey: 'slug',
targetKey: 'name',
},
],
});
db.table({
name: 'tags',
tableName: 't333333_tags',
fields: [
{
type: 'string',
name: 'name',
unique: true,
},
{
type: 'belongsToMany',
name: 'posts',
sourceKey: 'name',
targetKey: 'slug',
},
],
});
await db.sync({force: true});
const [ Post, Tag ] = db.getModels(['posts', 'tags']);
post = await Post.create({slug: 'post1'});
tag1 = await Tag.create({name: 'tag1'});
tag2 = await Tag.create({name: 'tag2'});
});
it('@', async () => {
await post.updateAssociations({
tags: tag1.name,
});
expect(await post.countTags()).toBe(1);
});
it('@', async () => {
await post.updateAssociations({
tags: tag2.id,
});
expect(await post.countTags()).toBe(1);
});
it('@', async () => {
await post.updateAssociations({
tags: [tag1, tag2],
});
expect(await post.countTags()).toBe(2);
});
it('@', async () => {
await post.updateAssociations({
tags: {
name: 'tag2',
},
});
expect(await post.countTags()).toBe(1);
expect((await post.getTags())[0].id).toBe(tag2.id);
});
it('@', async () => {
await post.updateAssociations({
tags: [{
name: 'tag3',
}],
});
expect(await post.countTags()).toBe(1);
});
});