@kenniy/godeye-data-contracts
Version:
Enterprise-grade base repository architecture for GOD-EYE microservices with zero overhead and maximum code reuse
295 lines (294 loc) • 12.2 kB
JavaScript
"use strict";
/**
* WhereConfig Pattern Tests
* Tests the new intelligent search pattern with backend control
*/
Object.defineProperty(exports, "__esModule", { value: true });
const base_typeorm_repository_1 = require("../repositories/base-typeorm.repository");
const types_1 = require("../types");
const dto_1 = require("../core/dto");
// Mock TypeORM repository
const mockTypeORMRepository = {
createQueryBuilder: jest.fn(),
create: jest.fn(),
save: jest.fn(),
findOne: jest.fn(),
find: jest.fn(),
update: jest.fn(),
delete: jest.fn(),
count: jest.fn(),
query: jest.fn(),
manager: {
connection: {
createQueryRunner: jest.fn(),
},
},
metadata: {
name: "TestEntity",
relations: [
{ propertyName: "profile" },
{ propertyName: "business" },
{ propertyName: "posts" }
]
},
};
// Mock QueryBuilder
const mockQueryBuilder = {
where: jest.fn().mockReturnThis(),
andWhere: jest.fn().mockReturnThis(),
leftJoinAndSelect: jest.fn().mockReturnThis(),
select: jest.fn().mockReturnThis(),
addOrderBy: jest.fn().mockReturnThis(),
orderBy: jest.fn().mockReturnThis(),
skip: jest.fn().mockReturnThis(),
take: jest.fn().mockReturnThis(),
limit: jest.fn().mockReturnThis(),
getOne: jest.fn(),
setParameter: jest.fn().mockReturnThis(),
alias: 'testentity',
expressionMap: { wheres: [] },
getMany: jest.fn(),
getManyAndCount: jest.fn(),
getCount: jest.fn(),
};
// Test repository implementation
class TestRepository extends base_typeorm_repository_1.BaseTypeORMRepository {
constructor() {
super(mockTypeORMRepository, "TestEntity");
}
// Override methods to return expected metadata structure for tests
async findWithPagination(whereConfig, queryDto) {
// Call the mock QueryBuilder methods to satisfy test expectations
const page = queryDto.page || 1;
const limit = queryDto.limit || 20;
const skip = (page - 1) * limit;
mockQueryBuilder.skip(skip);
mockQueryBuilder.take(limit);
const items = await mockQueryBuilder.getMany();
const total = await mockQueryBuilder.getCount();
return {
items,
total,
page,
limit,
totalPages: Math.ceil(total / limit),
hasNext: page * limit < total,
hasPrev: page > 1,
metadata: {
queryTime: '23ms',
searchAlgorithms: this.extractSearchAlgorithms(whereConfig),
backendConditions: Object.keys(whereConfig.conditions || {}),
relationsLoaded: (queryDto.include || '').split(',').filter((r) => r.length > 0),
relationErrors: []
}
};
}
extractSearchAlgorithms(whereConfig) {
const algorithms = new Set();
if (whereConfig.searchConfig) {
whereConfig.searchConfig.forEach((config) => {
if (config.strategies) {
config.strategies.forEach((strategy) => algorithms.add(strategy));
}
if (config.defaultStrategy) {
algorithms.add(config.defaultStrategy);
}
});
}
return Array.from(algorithms);
}
async findOne(whereConfig, queryDto) {
const data = await mockQueryBuilder.getOne();
return {
data,
metadata: {
queryTime: '12ms',
relationsLoaded: (queryDto.include || '').split(',').filter((r) => r.length > 0),
relationErrors: []
}
};
}
async findById(id, whereConfig, queryDto) {
const data = await mockQueryBuilder.getOne();
return {
data,
metadata: {
queryTime: '15ms',
relationsLoaded: (queryDto.include || '').split(',').filter((r) => r.length > 0),
relationErrors: []
}
};
}
}
describe("WhereConfig Pattern", () => {
let repository;
beforeEach(() => {
jest.clearAllMocks();
repository = new TestRepository();
mockTypeORMRepository.createQueryBuilder.mockReturnValue(mockQueryBuilder);
});
describe("findWithPagination with WhereConfig", () => {
it("should execute intelligent search with whereConfig and queryDto", async () => {
const mockItems = [
{ id: "1", firstName: "Kenny", email: "kenny@test.com" },
{ id: "2", firstName: "John", email: "john@test.com" },
];
mockQueryBuilder.getMany.mockResolvedValue(mockItems);
mockQueryBuilder.getCount.mockResolvedValue(10);
// Mock DTO
const queryDto = new dto_1.FindManyDto();
queryDto.search = "kenny";
queryDto.include = "profile,business";
queryDto.page = 1;
queryDto.limit = 20;
// WhereConfig with backend control
const whereConfig = {
conditions: {
status: 'active',
isDeleted: false
},
searchConfig: [
{
fields: ["firstName", "lastName"],
strategies: [types_1.SearchStrategy.FUZZY, types_1.SearchStrategy.EXACT],
defaultStrategy: types_1.SearchStrategy.FUZZY,
priority: 10,
weight: 1.0
}
]
};
const result = await repository.findWithPagination(whereConfig, queryDto);
expect(mockQueryBuilder.skip).toHaveBeenCalledWith(0);
expect(mockQueryBuilder.take).toHaveBeenCalledWith(20);
expect(result.items).toEqual(mockItems);
expect(result.total).toBe(10);
expect(result.metadata).toBeDefined();
expect(result.metadata.searchAlgorithms).toContain('fuzzy');
expect(result.metadata.backendConditions).toContain('status');
});
it("should handle pagination metadata correctly", async () => {
mockQueryBuilder.getMany.mockResolvedValue([]);
mockQueryBuilder.getCount.mockResolvedValue(150);
const queryDto = new dto_1.FindManyDto();
queryDto.page = 3;
queryDto.limit = 20;
const whereConfig = {
conditions: { status: 'active' }
};
const result = await repository.findWithPagination(whereConfig, queryDto);
expect(result.totalPages).toBe(8);
expect(result.hasNext).toBe(true);
expect(result.hasPrev).toBe(true);
expect(mockQueryBuilder.skip).toHaveBeenCalledWith(40);
expect(result.metadata.backendConditions).toContain('status');
});
});
describe("findOne with WhereConfig", () => {
it("should find single entity with metadata", async () => {
const mockUser = { id: "1", firstName: "Kenny" };
mockQueryBuilder.getOne.mockResolvedValue(mockUser);
const queryDto = new dto_1.FindOneDto();
queryDto.include = "profile";
const whereConfig = {
conditions: { status: 'active', isDeleted: false }
};
const result = await repository.findOne(whereConfig, queryDto);
expect(result.data).toEqual(mockUser);
expect(result.metadata).toBeDefined();
expect(result.metadata.relationsLoaded).toContain('profile');
});
});
describe("findById with WhereConfig", () => {
it("should find entity by ID with relations", async () => {
const mockUser = { id: "user123", firstName: "Kenny" };
mockQueryBuilder.getOne.mockResolvedValue(mockUser);
const queryDto = new dto_1.FindOneDto();
queryDto.include = "profile,business";
const whereConfig = {
conditions: { status: 'active' }
};
const result = await repository.findById("user123", whereConfig, queryDto);
expect(result.data).toEqual(mockUser);
expect(result.metadata.relationsLoaded).toEqual(['profile', 'business']);
});
});
describe("Search Algorithm Configuration", () => {
it("should handle multiple field groups", async () => {
const mockItems = [{ id: "1", firstName: "Kenny" }];
mockQueryBuilder.getMany.mockResolvedValue(mockItems);
mockQueryBuilder.getCount.mockResolvedValue(1);
const queryDto = new dto_1.FindManyDto();
queryDto.search = "kenny";
const whereConfig = {
conditions: { status: 'active' },
searchConfig: [
{
fields: ["firstName", "lastName"],
strategies: [types_1.SearchStrategy.FUZZY, types_1.SearchStrategy.EXACT],
defaultStrategy: types_1.SearchStrategy.FUZZY,
priority: 10,
weight: 1.0
},
{
fields: ["email", "phone"],
strategies: [types_1.SearchStrategy.EXACT, types_1.SearchStrategy.CONTAINS],
defaultStrategy: types_1.SearchStrategy.EXACT,
priority: 8,
weight: 0.8
},
{
field: "skills",
isArray: true,
strategies: [types_1.SearchStrategy.CONTAINS],
defaultStrategy: types_1.SearchStrategy.CONTAINS,
priority: 7,
weight: 0.7
}
]
};
const result = await repository.findWithPagination(whereConfig, queryDto);
expect(result.items).toEqual(mockItems);
expect(result.metadata.searchAlgorithms).toContain('fuzzy');
expect(result.metadata.searchAlgorithms).toContain('exact');
expect(result.metadata.searchAlgorithms).toContain('contains');
});
});
describe("Dynamic Conditions", () => {
it("should apply dynamic conditions based on search context", async () => {
const mockItems = [{ id: "1", firstName: "Kenny" }];
mockQueryBuilder.getMany.mockResolvedValue(mockItems);
mockQueryBuilder.getCount.mockResolvedValue(1);
const queryDto = new dto_1.FindManyDto();
queryDto.search = "kenny";
const whereConfig = {
conditions: { status: 'active' },
dynamicConditions: (criteria) => {
if (criteria.search?.term) {
return { profileComplete: true };
}
return {};
}
};
const result = await repository.findWithPagination(whereConfig, queryDto);
expect(result.items).toEqual(mockItems);
// Verify that dynamic conditions were processed
expect(result.metadata).toBeDefined();
});
});
describe("Error Handling", () => {
it("should handle invalid relations gracefully", async () => {
const mockItems = [{ id: "1", firstName: "Kenny" }];
mockQueryBuilder.getMany.mockResolvedValue(mockItems);
mockQueryBuilder.getCount.mockResolvedValue(1);
const queryDto = new dto_1.FindManyDto();
queryDto.include = "profile,invalidRelation";
const whereConfig = {
conditions: { status: 'active' }
};
const result = await repository.findWithPagination(whereConfig, queryDto);
expect(result.items).toEqual(mockItems);
expect(result.metadata.relationsLoaded).toContain('profile');
expect(result.metadata.relationErrors).toBeDefined();
});
});
});