Merge branch 'main' into next

This commit is contained in:
nocobase[bot] 2024-12-16 07:02:30 +00:00
commit 289d476ad1
13 changed files with 649 additions and 123 deletions

View File

@ -248,41 +248,66 @@ describe('belongs to many with target key', function () {
expect(count).toEqual(0);
});
test('destroy with target key and filter', async () => {
const t1 = await Tag.repository.create({
values: {
name: 't1',
status: 'published',
},
});
const t2 = await Tag.repository.create({
values: {
name: 't2',
status: 'draft',
},
});
test('firstOrCreate', async () => {
const p1 = await Post.repository.create({
values: { title: 'p1' },
});
const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.get('title') as string);
await PostTagRepository.set([t1.get('name') as string, t2.get('name') as string]);
let [_, count] = await PostTagRepository.findAndCount();
expect(count).toEqual(2);
await PostTagRepository.destroy({
filterByTk: t1.get('name') as string,
filter: {
status: 'draft',
// 测试基本创建
const tag1 = await PostTagRepository.firstOrCreate({
filterKeys: ['name'],
values: {
name: 't1',
status: 'active',
},
});
[_, count] = await PostTagRepository.findAndCount();
expect(count).toEqual(2);
expect(tag1.name).toEqual('t1');
expect(tag1.status).toEqual('active');
// 测试查找已存在记录
const tag2 = await PostTagRepository.firstOrCreate({
filterKeys: ['name'],
values: {
name: 't1',
status: 'inactive',
},
});
expect(tag2.id).toEqual(tag1.id);
expect(tag2.status).toEqual('active');
});
test('updateOrCreate', async () => {
const p1 = await Post.repository.create({
values: { title: 'p1' },
});
const PostTagRepository = new BelongsToManyRepository(Post, 'tags', p1.get('title') as string);
const tag1 = await PostTagRepository.updateOrCreate({
filterKeys: ['name'],
values: {
name: 't1',
status: 'active',
},
});
expect(tag1.name).toEqual('t1');
expect(tag1.status).toEqual('active');
const tag2 = await PostTagRepository.updateOrCreate({
filterKeys: ['name'],
values: {
name: 't1',
status: 'inactive',
},
});
expect(tag2.id).toEqual(tag1.id);
expect(tag2.status).toEqual('inactive');
});
});

View File

@ -0,0 +1,138 @@
import { Collection } from '@nocobase/database';
import Database from '../../database';
import { BelongsToRepository } from '../../relation-repository/belongs-to-repository';
import { mockDatabase } from '../index';
describe('belongs to repository', () => {
let db: Database;
let User: Collection;
let Post: Collection;
beforeEach(async () => {
db = mockDatabase();
await db.clean({ drop: true });
User = db.collection({
name: 'users',
fields: [
{ type: 'string', name: 'name' },
{ type: 'string', name: 'status' },
{ type: 'hasMany', name: 'posts' },
],
});
Post = db.collection({
name: 'posts',
fields: [
{ type: 'string', name: 'title' },
{ type: 'belongsTo', name: 'user' },
],
});
await db.sync();
});
afterEach(async () => {
await db.close();
});
test('firstOrCreate', async () => {
const p1 = await Post.repository.create({
values: { title: 'p1' },
});
const PostUserRepository = new BelongsToRepository(Post, 'user', p1.id);
// 测试基本创建
const user1 = await PostUserRepository.firstOrCreate({
filterKeys: ['name'],
values: {
name: 'u1',
status: 'active',
},
});
expect(user1.name).toEqual('u1');
expect(user1.status).toEqual('active');
// 验证关联是否建立
await p1.reload();
expect(p1.userId).toEqual(user1.id);
// 测试查找已存在记录
const user2 = await PostUserRepository.firstOrCreate({
filterKeys: ['name'],
values: {
name: 'u1',
status: 'inactive',
},
});
expect(user2.id).toEqual(user1.id);
expect(user2.status).toEqual('active');
// 测试多个 filterKeys
const user3 = await PostUserRepository.firstOrCreate({
filterKeys: ['name', 'status'],
values: {
name: 'u1',
status: 'draft',
},
});
expect(user3.id).not.toEqual(user1.id);
expect(user3.status).toEqual('draft');
});
test('updateOrCreate', async () => {
const p1 = await Post.repository.create({
values: { title: 'p1' },
});
const PostUserRepository = new BelongsToRepository(Post, 'user', p1.id);
// 测试基本创建
const user1 = await PostUserRepository.updateOrCreate({
filterKeys: ['name'],
values: {
name: 'u1',
status: 'active',
},
});
expect(user1.name).toEqual('u1');
expect(user1.status).toEqual('active');
// 验证关联是否建立
await p1.reload();
expect(p1.userId).toEqual(user1.id);
// 测试更新已存在记录
const user2 = await PostUserRepository.updateOrCreate({
filterKeys: ['name'],
values: {
name: 'u1',
status: 'inactive',
},
});
expect(user2.id).toEqual(user1.id);
expect(user2.status).toEqual('inactive');
// 测试多个 filterKeys 的创建
const user3 = await PostUserRepository.updateOrCreate({
filterKeys: ['name', 'status'],
values: {
name: 'u1',
status: 'draft',
},
});
expect(user3.id).not.toEqual(user1.id);
expect(user3.status).toEqual('draft');
// 验证关联是否更新
await p1.reload();
expect(p1.userId).toEqual(user3.id);
});
});

View File

@ -149,6 +149,7 @@ describe('has many repository', () => {
fields: [
{ type: 'string', name: 'name' },
{ type: 'hasMany', name: 'posts' },
{ type: 'string', name: 'status' },
],
});
@ -260,6 +261,118 @@ describe('has many repository', () => {
expect(p1.title).toEqual('u1t1');
});
test('firstOrCreate', async () => {
const u1 = await User.repository.create({
values: { name: 'u1' },
});
const UserPostRepository = new HasManyRepository(User, 'posts', u1.id);
// 测试基本创建
const post1 = await UserPostRepository.firstOrCreate({
filterKeys: ['title'],
values: {
title: 't1',
},
});
expect(post1.title).toEqual('t1');
expect(post1.userId).toEqual(u1.id);
// 测试查找已存在记录
const post2 = await UserPostRepository.firstOrCreate({
filterKeys: ['title'],
values: {
title: 't1',
},
});
expect(post2.id).toEqual(post1.id);
// 测试带关联数据的创建
const post3 = await UserPostRepository.firstOrCreate({
filterKeys: ['title'],
values: {
title: 't2',
comments: [{ content: 'comment1' }],
},
});
expect(post3.title).toEqual('t2');
expect(await post3.countComments()).toEqual(1);
// 测试多个 filterKeys
const post4 = await UserPostRepository.firstOrCreate({
filterKeys: ['title', 'status'],
values: {
title: 't2',
status: 'draft',
},
});
expect(post4.id).not.toEqual(post3.id);
});
test('updateOrCreate', async () => {
const u1 = await User.repository.create({
values: { name: 'u1' },
});
const UserPostRepository = new HasManyRepository(User, 'posts', u1.id);
// 测试基本创建
const post1 = await UserPostRepository.updateOrCreate({
filterKeys: ['title'],
values: {
title: 't1',
status: 'draft',
},
});
expect(post1.title).toEqual('t1');
expect(post1.status).toEqual('draft');
expect(post1.userId).toEqual(u1.id);
// 测试更新已存在记录
const post2 = await UserPostRepository.updateOrCreate({
filterKeys: ['title'],
values: {
title: 't1',
status: 'published',
},
});
expect(post2.id).toEqual(post1.id);
expect(post2.status).toEqual('published');
// 测试带关联数据的更新
const post3 = await UserPostRepository.updateOrCreate({
filterKeys: ['title'],
values: {
title: 't1',
status: 'archived',
comments: [{ content: 'new comment' }],
},
});
expect(post3.id).toEqual(post1.id);
expect(post3.status).toEqual('archived');
expect(await post3.countComments()).toEqual(1);
// 测试多个 filterKeys 的创建
const post4 = await UserPostRepository.updateOrCreate({
filterKeys: ['title', 'status'],
values: {
title: 't1',
status: 'draft',
comments: [{ content: 'another comment' }],
},
});
expect(post4.id).not.toEqual(post1.id);
expect(await post4.countComments()).toEqual(1);
});
test('find with has many', async () => {
const u1 = await User.repository.create({ values: { name: 'u1' } });

View File

@ -0,0 +1,128 @@
import { Collection } from '@nocobase/database';
import Database from '../../database';
import { HasOneRepository } from '../../relation-repository/hasone-repository';
import { mockDatabase } from '../index';
describe('has one repository', () => {
let db: Database;
let User: Collection;
let Profile: Collection;
beforeEach(async () => {
db = mockDatabase();
await db.clean({ drop: true });
User = db.collection({
name: 'users',
fields: [
{ type: 'string', name: 'name' },
{ type: 'hasOne', name: 'profile' },
],
});
Profile = db.collection({
name: 'profiles',
fields: [
{ type: 'string', name: 'avatar' },
{ type: 'string', name: 'status' },
{ type: 'belongsTo', name: 'user' },
],
});
await db.sync();
});
afterEach(async () => {
await db.close();
});
test('firstOrCreate', async () => {
const u1 = await User.repository.create({
values: { name: 'u1' },
});
const UserProfileRepository = new HasOneRepository(User, 'profile', u1.id);
// 测试基本创建
const profile1 = await UserProfileRepository.firstOrCreate({
filterKeys: ['avatar'],
values: {
avatar: 'avatar1.jpg',
status: 'active',
},
});
expect(profile1.avatar).toEqual('avatar1.jpg');
expect(profile1.status).toEqual('active');
expect(profile1.userId).toEqual(u1.id);
// 测试查找已存在记录
const profile2 = await UserProfileRepository.firstOrCreate({
filterKeys: ['avatar'],
values: {
avatar: 'avatar1.jpg',
status: 'inactive',
},
});
expect(profile2.id).toEqual(profile1.id);
expect(profile2.status).toEqual('active');
// 测试多个 filterKeys
const profile3 = await UserProfileRepository.firstOrCreate({
filterKeys: ['avatar', 'status'],
values: {
avatar: 'avatar1.jpg',
status: 'draft',
},
});
expect(profile3.id).not.toEqual(profile1.id);
expect(profile3.status).toEqual('draft');
});
test('updateOrCreate', async () => {
const u1 = await User.repository.create({
values: { name: 'u1' },
});
const UserProfileRepository = new HasOneRepository(User, 'profile', u1.id);
// 测试基本创建
const profile1 = await UserProfileRepository.updateOrCreate({
filterKeys: ['avatar'],
values: {
avatar: 'avatar1.jpg',
status: 'active',
},
});
expect(profile1.avatar).toEqual('avatar1.jpg');
expect(profile1.status).toEqual('active');
expect(profile1.userId).toEqual(u1.id);
// 测试更新已存在记录
const profile2 = await UserProfileRepository.updateOrCreate({
filterKeys: ['avatar'],
values: {
avatar: 'avatar1.jpg',
status: 'inactive',
},
});
expect(profile2.id).toEqual(profile1.id);
expect(profile2.status).toEqual('inactive');
// 测试多个 filterKeys 的创建
const profile3 = await UserProfileRepository.updateOrCreate({
filterKeys: ['avatar', 'status'],
values: {
avatar: 'avatar1.jpg',
status: 'draft',
},
});
expect(profile3.id).not.toEqual(profile1.id);
expect(profile3.status).toEqual('draft');
});
});

View File

@ -13,6 +13,7 @@ import { AggregateOptions, CreateOptions, DestroyOptions, TargetKey } from '../r
import { updateAssociations, updateThroughTableValue } from '../update-associations';
import { MultipleRelationRepository } from './multiple-relation-repository';
import { transaction } from './relation-repository';
import { AssociatedOptions, PrimaryKeyWithThroughValues } from './types';
type CreateBelongsToManyOptions = CreateOptions;

View File

@ -8,9 +8,7 @@
*/
import { BelongsTo } from 'sequelize';
import { SingleRelationFindOption, SingleRelationRepository } from './single-relation-repository';
type BelongsToFindOptions = SingleRelationFindOption;
import { SingleRelationRepository } from './single-relation-repository';
export class BelongsToRepository extends SingleRelationRepository {
/**

View File

@ -10,8 +10,9 @@
import { omit } from 'lodash';
import { HasMany, Op } from 'sequelize';
import { AggregateOptions, DestroyOptions, FindOptions, TargetKey, TK } from '../repository';
import { AssociatedOptions, MultipleRelationRepository } from './multiple-relation-repository';
import { MultipleRelationRepository } from './multiple-relation-repository';
import { transaction } from './relation-repository';
import { AssociatedOptions } from './types';
export class HasManyRepository extends MultipleRelationRepository {
async find(options?: FindOptions): Promise<any> {

View File

@ -8,28 +8,22 @@
*/
import lodash from 'lodash';
import { HasOne, MultiAssociationAccessors, Sequelize, Transaction, Transactionable } from 'sequelize';
import { HasOne, MultiAssociationAccessors, Sequelize, Transaction } from 'sequelize';
import injectTargetCollection from '../decorators/target-collection-decorator';
import {
CommonFindOptions,
CountOptions,
DestroyOptions,
Filter,
FindOneOptions,
FindOptions,
TargetKey,
TK,
UpdateOptions,
} from '../repository';
import { updateModelByValues } from '../update-associations';
import { UpdateGuard } from '../update-guard';
import { RelationRepository, transaction } from './relation-repository';
type FindAndCountOptions = CommonFindOptions;
export interface AssociatedOptions extends Transactionable {
tk?: TK;
}
import {
AssociatedOptions,
CountOptions,
DestroyOptions,
Filter,
FindOptions,
TargetKey,
UpdateOptions,
FirstOrCreateOptions,
} from './types';
import { valuesToFilter } from '../utils/filter-utils';
export abstract class MultipleRelationRepository extends RelationRepository {
async targetRepositoryFilterOptionsBySourceValue(): Promise<any> {
@ -73,7 +67,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
});
}
async findAndCount(options?: FindAndCountOptions): Promise<[any[], number]> {
async findAndCount(options?: FindOptions): Promise<[any[], number]> {
const transaction = await this.getTransaction(options, false);
return [
@ -121,7 +115,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
return parseInt(count.count);
}
async findOne(options?: FindOneOptions): Promise<any> {
async findOne(options?: FindOptions): Promise<any> {
const transaction = await this.getTransaction(options, false);
const rows = await this.find({ ...options, limit: 1, transaction });
return rows.length == 1 ? rows[0] : null;
@ -181,7 +175,7 @@ export abstract class MultipleRelationRepository extends RelationRepository {
return instances;
}
async destroy(options?: TK | DestroyOptions): Promise<boolean> {
async destroy(options?: TargetKey | DestroyOptions): Promise<boolean> {
return false;
}
@ -205,4 +199,10 @@ export abstract class MultipleRelationRepository extends RelationRepository {
protected accessors() {
return <MultiAssociationAccessors>super.accessors();
}
@transaction()
async updateOrCreate(options: FirstOrCreateOptions) {
const result = await super.updateOrCreate(options);
return Array.isArray(result) ? result[0] : result;
}
}

View File

@ -16,9 +16,10 @@ import { RelationField } from '../fields/relation-field';
import FilterParser from '../filter-parser';
import { Model } from '../model';
import { OptionsParser } from '../options-parser';
import { CreateOptions, Filter, FindOptions, TargetKey } from '../repository';
import { updateAssociations } from '../update-associations';
import { UpdateGuard } from '../update-guard';
import { CreateOptions, Filter, FindOptions, TargetKey, UpdateOptions, FirstOrCreateOptions } from './types';
import { valuesToFilter } from '../utils/filter-utils';
export const transaction = transactionWrapperBuilder(function () {
return this.sourceCollection.model.sequelize.transaction();
@ -76,6 +77,8 @@ export abstract class RelationRepository {
}
abstract find(options?: FindOptions): Promise<any>;
abstract findOne(options?: FindOptions): Promise<any>;
abstract update(options: UpdateOptions): Promise<any>;
async chunk(
options: FindOptions & { chunkSize: number; callback: (rows: Model[], options: FindOptions) => Promise<void> },
@ -138,6 +141,41 @@ export abstract class RelationRepository {
return this.associationField.targetKey;
}
@transaction()
async firstOrCreate(options: FirstOrCreateOptions) {
const { filterKeys, values, transaction, hooks } = options;
const filter = valuesToFilter(values, filterKeys);
const instance = await this.findOne({ filter, transaction });
if (instance) {
return instance;
}
return this.create({ values, transaction, hooks });
}
@transaction()
async updateOrCreate(options: FirstOrCreateOptions) {
const { filterKeys, values, transaction, hooks } = options;
const filter = valuesToFilter(values, filterKeys);
const instance = await this.findOne({ filter, transaction });
if (instance) {
return await this.update({
filterByTk: instance.get(
this.targetCollection.filterTargetKey || this.targetCollection.model.primaryKeyAttribute,
),
values,
transaction,
hooks,
});
}
return this.create({ values, transaction, hooks });
}
@transaction()
async create(options?: CreateOptions): Promise<any> {
if (Array.isArray(options.values)) {

View File

@ -7,22 +7,13 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import lodash from 'lodash';
import { SingleAssociationAccessors, Transactionable } from 'sequelize';
import injectTargetCollection from '../decorators/target-collection-decorator';
import { Model } from '../model';
import { Appends, Except, Fields, Filter, TargetKey, UpdateOptions } from '../repository';
import { FindOptions, TargetKey, UpdateOptions } from './types';
import { updateModelByValues } from '../update-associations';
import { RelationRepository, transaction } from './relation-repository';
export interface SingleRelationFindOption extends Transactionable {
fields?: Fields;
except?: Except;
appends?: Appends;
filter?: Filter;
targetCollection?: string;
}
interface SetOption extends Transactionable {
tk?: TargetKey;
}
@ -55,7 +46,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
});
}
async find(options?: SingleRelationFindOption): Promise<any> {
async find(options?: FindOptions): Promise<any> {
const targetRepository = this.targetCollection.repository;
const sourceModel = await this.getSourceModel(await this.getTransaction(options));
@ -74,7 +65,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
return await targetRepository.findOne(findOptions);
}
async findOne(options?: SingleRelationFindOption): Promise<Model<any>> {
async findOne(options?: FindOptions): Promise<Model<any>> {
return this.find({ ...options, filterByTk: null } as any);
}
@ -100,6 +91,7 @@ export abstract class SingleRelationRepository extends RelationRepository {
const target = await this.find({
transaction,
// @ts-ignore
targetCollection: options.targetCollection,
});

View File

@ -7,18 +7,96 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { TargetKey, Values } from '../repository';
import { Transactionable } from 'sequelize';
import { Transaction } from 'sequelize';
import {
CreateOptions as SequelizeCreateOptions,
UpdateOptions as SequelizeUpdateOptions,
} from 'sequelize/types/model';
import { AssociationKeysToBeUpdate, BlackList, Values, WhiteList } from '@nocobase/database';
export type PrimaryKeyWithThroughValues = [TargetKey, Values];
export type TargetKey = string | number | { [key: string]: any };
export interface AssociatedOptions extends Transactionable {
tk?: TargetKey | TargetKey[] | PrimaryKeyWithThroughValues | PrimaryKeyWithThroughValues[];
export interface Filter {
[key: string]: any;
}
export type setAssociationOptions =
| TargetKey
| TargetKey[]
| PrimaryKeyWithThroughValues
| PrimaryKeyWithThroughValues[]
| AssociatedOptions;
export interface Appends {
[key: string]: true | Appends;
}
export interface Except {
[key: string]: true | Except;
}
export interface CommonOptions {
transaction?: Transaction;
context?: any;
}
export interface FindOptions extends CommonOptions {
filter?: Filter;
filterByTk?: TargetKey;
fields?: string[];
appends?: string[];
except?: string[];
sort?: string[];
limit?: number;
offset?: number;
raw?: boolean;
targetCollection?: string;
}
export interface CountOptions extends CommonOptions {
filter?: Filter;
}
export interface CreateOptions extends SequelizeCreateOptions {
values?: Values | Values[];
whitelist?: WhiteList;
blacklist?: BlackList;
updateAssociationValues?: AssociationKeysToBeUpdate;
context?: any;
}
export interface UpdateOptions extends Omit<SequelizeUpdateOptions, 'where'> {
values: Values;
filter?: Filter;
filterByTk?: TargetKey;
whitelist?: WhiteList;
blacklist?: BlackList;
updateAssociationValues?: AssociationKeysToBeUpdate;
targetCollection?: string;
context?: any;
}
export interface DestroyOptions extends CommonOptions {
filter?: Filter;
filterByTk?: TargetKey;
truncate?: boolean;
context?: any;
}
export interface FirstOrCreateOptions extends CommonOptions {
filterKeys: string[];
values: any;
hooks?: boolean;
}
export interface ThroughValues {
[key: string]: any;
}
export interface AssociatedOptions extends CommonOptions {
tk?: TargetKey | TargetKey[];
transaction?: Transaction;
}
export interface PrimaryKeyWithThroughValues {
pk: any;
throughValues?: ThroughValues;
}
export interface ToggleOptions extends CommonOptions {
tk?: TargetKey;
transaction?: Transaction;
}

View File

@ -46,6 +46,7 @@ import { RelationRepository } from './relation-repository/relation-repository';
import { updateAssociations, updateModelByValues } from './update-associations';
import { UpdateGuard } from './update-guard';
import { BelongsToArrayRepository } from './relation-repository/belongs-to-array-repository';
import { valuesToFilter } from './utils/filter-utils';
const debug = require('debug')('noco-database');
@ -234,7 +235,7 @@ export interface AggregateOptions {
distinct?: boolean;
}
interface FirstOrCreateOptions extends Transactionable {
export interface FirstOrCreateOptions extends Transactionable {
filterKeys: string[];
values?: Values;
hooks?: boolean;
@ -251,53 +252,7 @@ export class Repository<TModelAttributes extends {} = any, TCreationAttributes e
this.model = collection.model;
}
public static valuesToFilter(values: Values = {}, filterKeys: Array<string>) {
const removeArrayIndexInKey = (key) => {
const chunks = key.split('.');
return chunks
.filter((chunk) => {
return !chunk.match(/\d+/);
})
.join('.');
};
const filterAnd = [];
const flattedValues = flatten(values);
const flattedValuesObject = {};
for (const key in flattedValues) {
const keyWithoutArrayIndex = removeArrayIndexInKey(key);
if (flattedValuesObject[keyWithoutArrayIndex]) {
if (!Array.isArray(flattedValuesObject[keyWithoutArrayIndex])) {
flattedValuesObject[keyWithoutArrayIndex] = [flattedValuesObject[keyWithoutArrayIndex]];
}
flattedValuesObject[keyWithoutArrayIndex].push(flattedValues[key]);
} else {
flattedValuesObject[keyWithoutArrayIndex] = [flattedValues[key]];
}
}
for (const filterKey of filterKeys) {
const filterValue = flattedValuesObject[filterKey]
? flattedValuesObject[filterKey]
: lodash.get(values, filterKey);
if (filterValue) {
filterAnd.push({
[filterKey]: filterValue,
});
} else {
filterAnd.push({
[filterKey]: null,
});
}
}
return {
$and: filterAnd,
};
}
public static valuesToFilter = valuesToFilter;
/**
* return count by filter

View File

@ -0,0 +1,59 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import lodash from 'lodash';
import { flatten } from 'flat';
type Values = Record<string, any>;
export function valuesToFilter(values: Values = {}, filterKeys: Array<string>) {
const removeArrayIndexInKey = (key) => {
const chunks = key.split('.');
return chunks
.filter((chunk) => {
return !chunk.match(/\d+/);
})
.join('.');
};
const filterAnd = [];
const flattedValues = flatten(values);
const flattedValuesObject = {};
for (const key in flattedValues) {
const keyWithoutArrayIndex = removeArrayIndexInKey(key);
if (flattedValuesObject[keyWithoutArrayIndex]) {
if (!Array.isArray(flattedValuesObject[keyWithoutArrayIndex])) {
flattedValuesObject[keyWithoutArrayIndex] = [flattedValuesObject[keyWithoutArrayIndex]];
}
flattedValuesObject[keyWithoutArrayIndex].push(flattedValues[key]);
} else {
flattedValuesObject[keyWithoutArrayIndex] = [flattedValues[key]];
}
}
for (const filterKey of filterKeys) {
const filterValue = flattedValuesObject[filterKey] ? flattedValuesObject[filterKey] : lodash.get(values, filterKey);
if (filterValue) {
filterAnd.push({
[filterKey]: filterValue,
});
} else {
filterAnd.push({
[filterKey]: null,
});
}
}
return {
$and: filterAnd,
};
}