chore(database): merge fields arguments by path (#2331)

* feat: merge fields array arg

* chore: test

* chore: test

* chore: test

* fix: test
This commit is contained in:
ChengLei Shao 2023-07-28 16:46:43 +08:00 committed by GitHub
parent fd6d5ac2a6
commit 493965f848
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 137 additions and 71 deletions

View File

@ -112,81 +112,115 @@ describe('option parser', () => {
]); ]);
}); });
test('option parser with fields option', async () => { describe('options parser with fields option', () => {
let options: any = { it('should handle field and association', () => {
const options: any = {
fields: ['id', 'posts'], fields: ['id', 'posts'],
}; };
// 转换为 attributes: ['id'], include: [{association: 'posts'}] // 转换为 attributes: ['id'], include: [{association: 'posts'}]
let parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
let params = parser.toSequelizeParams();
const params = parser.toSequelizeParams();
console.log(params);
expect(params['attributes']).toContain('id'); expect(params['attributes']).toContain('id');
expect(params['include'][0]['association']).toEqual('posts'); expect(params['include'][0]['association']).toEqual('posts');
});
// only appends it('should handle field with association', () => {
options = { const options = {
appends: ['posts'], appends: ['posts'],
}; };
parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
params = parser.toSequelizeParams(); const params = parser.toSequelizeParams();
expect(params['attributes']['include']).toEqual([]); expect(params['attributes']['include']).toEqual([]);
expect(params['include'][0]['association']).toEqual('posts'); expect(params['include'][0]['association']).toEqual('posts');
});
it('should handle field with association field', () => {
// fields with association field // fields with association field
options = { const options = {
fields: ['id', 'posts.title'], fields: ['id', 'posts.title'],
}; };
parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
params = parser.toSequelizeParams();
const params = parser.toSequelizeParams();
expect(params['attributes']).toContain('id'); expect(params['attributes']).toContain('id');
expect(params['include'][0]['association']).toEqual('posts'); expect(params['include'][0]['association']).toEqual('posts');
expect(params['include'][0]['attributes']).toContain('title'); expect(params['include'][0]['attributes']).toContain('title');
});
it('should handle nested fields option', () => {
const options = {
fields: ['posts', 'posts.title'],
};
const parser = new OptionsParser(options, {
collection: User,
});
const params = parser.toSequelizeParams();
const postAssociationParams = params['include'][0];
expect(postAssociationParams['attributes']).toEqual({ include: [] });
});
it('should handle fields with association & association field', () => {
// fields with nested field // fields with nested field
options = { const options = {
fields: ['id', 'posts', 'posts.comments.content'], fields: ['id', 'posts', 'posts.comments.content'],
}; };
parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
params = parser.toSequelizeParams();
expect(params['attributes']).toContain('id');
expect(params['include'][0]['association']).toEqual('posts');
expect(params['include'][0]['attributes']).toEqual({ include: [] });
expect(params['include'][0]['include'][0]['association']).toEqual('comments');
const params = parser.toSequelizeParams();
const postAssociationParams = params['include'][0];
expect(params['attributes']).toContain('id');
expect(postAssociationParams['association']).toEqual('posts');
expect(postAssociationParams['attributes']).toEqual({ include: [] });
expect(postAssociationParams['include'][0]['association']).toEqual('comments');
});
it('should handle except option', () => {
// fields with expect // fields with expect
options = { const options = {
except: ['id'], except: ['id'],
}; };
parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
params = parser.toSequelizeParams();
expect(params['attributes']['exclude']).toContain('id');
const params = parser.toSequelizeParams();
expect(params['attributes']['exclude']).toContain('id');
});
it('should handle fields with except option', () => {
// expect with association // expect with association
options = { const options = {
fields: ['posts'], fields: ['posts'],
except: ['posts.id'], except: ['posts.id'],
}; };
parser = new OptionsParser(options, { const parser = new OptionsParser(options, {
collection: User, collection: User,
}); });
params = parser.toSequelizeParams(); const params = parser.toSequelizeParams();
expect(params['include'][0]['attributes']['exclude']).toContain('id'); expect(params['include'][0]['attributes']['exclude']).toContain('id');
}); });
});
test('option parser with multiple association', () => { test('option parser with multiple association', () => {
// fields with association field // fields with association field

View File

@ -378,23 +378,33 @@ describe('repository find', () => {
}); });
}); });
describe('find with fields', () => {
it('should only output filed in fields args', async () => { it('should only output filed in fields args', async () => {
const resp = await User.model.findOne({
attributes: [],
include: [
{
association: 'profile',
attributes: ['salary'],
},
],
});
const users = await User.repository.find({ const users = await User.repository.find({
fields: ['profile', 'profile.salary', 'profile.id'], fields: ['profile.salary'],
}); });
const firstUser = users[0].toJSON(); const firstUser = users[0].toJSON();
expect(Object.keys(firstUser)).toEqual(['profile']); expect(Object.keys(firstUser)).toEqual(['profile']);
expect(Object.keys(firstUser.profile)).toEqual(['salary']);
});
it('should output all fields when field has relation field', async () => {
const users = await User.repository.find({
fields: ['profile.salary', 'profile'],
});
const firstUser = users[0].toJSON();
expect(Object.keys(firstUser)).toEqual(['profile']);
expect(Object.keys(firstUser.profile)).toEqual([
'id',
'createdAt',
'updatedAt',
'salary',
'userId',
'description',
]);
});
}); });
it('append with associations', async () => { it('append with associations', async () => {

View File

@ -240,6 +240,9 @@ export class OptionsParser {
protected parseAppends(appends: Appends, filterParams: any) { protected parseAppends(appends: Appends, filterParams: any) {
if (!appends) return filterParams; if (!appends) return filterParams;
// sort appends by path length
appends = lodash.sortBy(appends, (append) => append.split('.').length);
/** /**
* set include params * set include params
* @param model * @param model
@ -287,6 +290,25 @@ export class OptionsParser {
// if include from filter, remove fromFilter attribute // if include from filter, remove fromFilter attribute
if (existIncludeIndex != -1) { if (existIncludeIndex != -1) {
delete queryParams['include'][existIncludeIndex]['fromFilter']; delete queryParams['include'][existIncludeIndex]['fromFilter'];
// set include attributes to all attributes
if (
Array.isArray(queryParams['include'][existIncludeIndex]['attributes']) &&
queryParams['include'][existIncludeIndex]['attributes'].length == 0
) {
queryParams['include'][existIncludeIndex]['attributes'] = {
include: [],
};
}
}
if (
lastLevel &&
existIncludeIndex != -1 &&
lodash.get(queryParams, ['include', existIncludeIndex, 'attributes', 'include'])?.length == 0
) {
// if append is last level and association exists, ignore it
return;
} }
// if association not exist, create it // if association not exist, create it