@funztic/db
Version:
TypeScript기반 파일 데이터베이스, zod를 지원합니다.
136 lines (135 loc) • 4.52 kB
JavaScript
export function* autoIncrement() {
let i = 0;
while (true)
yield i++;
}
export class Repository {
constructor(collection, options) {
this.collection = collection;
this.options = options;
}
async save(entity) {
let processedEntity = { ...entity };
if (this.options.beforeCreate)
processedEntity = await this.options.beforeCreate(processedEntity);
if (!processedEntity.id)
processedEntity.id = this.options.idGenerator();
const existingEntity = await this.collection.get(processedEntity.id);
let finalEntity = existingEntity
? { ...existingEntity, ...processedEntity }
: processedEntity;
if (this.options.beforeSave)
finalEntity = await this.options.beforeSave(finalEntity);
const savedEntity = existingEntity
? await this.collection.update(finalEntity.id, finalEntity)
: await this.collection.create(finalEntity);
if (this.options.afterSave)
await this.options.afterSave(savedEntity);
return savedEntity;
}
async findById(id) {
const entity = await this.collection.get(id);
return entity || null;
}
async findAll() {
return await this.collection.getAll();
}
async findBy(criteria) {
const entries = Object.entries(criteria);
return await this.collection.find((entity) => {
return entries.every(([key, value]) => entity[key] === value);
});
}
async findOne(criteria) {
const results = await this.findBy(criteria);
return results.length > 0 ? results[0] : null;
}
async update(id, data) {
const entity = await this.collection.get(id);
if (!entity)
return null;
let updates = { ...data };
if (this.options.beforeUpdate)
updates = await this.options.beforeUpdate(entity, updates);
const updatedEntity = await this.collection.update(id, updates);
if (updatedEntity && this.options.afterSave)
await this.options.afterSave(updatedEntity);
return updatedEntity || null;
}
async delete(id) {
return await this.collection.delete(id);
}
async count() {
const all = await this.collection.getAll();
return all.length;
}
async exists(id) {
const entity = await this.collection.get(id);
return !!entity;
}
async clear() {
await this.collection.clear();
}
async query(queryFn) {
const entities = await this.collection.getAll();
return queryFn(entities);
}
async paginate(page = 1, limit = 10) {
const allItems = await this.collection.getAll();
const total = allItems.length;
const start = (page - 1) * limit;
const end = start + limit;
const data = allItems.slice(start, end);
const totalPages = Math.ceil(total / limit);
return {
data,
total,
page,
limit,
totalPages
};
}
async *createPaginator(limit = 10, sortBy, order = 'asc') {
const data = await this.findAllSorted(sortBy, order);
const total = data.length;
const totalPages = Math.ceil(total / limit);
let currentPage = 1;
while (currentPage <= totalPages) {
const start = (currentPage - 1) * limit;
const end = start + limit;
yield {
data: data.slice(start, end),
total,
page: currentPage,
isLast: currentPage === totalPages
};
currentPage++;
}
}
async findAllSorted(sortBy, order = 'asc') {
const entities = await this.collection.getAll();
return entities.sort((a, b) => {
const valueA = a[sortBy];
const valueB = b[sortBy];
if (valueA === valueB)
return 0;
if (order === 'asc') {
return valueA < valueB ? -1 : 1;
}
else {
return valueA > valueB ? -1 : 1;
}
});
}
getRawCollection() {
return this.collection;
}
}
export function createRepository(collection, options = (() => {
const idGenerator = autoIncrement();
return {
idGenerator: () => idGenerator.next().value.toString()
};
})()) {
return new Repository(collection, options);
}