UNPKG

@cloud-cli/store

Version:
114 lines (113 loc) 3.99 kB
import { Resource, ResourceDriver } from './resource.js'; import { randomUUID } from 'crypto'; const headers = { 'content-type': 'application/json' }; export class StoreDriver extends ResourceDriver { constructor(baseUrl = process.env.STORE_URL) { super(); this.storeUrl = String(baseUrl).replace(/\/$/, ''); } async create(resource) { const desc = Resource.describe(resource); const { name } = desc; const url = this.storeUrl + '/' + name + '/0'; try { await StoreDriver.fetch(url, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: '{}', }); await StoreDriver.fetch(url, { method: 'DELETE' }); } catch { throw new Error(`Cannot create resource "${name}"`); } } async save(model) { const desc = Resource.describe(model); const { url, id } = this.getUrl(model); desc.fields.forEach((field) => { model[field.name] = model[field.name] ?? field.defaultValue; }); const body = JSON.stringify(model); const remote = await StoreDriver.fetch(url, { method: 'PUT', headers, body }); if (remote.ok) { return id; } throw new Error(String(remote.status)); } async remove(model) { const { url } = this.getUrl(model); return void (await StoreDriver.fetch(url, { method: 'DELETE' })); } async find(model) { const { url } = this.getUrl(model); const resource = Object.getPrototypeOf(model).constructor; const remote = await StoreDriver.fetch(url); if (remote.ok) { return this.createModel(resource, await remote.json()); } throw new Error('Not found'); } async findAll(resource, query) { const desc = Resource.describe(resource); const { name } = desc; const url = this.storeUrl + '/' + name; const remote = await StoreDriver.fetch(url); if (remote.ok) { const map = await remote.json(); const items = Object.values(map).map((raw) => this.createModel(resource, raw)); return this.filter(items, query); } throw new Error('Not found'); } getUrl(model) { const desc = Resource.describe(model); const { name } = desc; const primary = desc.fields.find((field) => field.primary); if (!model[primary.name]) { model[primary.name] = StoreDriver.uid(); } const id = model[primary.name]; const url = this.storeUrl + '/' + name + '/' + id; return { url, id }; } filter(items, query) { const filters = query.toJSON(); let next; while (items.length && (next = filters.shift())) { const [left, op, right] = next; items = items.filter((item) => this.compare(item, left, op, right)); } return items; } compare(item, left, op, right) { switch (op) { case '=': return item[left] == right; case '!=': return item[left] != right; case 'like': return String(item[left]).includes(String(right)); case '>': return item[left] > right; case '<': return item[left] < right; case '>=': return item[left] >= right; case '<=': return item[left] <= right; default: return true; } } createModel(model, data) { const desc = Resource.describe(model); const modelData = {}; desc.fields.forEach((field) => { modelData[field.name] = data[field.name] ?? field.defaultValue; }); return new model(modelData); } } StoreDriver.fetch = globalThis.fetch; StoreDriver.uid = randomUUID;