added doga
This commit is contained in:
8
25_02_24/node_modules/json-server/lib/app.d.ts
generated
vendored
Normal file
8
25_02_24/node_modules/json-server/lib/app.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { App } from '@tinyhttp/app';
|
||||
import { Low } from 'lowdb';
|
||||
import { Data } from './service.js';
|
||||
export type AppOptions = {
|
||||
logger?: boolean;
|
||||
static?: string[];
|
||||
};
|
||||
export declare function createApp(db: Low<Data>, options?: AppOptions): App<import("@tinyhttp/app").Request, import("@tinyhttp/app").Response<unknown>>;
|
||||
112
25_02_24/node_modules/json-server/lib/app.js
generated
vendored
Normal file
112
25_02_24/node_modules/json-server/lib/app.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
import { dirname, isAbsolute, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { App } from '@tinyhttp/app';
|
||||
import { cors } from '@tinyhttp/cors';
|
||||
import { Eta } from 'eta';
|
||||
import { json } from 'milliparsec';
|
||||
import sirv from 'sirv';
|
||||
import { isItem, Service } from './service.js';
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const isProduction = process.env['NODE_ENV'] === 'production';
|
||||
const eta = new Eta({
|
||||
views: join(__dirname, '../views'),
|
||||
cache: isProduction,
|
||||
});
|
||||
export function createApp(db, options = {}) {
|
||||
// Create service
|
||||
const service = new Service(db);
|
||||
// Create app
|
||||
const app = new App();
|
||||
// Static files
|
||||
app.use(sirv('public', { dev: !isProduction }));
|
||||
options.static
|
||||
?.map((path) => (isAbsolute(path) ? path : join(process.cwd(), path)))
|
||||
.forEach((dir) => app.use(sirv(dir, { dev: !isProduction })));
|
||||
// CORS
|
||||
app
|
||||
.use((req, res, next) => {
|
||||
return cors({
|
||||
allowedHeaders: req.headers['access-control-request-headers']
|
||||
?.split(',')
|
||||
.map((h) => h.trim()),
|
||||
})(req, res, next);
|
||||
})
|
||||
.options('*', cors());
|
||||
// Body parser
|
||||
// @ts-expect-error expected
|
||||
app.use(json());
|
||||
app.get('/', (_req, res) => res.send(eta.render('index.html', { data: db.data })));
|
||||
app.get('/:name', (req, res, next) => {
|
||||
const { name = '' } = req.params;
|
||||
const query = Object.fromEntries(Object.entries(req.query)
|
||||
.map(([key, value]) => {
|
||||
if (['_start', '_end', '_limit', '_page', '_per_page'].includes(key) &&
|
||||
typeof value === 'string') {
|
||||
return [key, parseInt(value)];
|
||||
}
|
||||
else {
|
||||
return [key, value];
|
||||
}
|
||||
})
|
||||
.filter(([, value]) => !Number.isNaN(value)));
|
||||
res.locals['data'] = service.find(name, query);
|
||||
next?.();
|
||||
});
|
||||
app.get('/:name/:id', (req, res, next) => {
|
||||
const { name = '', id = '' } = req.params;
|
||||
res.locals['data'] = service.findById(name, id, req.query);
|
||||
next?.();
|
||||
});
|
||||
app.post('/:name', async (req, res, next) => {
|
||||
const { name = '' } = req.params;
|
||||
if (isItem(req.body)) {
|
||||
res.locals['data'] = await service.create(name, req.body);
|
||||
}
|
||||
next?.();
|
||||
});
|
||||
app.put('/:name', async (req, res, next) => {
|
||||
const { name = '' } = req.params;
|
||||
if (isItem(req.body)) {
|
||||
res.locals['data'] = await service.update(name, req.body);
|
||||
}
|
||||
next?.();
|
||||
});
|
||||
app.put('/:name/:id', async (req, res, next) => {
|
||||
const { name = '', id = '' } = req.params;
|
||||
if (isItem(req.body)) {
|
||||
res.locals['data'] = await service.updateById(name, id, req.body);
|
||||
}
|
||||
next?.();
|
||||
});
|
||||
app.patch('/:name', async (req, res, next) => {
|
||||
const { name = '' } = req.params;
|
||||
if (isItem(req.body)) {
|
||||
res.locals['data'] = await service.patch(name, req.body);
|
||||
}
|
||||
next?.();
|
||||
});
|
||||
app.patch('/:name/:id', async (req, res, next) => {
|
||||
const { name = '', id = '' } = req.params;
|
||||
if (isItem(req.body)) {
|
||||
res.locals['data'] = await service.patchById(name, id, req.body);
|
||||
}
|
||||
next?.();
|
||||
});
|
||||
app.delete('/:name/:id', async (req, res, next) => {
|
||||
const { name = '', id = '' } = req.params;
|
||||
res.locals['data'] = await service.destroyById(name, id, req.query['_dependent']);
|
||||
next?.();
|
||||
});
|
||||
app.use('/:name', (req, res) => {
|
||||
const { data } = res.locals;
|
||||
if (data === undefined) {
|
||||
res.sendStatus(404);
|
||||
}
|
||||
else {
|
||||
if (req.method === 'POST')
|
||||
res.status(201);
|
||||
res.json(data);
|
||||
}
|
||||
});
|
||||
return app;
|
||||
}
|
||||
2
25_02_24/node_modules/json-server/lib/bin.d.ts
generated
vendored
Normal file
2
25_02_24/node_modules/json-server/lib/bin.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
export {};
|
||||
183
25_02_24/node_modules/json-server/lib/bin.js
generated
vendored
Normal file
183
25_02_24/node_modules/json-server/lib/bin.js
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
#!/usr/bin/env node
|
||||
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { extname } from 'node:path';
|
||||
import { parseArgs } from 'node:util';
|
||||
import chalk from 'chalk';
|
||||
import { watch } from 'chokidar';
|
||||
import JSON5 from 'json5';
|
||||
import { Low } from 'lowdb';
|
||||
import { DataFile, JSONFile } from 'lowdb/node';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { createApp } from './app.js';
|
||||
import { Observer } from './observer.js';
|
||||
function help() {
|
||||
console.log(`Usage: json-server [options] <file>
|
||||
|
||||
Options:
|
||||
-p, --port <port> Port (default: 3000)
|
||||
-h, --host <host> Host (default: localhost)
|
||||
-s, --static <dir> Static files directory (multiple allowed)
|
||||
--help Show this message
|
||||
--version Show version number
|
||||
`);
|
||||
}
|
||||
// Parse args
|
||||
function args() {
|
||||
try {
|
||||
const { values, positionals } = parseArgs({
|
||||
options: {
|
||||
port: {
|
||||
type: 'string',
|
||||
short: 'p',
|
||||
default: process.env['PORT'] ?? '3000',
|
||||
},
|
||||
host: {
|
||||
type: 'string',
|
||||
short: 'h',
|
||||
default: process.env['HOST'] ?? 'localhost',
|
||||
},
|
||||
static: {
|
||||
type: 'string',
|
||||
short: 's',
|
||||
multiple: true,
|
||||
default: [],
|
||||
},
|
||||
help: {
|
||||
type: 'boolean',
|
||||
},
|
||||
version: {
|
||||
type: 'boolean',
|
||||
},
|
||||
// Deprecated
|
||||
watch: {
|
||||
type: 'boolean',
|
||||
short: 'w',
|
||||
},
|
||||
},
|
||||
allowPositionals: true,
|
||||
});
|
||||
// --version
|
||||
if (values.version) {
|
||||
const pkg = JSON.parse(readFileSync(fileURLToPath(new URL('../package.json', import.meta.url)), 'utf-8'));
|
||||
console.log(pkg.version);
|
||||
process.exit();
|
||||
}
|
||||
// Handle --watch
|
||||
if (values.watch) {
|
||||
console.log(chalk.yellow('--watch/-w can be omitted, JSON Server 1+ watches for file changes by default'));
|
||||
}
|
||||
if (values.help || positionals.length === 0) {
|
||||
help();
|
||||
process.exit();
|
||||
}
|
||||
// App args and options
|
||||
return {
|
||||
file: positionals[0] ?? '',
|
||||
port: parseInt(values.port),
|
||||
host: values.host,
|
||||
static: values.static,
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
if (e.code === 'ERR_PARSE_ARGS_UNKNOWN_OPTION') {
|
||||
console.log(chalk.red(e.message.split('.')[0]));
|
||||
help();
|
||||
process.exit(1);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
const { file, port, host, static: staticArr } = args();
|
||||
if (!existsSync(file)) {
|
||||
console.log(chalk.red(`File ${file} not found`));
|
||||
process.exit(1);
|
||||
}
|
||||
// Handle empty string JSON file
|
||||
if (readFileSync(file, 'utf-8').trim() === '') {
|
||||
writeFileSync(file, '{}');
|
||||
}
|
||||
// Set up database
|
||||
let adapter;
|
||||
if (extname(file) === '.json5') {
|
||||
adapter = new DataFile(file, {
|
||||
parse: JSON5.parse,
|
||||
stringify: JSON5.stringify,
|
||||
});
|
||||
}
|
||||
else {
|
||||
adapter = new JSONFile(file);
|
||||
}
|
||||
const observer = new Observer(adapter);
|
||||
const db = new Low(observer, {});
|
||||
await db.read();
|
||||
// Create app
|
||||
const app = createApp(db, { logger: false, static: staticArr });
|
||||
function logRoutes(data) {
|
||||
console.log(chalk.bold('Endpoints:'));
|
||||
if (Object.keys(data).length === 0) {
|
||||
console.log(chalk.gray(`No endpoints found, try adding some data to ${file}`));
|
||||
return;
|
||||
}
|
||||
console.log(Object.keys(data)
|
||||
.map((key) => `${chalk.gray(`http://${host}:${port}/`)}${chalk.blue(key)}`)
|
||||
.join('\n'));
|
||||
}
|
||||
const kaomojis = ['♡⸜(˶˃ ᵕ ˂˶)⸝♡', '♡( ◡‿◡ )', '( ˶ˆ ᗜ ˆ˵ )', '(˶ᵔ ᵕ ᵔ˶)'];
|
||||
function randomItem(items) {
|
||||
const index = Math.floor(Math.random() * items.length);
|
||||
return items.at(index) ?? '';
|
||||
}
|
||||
app.listen(port, () => {
|
||||
console.log([
|
||||
chalk.bold(`JSON Server started on PORT :${port}`),
|
||||
chalk.gray('Press CTRL-C to stop'),
|
||||
chalk.gray(`Watching ${file}...`),
|
||||
'',
|
||||
chalk.magenta(randomItem(kaomojis)),
|
||||
'',
|
||||
chalk.bold('Index:'),
|
||||
chalk.gray(`http://localhost:${port}/`),
|
||||
'',
|
||||
chalk.bold('Static files:'),
|
||||
chalk.gray('Serving ./public directory if it exists'),
|
||||
'',
|
||||
].join('\n'));
|
||||
logRoutes(db.data);
|
||||
});
|
||||
// Watch file for changes
|
||||
if (process.env['NODE_ENV'] !== 'production') {
|
||||
let writing = false; // true if the file is being written to by the app
|
||||
let prevEndpoints = '';
|
||||
observer.onWriteStart = () => {
|
||||
writing = true;
|
||||
};
|
||||
observer.onWriteEnd = () => {
|
||||
writing = false;
|
||||
};
|
||||
observer.onReadStart = () => {
|
||||
prevEndpoints = JSON.stringify(Object.keys(db.data).sort());
|
||||
};
|
||||
observer.onReadEnd = (data) => {
|
||||
if (data === null) {
|
||||
return;
|
||||
}
|
||||
const nextEndpoints = JSON.stringify(Object.keys(data).sort());
|
||||
if (prevEndpoints !== nextEndpoints) {
|
||||
console.log();
|
||||
logRoutes(data);
|
||||
}
|
||||
};
|
||||
watch(file).on('change', () => {
|
||||
// Do no reload if the file is being written to by the app
|
||||
if (!writing) {
|
||||
db.read().catch((e) => {
|
||||
if (e instanceof SyntaxError) {
|
||||
return console.log(chalk.red(['', `Error parsing ${file}`, e.message].join('\n')));
|
||||
}
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
11
25_02_24/node_modules/json-server/lib/observer.d.ts
generated
vendored
Normal file
11
25_02_24/node_modules/json-server/lib/observer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import { Adapter } from 'lowdb';
|
||||
export declare class Observer<T> {
|
||||
#private;
|
||||
onReadStart: () => void;
|
||||
onReadEnd: (data: T | null) => void;
|
||||
onWriteStart: () => void;
|
||||
onWriteEnd: () => void;
|
||||
constructor(adapter: Adapter<T>);
|
||||
read(): Promise<T | null>;
|
||||
write(arg: T): Promise<void>;
|
||||
}
|
||||
30
25_02_24/node_modules/json-server/lib/observer.js
generated
vendored
Normal file
30
25_02_24/node_modules/json-server/lib/observer.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
// Lowdb adapter to observe read/write events
|
||||
export class Observer {
|
||||
#adapter;
|
||||
onReadStart = function () {
|
||||
return;
|
||||
};
|
||||
onReadEnd = function () {
|
||||
return;
|
||||
};
|
||||
onWriteStart = function () {
|
||||
return;
|
||||
};
|
||||
onWriteEnd = function () {
|
||||
return;
|
||||
};
|
||||
constructor(adapter) {
|
||||
this.#adapter = adapter;
|
||||
}
|
||||
async read() {
|
||||
this.onReadStart();
|
||||
const data = await this.#adapter.read();
|
||||
this.onReadEnd(data);
|
||||
return data;
|
||||
}
|
||||
async write(arg) {
|
||||
this.onWriteStart();
|
||||
await this.#adapter.write(arg);
|
||||
this.onWriteEnd();
|
||||
}
|
||||
}
|
||||
38
25_02_24/node_modules/json-server/lib/service.d.ts
generated
vendored
Normal file
38
25_02_24/node_modules/json-server/lib/service.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Low } from 'lowdb';
|
||||
export type Item = Record<string, unknown>;
|
||||
export type Data = Record<string, Item[] | Item>;
|
||||
export declare function isItem(obj: unknown): obj is Item;
|
||||
export declare function isData(obj: unknown): obj is Record<string, Item[]>;
|
||||
export type PaginatedItems = {
|
||||
first: number;
|
||||
prev: number | null;
|
||||
next: number | null;
|
||||
last: number;
|
||||
pages: number;
|
||||
items: number;
|
||||
data: Item[];
|
||||
};
|
||||
export declare class Service {
|
||||
#private;
|
||||
constructor(db: Low<Data>);
|
||||
has(name: string): boolean;
|
||||
findById(name: string, id: string, query: {
|
||||
_embed?: string[] | string;
|
||||
}): Item | undefined;
|
||||
find(name: string, query?: {
|
||||
[key: string]: unknown;
|
||||
_embed?: string | string[];
|
||||
_sort?: string;
|
||||
_start?: number;
|
||||
_end?: number;
|
||||
_limit?: number;
|
||||
_page?: number;
|
||||
_per_page?: number;
|
||||
}): Item[] | PaginatedItems | Item | undefined;
|
||||
create(name: string, data?: Omit<Item, 'id'>): Promise<Item | undefined>;
|
||||
update(name: string, body?: Item): Promise<Item | undefined>;
|
||||
patch(name: string, body?: Item): Promise<Item | undefined>;
|
||||
updateById(name: string, id: string, body?: Item): Promise<Item | undefined>;
|
||||
patchById(name: string, id: string, body?: Item): Promise<Item | undefined>;
|
||||
destroyById(name: string, id: string, dependent?: string | string[]): Promise<Item | undefined>;
|
||||
}
|
||||
333
25_02_24/node_modules/json-server/lib/service.js
generated
vendored
Normal file
333
25_02_24/node_modules/json-server/lib/service.js
generated
vendored
Normal file
@@ -0,0 +1,333 @@
|
||||
import { randomBytes } from 'node:crypto';
|
||||
import { getProperty } from 'dot-prop';
|
||||
import inflection from 'inflection';
|
||||
import sortOn from 'sort-on';
|
||||
export function isItem(obj) {
|
||||
return typeof obj === 'object' && obj !== null;
|
||||
}
|
||||
export function isData(obj) {
|
||||
if (typeof obj !== 'object' || obj === null) {
|
||||
return false;
|
||||
}
|
||||
const data = obj;
|
||||
return Object.values(data).every((value) => Array.isArray(value) && value.every(isItem));
|
||||
}
|
||||
var Condition;
|
||||
(function (Condition) {
|
||||
Condition["lt"] = "lt";
|
||||
Condition["lte"] = "lte";
|
||||
Condition["gt"] = "gt";
|
||||
Condition["gte"] = "gte";
|
||||
Condition["ne"] = "ne";
|
||||
Condition["default"] = "";
|
||||
})(Condition || (Condition = {}));
|
||||
function isCondition(value) {
|
||||
return Object.values(Condition).includes(value);
|
||||
}
|
||||
function ensureArray(arg = []) {
|
||||
return Array.isArray(arg) ? arg : [arg];
|
||||
}
|
||||
function embed(db, name, item, related) {
|
||||
if (inflection.singularize(related) === related) {
|
||||
const relatedData = db.data[inflection.pluralize(related)];
|
||||
if (!relatedData) {
|
||||
return item;
|
||||
}
|
||||
const foreignKey = `${related}Id`;
|
||||
const relatedItem = relatedData.find((relatedItem) => {
|
||||
return relatedItem['id'] === item[foreignKey];
|
||||
});
|
||||
return { ...item, [related]: relatedItem };
|
||||
}
|
||||
const relatedData = db.data[related];
|
||||
if (!relatedData) {
|
||||
return item;
|
||||
}
|
||||
const foreignKey = `${inflection.singularize(name)}Id`;
|
||||
const relatedItems = relatedData.filter((relatedItem) => relatedItem[foreignKey] === item['id']);
|
||||
return { ...item, [related]: relatedItems };
|
||||
}
|
||||
function nullifyForeignKey(db, name, id) {
|
||||
const foreignKey = `${inflection.singularize(name)}Id`;
|
||||
Object.entries(db.data).forEach(([key, items]) => {
|
||||
// Skip
|
||||
if (key === name)
|
||||
return;
|
||||
// Nullify
|
||||
if (Array.isArray(items)) {
|
||||
items.forEach((item) => {
|
||||
if (item[foreignKey] === id) {
|
||||
item[foreignKey] = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function deleteDependents(db, name, dependents) {
|
||||
const foreignKey = `${inflection.singularize(name)}Id`;
|
||||
Object.entries(db.data).forEach(([key, items]) => {
|
||||
// Skip
|
||||
if (key === name || !dependents.includes(key))
|
||||
return;
|
||||
// Delete if foreign key is null
|
||||
if (Array.isArray(items)) {
|
||||
db.data[key] = items.filter((item) => item[foreignKey] !== null);
|
||||
}
|
||||
});
|
||||
}
|
||||
function randomId() {
|
||||
return randomBytes(2).toString('hex');
|
||||
}
|
||||
function fixItemsIds(items) {
|
||||
items.forEach((item) => {
|
||||
if (typeof item['id'] === 'number') {
|
||||
item['id'] = item['id'].toString();
|
||||
}
|
||||
if (item['id'] === undefined) {
|
||||
item['id'] = randomId();
|
||||
}
|
||||
});
|
||||
}
|
||||
// Ensure all items have an id
|
||||
function fixAllItemsIds(data) {
|
||||
Object.values(data).forEach((value) => {
|
||||
if (Array.isArray(value)) {
|
||||
fixItemsIds(value);
|
||||
}
|
||||
});
|
||||
}
|
||||
export class Service {
|
||||
#db;
|
||||
constructor(db) {
|
||||
fixAllItemsIds(db.data);
|
||||
this.#db = db;
|
||||
}
|
||||
#get(name) {
|
||||
return this.#db.data[name];
|
||||
}
|
||||
has(name) {
|
||||
return Object.prototype.hasOwnProperty.call(this.#db?.data, name);
|
||||
}
|
||||
findById(name, id, query) {
|
||||
const value = this.#get(name);
|
||||
if (Array.isArray(value)) {
|
||||
let item = value.find((item) => item['id'] === id);
|
||||
ensureArray(query._embed).forEach((related) => {
|
||||
if (item !== undefined)
|
||||
item = embed(this.#db, name, item, related);
|
||||
});
|
||||
return item;
|
||||
}
|
||||
return;
|
||||
}
|
||||
find(name, query = {}) {
|
||||
let items = this.#get(name);
|
||||
if (!Array.isArray(items)) {
|
||||
return items;
|
||||
}
|
||||
// Include
|
||||
ensureArray(query._embed).forEach((related) => {
|
||||
if (items !== undefined && Array.isArray(items)) {
|
||||
items = items.map((item) => embed(this.#db, name, item, related));
|
||||
}
|
||||
});
|
||||
// Return list if no query params
|
||||
if (Object.keys(query).length === 0) {
|
||||
return items;
|
||||
}
|
||||
// Convert query params to conditions
|
||||
const conds = [];
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value === undefined || typeof value !== 'string') {
|
||||
continue;
|
||||
}
|
||||
const re = /_(lt|lte|gt|gte|ne)$/;
|
||||
const reArr = re.exec(key);
|
||||
const op = reArr?.at(1);
|
||||
if (op && isCondition(op)) {
|
||||
const field = key.replace(re, '');
|
||||
conds.push([field, op, value]);
|
||||
continue;
|
||||
}
|
||||
if ([
|
||||
'_embed',
|
||||
'_sort',
|
||||
'_start',
|
||||
'_end',
|
||||
'_limit',
|
||||
'_page',
|
||||
'_per_page',
|
||||
].includes(key)) {
|
||||
continue;
|
||||
}
|
||||
conds.push([key, Condition.default, value]);
|
||||
}
|
||||
// Loop through conditions and filter items
|
||||
let filtered = items;
|
||||
for (const [key, op, paramValue] of conds) {
|
||||
filtered = filtered.filter((item) => {
|
||||
if (paramValue && !Array.isArray(paramValue)) {
|
||||
// https://github.com/sindresorhus/dot-prop/issues/95
|
||||
const itemValue = getProperty(item, key);
|
||||
switch (op) {
|
||||
// item_gt=value
|
||||
case Condition.gt: {
|
||||
if (!(typeof itemValue === 'number' &&
|
||||
itemValue > parseInt(paramValue))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// item_gte=value
|
||||
case Condition.gte: {
|
||||
if (!(typeof itemValue === 'number' &&
|
||||
itemValue >= parseInt(paramValue))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// item_lt=value
|
||||
case Condition.lt: {
|
||||
if (!(typeof itemValue === 'number' &&
|
||||
itemValue < parseInt(paramValue))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// item_lte=value
|
||||
case Condition.lte: {
|
||||
if (!(typeof itemValue === 'number' &&
|
||||
itemValue <= parseInt(paramValue))) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// item_ne=value
|
||||
case Condition.ne: {
|
||||
switch (typeof itemValue) {
|
||||
case 'number':
|
||||
return itemValue !== parseInt(paramValue);
|
||||
case 'string':
|
||||
return itemValue !== paramValue;
|
||||
case 'boolean':
|
||||
return itemValue !== (paramValue === 'true');
|
||||
}
|
||||
break;
|
||||
}
|
||||
// item=value
|
||||
case Condition.default: {
|
||||
switch (typeof itemValue) {
|
||||
case 'number':
|
||||
return itemValue === parseInt(paramValue);
|
||||
case 'string':
|
||||
return itemValue === paramValue;
|
||||
case 'boolean':
|
||||
return itemValue === (paramValue === 'true');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// Sort
|
||||
const sort = query._sort || '';
|
||||
const sorted = sortOn(filtered, sort.split(','));
|
||||
// Slice
|
||||
const start = query._start;
|
||||
const end = query._end;
|
||||
const limit = query._limit;
|
||||
if (start !== undefined) {
|
||||
if (end !== undefined) {
|
||||
return sorted.slice(start, end);
|
||||
}
|
||||
return sorted.slice(start, start + (limit || 0));
|
||||
}
|
||||
if (limit !== undefined) {
|
||||
return sorted.slice(0, limit);
|
||||
}
|
||||
// Paginate
|
||||
let page = query._page;
|
||||
const perPage = query._per_page || 10;
|
||||
if (page) {
|
||||
const items = sorted.length;
|
||||
const pages = Math.ceil(items / perPage);
|
||||
// Ensure page is within the valid range
|
||||
page = Math.max(1, Math.min(page, pages));
|
||||
const first = 1;
|
||||
const prev = page > 1 ? page - 1 : null;
|
||||
const next = page < pages ? page + 1 : null;
|
||||
const last = pages;
|
||||
const start = (page - 1) * perPage;
|
||||
const end = start + perPage;
|
||||
const data = sorted.slice(start, end);
|
||||
return {
|
||||
first,
|
||||
prev,
|
||||
next,
|
||||
last,
|
||||
pages,
|
||||
items,
|
||||
data,
|
||||
};
|
||||
}
|
||||
return sorted.slice(start, end);
|
||||
}
|
||||
async create(name, data = {}) {
|
||||
const items = this.#get(name);
|
||||
if (items === undefined || !Array.isArray(items))
|
||||
return;
|
||||
const item = { id: randomId(), ...data };
|
||||
items.push(item);
|
||||
await this.#db.write();
|
||||
return item;
|
||||
}
|
||||
async #updateOrPatch(name, body = {}, isPatch) {
|
||||
const item = this.#get(name);
|
||||
if (item === undefined || Array.isArray(item))
|
||||
return;
|
||||
const nextItem = (this.#db.data[name] = isPatch ? { item, ...body } : body);
|
||||
await this.#db.write();
|
||||
return nextItem;
|
||||
}
|
||||
async #updateOrPatchById(name, id, body = {}, isPatch) {
|
||||
const items = this.#get(name);
|
||||
if (items === undefined || !Array.isArray(items))
|
||||
return;
|
||||
const item = items.find((item) => item['id'] === id);
|
||||
if (!item)
|
||||
return;
|
||||
const nextItem = isPatch ? { ...item, ...body, id } : { ...body, id };
|
||||
const index = items.indexOf(item);
|
||||
items.splice(index, 1, nextItem);
|
||||
await this.#db.write();
|
||||
return nextItem;
|
||||
}
|
||||
async update(name, body = {}) {
|
||||
return this.#updateOrPatch(name, body, false);
|
||||
}
|
||||
async patch(name, body = {}) {
|
||||
return this.#updateOrPatch(name, body, true);
|
||||
}
|
||||
async updateById(name, id, body = {}) {
|
||||
return this.#updateOrPatchById(name, id, body, false);
|
||||
}
|
||||
async patchById(name, id, body = {}) {
|
||||
return this.#updateOrPatchById(name, id, body, true);
|
||||
}
|
||||
async destroyById(name, id, dependent) {
|
||||
const items = this.#get(name);
|
||||
if (items === undefined || !Array.isArray(items))
|
||||
return;
|
||||
const item = items.find((item) => item['id'] === id);
|
||||
if (item === undefined)
|
||||
return;
|
||||
const index = items.indexOf(item);
|
||||
items.splice(index, 1);
|
||||
nullifyForeignKey(this.#db, name, id);
|
||||
const dependents = ensureArray(dependent);
|
||||
deleteDependents(this.#db, name, dependents);
|
||||
await this.#db.write();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user