Work on experimental storage system
This commit is contained in:
@@ -3,24 +3,31 @@
|
|||||||
import { inspect } from 'node:util';
|
import { inspect } from 'node:util';
|
||||||
|
|
||||||
class Not_Storable_Error extends Error {
|
class Not_Storable_Error extends Error {
|
||||||
constructor({ storage, value, prop, id }) {
|
constructor(data) {
|
||||||
|
const { storage, value, property, id } = data;
|
||||||
const type = value === null ? 'null' : typeof value;
|
const type = value === null ? 'null' : typeof value;
|
||||||
const location = prop ? `property "${prop}" of record #${id}` : `record #${id}`;
|
const location = property ? `property "${property}" of record #${id}` : `record #${id}`;
|
||||||
super(`Cannot store value of type "${type}" in ${location}: ${inspect(value)}`);
|
super(`Cannot store value of type "${type}" in ${location}: ${inspect(value)}`);
|
||||||
this.name = 'Not_Storable_Error';
|
this.data = data;
|
||||||
this.storage = storage;
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Not_Mutable_Error extends Error {
|
class Not_Mutable_Error extends Error {
|
||||||
constructor({ storage, value, prop, id }) {
|
constructor(data) {
|
||||||
|
const { storage, value, property, id } = data;
|
||||||
const type = value === null ? 'null' : typeof value;
|
const type = value === null ? 'null' : typeof value;
|
||||||
const location = prop ? `property "${prop}" of record #${id}` : `record #${id}`;
|
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)})`);
|
super(`Cannot set ${location}: record is immutable (tried to store value of type "${type}": ${inspect(value)})`);
|
||||||
this.name = 'Not_Mutable_Error';
|
this.data = data;
|
||||||
this.storage = storage;
|
}
|
||||||
this.value = value;
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,29 +42,19 @@ function load_descriptor({ type, value }, { storage, mutable }) {
|
|||||||
|
|
||||||
const Record_Handler = {
|
const Record_Handler = {
|
||||||
|
|
||||||
get(target, prop, receiver) {
|
get(target, property, receiver) {
|
||||||
const { storage, id, mutable } = target;
|
const { storage, id } = target;
|
||||||
|
return storage.get_record_property(id, property);
|
||||||
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) {
|
set(target, property, value) {
|
||||||
const { storage, id, mutable } = target;
|
const { storage, id, mutable } = target;
|
||||||
|
|
||||||
if (!mutable) {
|
if (!mutable) {
|
||||||
throw new Not_Mutable_Error({ storage, id, prop, value });
|
throw new Not_Mutable_Error({ storage, id, property, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!storage.can_be_stored(value)) {
|
storage.set_record_property(id, property, value);
|
||||||
throw new Not_Storable_Error({ storage, id, prop, value });
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.set_record_property(id, prop, value);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,12 +86,36 @@ class Storage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_record_property(item_id, property) {
|
get_record_property(item_id, property) {
|
||||||
console.log("Should get record property", { item_id, property });
|
|
||||||
return { type: 'primitive', value: 'Hello' };
|
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) {
|
set_record_property(item_id, property, value) {
|
||||||
console.log("Should 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) {
|
can_be_stored(value) {
|
||||||
@@ -115,7 +136,10 @@ class Storage {
|
|||||||
const s1 = new Storage();
|
const s1 = new Storage();
|
||||||
|
|
||||||
|
|
||||||
const p1 = s1.create_record({stuff: 'hello'}, true);
|
const p1 = s1.create_record({stuff: 5n}, true);
|
||||||
console.log(p1.blargh);
|
console.log(p1.blargh);
|
||||||
|
|
||||||
|
console.log(s1.get_record_property(1, 'stuff'))
|
||||||
|
|
||||||
|
|
||||||
//p1.stuff = ['hello', 'world'];
|
//p1.stuff = ['hello', 'world'];
|
||||||
65
experiments/res1.mjs
Normal file
65
experiments/res1.mjs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
import { inspect } from 'node:util';
|
||||||
|
|
||||||
|
class Item_Unresolvable extends Error {
|
||||||
|
constructor(data) {
|
||||||
|
const { resolver, item } = data;
|
||||||
|
const type = item === null ? 'null' : typeof item;
|
||||||
|
super(`Cannot resolve item ${inspect(item)} of type "${type}" using resolver ${resolver}`);
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Abstract_Resolver {
|
||||||
|
resolve(item) {
|
||||||
|
const handler = this.resolve_handler(item);
|
||||||
|
if (!handler) {
|
||||||
|
throw new Item_Unresolvable({ resolver: this, item });
|
||||||
|
}
|
||||||
|
return handler({ resolver: this, item });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Chained_Resolver extends Abstract_Resolver {
|
||||||
|
constructor(chain_links) {
|
||||||
|
super();
|
||||||
|
Object.assign(this, { chain_links });
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_handler(item) {
|
||||||
|
const { chain_links } = this;
|
||||||
|
for (const link of chain_links) {
|
||||||
|
const handler = link.resolve_handler(item);
|
||||||
|
if (handler) {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Mapping_Resolver {
|
||||||
|
constructor(rules=new Map(), key_function=null) {
|
||||||
|
Object.assign(this, { rules, key_function });
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_handler(item) {
|
||||||
|
const { key_function, rules } = this;
|
||||||
|
const key = key_function ? key_function(item) : item;
|
||||||
|
return rules.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const vr = new Mapping_Resolver();
|
||||||
|
const tr = new Mapping_Resolver(new Map(), item => typeof item);
|
||||||
|
|
||||||
|
const cr = new Chained_Resolver([vr, tr]);
|
||||||
|
|
||||||
|
|
||||||
|
vr.rules.set('HELLO', () => 'WORLD');
|
||||||
|
tr.rules.set('string', () => 'World');
|
||||||
|
|
||||||
|
console.log(cr.resolve('HELLO'));
|
||||||
|
console.log(cr.resolve('hello'));
|
||||||
Reference in New Issue
Block a user