export default class MiniORM {
constructor(data) {
this._store = {};
for (const [modelName, records] of Object.entries(data || {})) {
this._store[modelName] = records.map((record) => ({ ...record }));
this[modelName] = this._createDelegate(modelName);
}
}
_createDelegate(modelName) {
return {
findMany: (args = {}) => {
const table = this._store[modelName];
const where = args.where;
const orderBy = args.orderBy;
let results = table;
if (where) {
results = results.filter((record) => matchesWhereEnhanced(record, where));
}
if (orderBy) {
const [field, direction] = Object.entries(orderBy)[0];
const sortFactor = direction === 'asc' ? 1 : -1;
results = [...results].sort((a, b) => {
if (a[field] === b[field]) {
return 0;
}
return a[field] < b[field] ? -1 * sortFactor : 1 * sortFactor;
});
}
return results.map((record) => ({ ...record }));
},
create: ({ data }) => {
const table = this._store[modelName];
const created = { ...data };
table.push(created);
return { ...created };
},
update: ({ where, data }) => {
const table = this._store[modelName];
const index = table.findIndex((record) => matchesWhereExact(record, where));
const updated = { ...table[index], ...data };
table[index] = updated;
return { ...updated };
},
delete: ({ where }) => {
const table = this._store[modelName];
const index = table.findIndex((record) => matchesWhereExact(record, where));
const [deleted] = table.splice(index, 1);
return { ...deleted };
},
};
}
}
function matchesWhereExact(record, where) {
for (const [key, value] of Object.entries(where)) {
if (record[key] !== value) {
return false;
}
}
return true;
}
function matchesWhereEnhanced(record, where) {
for (const [field, condition] of Object.entries(where)) {
const fieldValue = record[field];
if (!isOperatorObject(condition)) {
if (fieldValue !== condition) {
return false;
}
continue;
}
if (Object.prototype.hasOwnProperty.call(condition, 'in')) {
if (!condition.in.includes(fieldValue)) {
return false;
}
}
if (Object.prototype.hasOwnProperty.call(condition, 'gt')) {
if (!(fieldValue > condition.gt)) {
return false;
}
}
if (Object.prototype.hasOwnProperty.call(condition, 'gte')) {
if (!(fieldValue >= condition.gte)) {
return false;
}
}
if (Object.prototype.hasOwnProperty.call(condition, 'lt')) {
if (!(fieldValue < condition.lt)) {
return false;
}
}
if (Object.prototype.hasOwnProperty.call(condition, 'lte')) {
if (!(fieldValue <= condition.lte)) {
return false;
}
}
if (Object.prototype.hasOwnProperty.call(condition, 'contains')) {
if (typeof fieldValue !== 'string' || !fieldValue.includes(condition.contains)) {
return false;
}
}
}
return true;
}
function isOperatorObject(value) {
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
return false;
}
const operatorKeys = new Set(['in', 'gt', 'gte', 'lt', 'lte', 'contains']);
const keys = Object.keys(value);
if (keys.length === 0) {
return false;
}
return keys.some((key) => operatorKeys.has(key));
}