// Note: Only handled objects and primitives are allowed to be set/pushed/mapped import { inspect } from 'node:util'; class Not_Storable_Error extends Error { constructor({ storage, value, prop, id }) { const type = value === null ? 'null' : typeof value; const location = prop ? `property "${prop}" of record #${id}` : `record #${id}`; super(`Cannot store value of type "${type}" in ${location}: ${inspect(value)}`); this.name = 'Not_Storable_Error'; this.storage = storage; this.value = value; } } class Not_Mutable_Error extends Error { constructor({ storage, value, prop, id }) { const type = value === null ? 'null' : typeof value; const location = prop ? `property "${prop}" of record #${id}` : `record #${id}`; super(`Cannot set ${location}: record is immutable (tried to store value of type "${type}": ${inspect(value)})`); this.name = 'Not_Mutable_Error'; this.storage = storage; this.value = value; } } function load_descriptor({ type, value }, { storage, mutable }) { if (type === 'primitive') { return value; } else { throw new Error('not implemented'); } } const Record_Handler = { get(target, prop, receiver) { const { storage, id, mutable } = target; const result_descriptor = storage.get_record_property(id, prop); if (result_descriptor) { return load_descriptor(result_descriptor, { storage, mutable }); } else { return undefined; } }, set(target, prop, value) { const { storage, id, mutable } = target; if (!mutable) { throw new Not_Mutable_Error({ storage, id, prop, value }); } if (!storage.can_be_stored(value)) { throw new Not_Storable_Error({ storage, id, prop, value }); } storage.set_record_property(id, prop, value); return true; } }; class Storage { #pending_id = 1; #records = new Map(); create_record(data=undefined, mutable=true) { const id = this.acquire_new_id(); const property_bag = {}; const result = new Proxy({ storage: this, id, property_bag, mutable, }, Record_Handler); this.#records.set(id, property_bag); if (data !== undefined) { Object.assign(result, data); } return result; } get_record_property(item_id, property) { console.log("Should get record property", { item_id, property }); return { type: 'primitive', value: 'Hello' }; } set_record_property(item_id, property, value) { console.log("Should set record property", { item_id, property, value }); } can_be_stored(value) { if (typeof value === 'string') { return true; } else { return false; } } acquire_new_id() { return this.#pending_id++; } }; const s1 = new Storage(); const p1 = s1.create_record({stuff: 'hello'}, true); console.log(p1.blargh); //p1.stuff = ['hello', 'world'];