Files
nodejs.esm-library/experiments/os1.mjs

145 lines
3.2 KiB
JavaScript

// 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(data) {
const { storage, value, property, id } = data;
const type = value === null ? 'null' : typeof value;
const location = property ? `property "${property}" of record #${id}` : `record #${id}`;
super(`Cannot store value of type "${type}" in ${location}: ${inspect(value)}`);
this.data = data;
}
}
class Not_Mutable_Error extends Error {
constructor(data) {
const { storage, value, property, id } = data;
const type = value === null ? 'null' : typeof value;
const location = property ? `property "${property}" of record #${id}` : `record #${id}`;
super(`Cannot set ${location}: record is immutable (tried to store value of type "${type}": ${inspect(value)})`);
this.data = data;
}
}
class No_Such_Object_Index_Error extends Error {
constructor(data) {
const { storage, property, id } = data;
const location = property ? `property "${property}" of record #${id}` : `record #${id}`;
super(`Cannot get ${location}: no such record index`);
this.data = data;
}
}
function load_descriptor({ type, value }, { storage, mutable }) {
if (type === 'primitive') {
return value;
} else {
throw new Error('not implemented');
}
}
const Record_Handler = {
get(target, property, receiver) {
const { storage, id } = target;
return storage.get_record_property(id, property);
},
set(target, property, value) {
const { storage, id, mutable } = target;
if (!mutable) {
throw new Not_Mutable_Error({ storage, id, property, value });
}
storage.set_record_property(id, property, 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) {
const property_bag = this.#records.get(item_id);
if (property_bag === undefined) {
throw new No_Such_Object_Index_Error({storage: this, id: item_id, property});
}
return property_bag[property];
}
set_record_property(item_id, property, value) {
const descriptor = this.maybe_create_descriptor(value);
if (!descriptor) {
throw new Not_Storable_Error({ storage: this, id: item_id, property, value });
}
const property_bag = this.#records.get(item_id);
if (property_bag === undefined) {
throw new No_Such_Object_Index_Error({storage: this, id: item_id, property});
}
property_bag[property] = descriptor;
}
maybe_create_descriptor(value) {
if (typeof value === 'string') {
return { type: 'primitive', 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: 5n}, true);
console.log(p1.blargh);
console.log(s1.get_record_property(1, 'stuff'))
//p1.stuff = ['hello', 'world'];