extract disk related actions to frgid & add tests

master
Valerie 2021-06-11 00:47:09 -04:00
parent a8030aa14e
commit bc612290dc
10 changed files with 192 additions and 121 deletions

View File

@ -8,6 +8,7 @@
"repository": "https://github.com/marcus13345/frigid.git",
"devDependencies": {
"@types/node": "^15.12.2",
"chai": "^4.3.4",
"typescript": "^4.3.2",
"yarn": "^1.22.10"
},

33
src/Frigid.ts 100644
View File

@ -0,0 +1,33 @@
import { existsSync, readFileSync, writeFileSync } from "fs";
import Serializable from "./Serializable.js";
const PERSIST_LOCATION = Symbol('PERSIST_LOCATION');
export const RESTORE = Symbol('RESTORE');
export default class Frigid extends Serializable {
static create(filename: string, ...args: any[]) {
if(existsSync(filename)) {
const instance = this.deserialize(readFileSync(filename));
// TS is plain and simply wrong... symbols can be used to index object...
// @ts-ignore
instance[PERSIST_LOCATION] = filename;
instance[RESTORE]();
return instance;
} else {
const instance = new this(...args);
// again... TS is wrong...
// @ts-ignore
instance[PERSIST_LOCATION] = filename;
instance[RESTORE]();
instance.sync();
return instance;
}
}
sync() {
const data = this.serialize();
// this is getting annoying...
// @ts-ignore
writeFileSync(this[PERSIST_LOCATION], data);
}
}

View File

@ -1,5 +1,6 @@
// import { Ubjson } from '@shelacek/ubjson';
import { existsSync, readFileSync, writeFileSync } from 'fs';
import { reverseLookup } from './reverseLookup.js';
export default class Serializable {
@ -14,26 +15,21 @@ export default class Serializable {
static INSTANCE_DECLARATION = '$$INSTANCE_ID';
static INSTANCE_REFERENCE = '$$INSTANCE_REF';
// things that need to be stored only at runtime
// are keyed with symbols to not interfere with
// user code.
static PERSIST_LOCATION = Symbol('PERSIST_LOCATION');
static serializationDependencies(): any[] {
return [];
}
toJson() {
return JSON.stringify(this.toSerializableObject(), null, 2);
}
static serializationDependencies(): any[] {
return [];
}
static fromJson(str: string) {
return this.fromSerializableObject(JSON.parse(str));
}
// thisdoesnt operate recursively, it doesnt need to, because dependency
// resoltion isnt required. we simply declare the dependencies.
// so we never touch static serializationDependencies!
// this doesnt operate recursively, it doesnt need to, because
// dependency resoltion isnt required. we simply declare the
// dependencies. so we never touch serializationDependencies!
toSerializableObject() {
const instances: Map<number, object> = new Map();
@ -197,57 +193,4 @@ export default class Serializable {
}
}
}
async restore() {}
static createFromDisk(filename: string, ...args: any[]) {
const filepath = createFilepath(filename);
if(existsSync(filepath)) {
const instance = this.deserialize(readFileSync(filepath));
// TS is plain and simply wrong... symbols can be used to index object...
// @ts-ignore
instance[Serializable.PERSIST_LOCATION] = filepath;
instance?.restore();
return instance;
} else {
const instance = new this(...args);
// again... TS is wrong...
// @ts-ignore
instance[Serializable.PERSIST_LOCATION] = filepath;
instance?.updateDisk();
return instance;
}
}
updateDisk(filepath?: string) {
// if it hasnt yet been written to disk...
// this can happen if the contrustor
// was called outside of createFromDisk
if(filepath) {
// see above... TS7053 is just _wrong_. incorrect. thats not how JS works.
// @ts-ignore
this[Serializable.PERSIST_LOCATION] = createFilepath(filepath);
}
const data = this.serialize();
// this is getting annoying...
// @ts-ignore
writeFileSync(this[Serializable.PERSIST_LOCATION], data);
}
}
function createFilepath(path: string) {
return `data/${path}`;
}
function reverseLookup<K, V>(map: Map<K, V>, value: V): K {
// console.log('searching for', value, 'in', map);
for(const [k, v] of map) {
if(v === value) {
// console.log('found in key', k);
return k;
}
}
// console.log(value, 'not found')
return null;
}

View File

@ -1 +1,2 @@
export {default as Serializable} from './Serializable.js';
export {default as Serializable} from './Serializable.js';
export {default as Frigid, RESTORE} from './Frigid.js'

View File

@ -0,0 +1,11 @@
export function reverseLookup<K, V>(map: Map<K, V>, value: V): K {
// console.log('searching for', value, 'in', map);
for (const [k, v] of map) {
if (v === value) {
// console.log('found in key', k);
return k;
}
}
// console.log(value, 'not found')
return null;
}

5
test.state.json 100644
View File

@ -0,0 +1,5 @@
{
"$$INSTANCE_ID": 0,
"foo": "bar",
"$$CLASS_NAME": "Test"
}

42
test/Frigid.js 100644
View File

@ -0,0 +1,42 @@
import {Frigid, RESTORE} from '../out/index.js';
import { existsSync, readFileSync, unlinkSync } from 'fs';
import { expect } from 'chai';
const trackingData = {
constructorCalls: 0,
restoreCalls: 0
}
class Test extends Frigid {
foo = 'bar';
constructor() {
super();
trackingData.constructorCalls ++;
}
[RESTORE]() {
trackingData.restoreCalls ++;
}
}
const filepath = 'test.state.json';
if(existsSync(filepath)) {
unlinkSync(filepath)
}
const test = Test.create(filepath)
expect(test.sync.bind(test)).to.not.throw();
expect(existsSync(filepath)).to.be.true;
expect(readFileSync(filepath).toString()).to.not.be.empty;
expect(trackingData.constructorCalls).to.equal(1);
expect(trackingData.restoreCalls).to.equal(1);
const retest = Test.create(filepath);
expect(trackingData.constructorCalls).to.equal(1);
expect(trackingData.restoreCalls).to.equal(2);

View File

@ -0,0 +1,51 @@
import { Serializable } from '../out/index.js'
class Sub extends Serializable {
otherData = sharedObject;
root;
static serializationDependencies() {
return [Root];
}
}
class Root extends Serializable{
stuff = sharedObject;
child;
static serializationDependencies() {
return [Sub];
}
test() {
return {
circular: this.child.root === this,
shared: this.stuff === this.child.otherData
}
}
}
const sharedObject = {shared: 'data'}
const root = new Root();
const sub = new Sub();
root.child = sub;
sub.root = root;
console.clear();
console.log('#'.repeat(process.stdout.columns));
console.log(root);
const json = root.toJson();
console.log(json);
const obj = Root.fromJson(json);
console.log(obj);
const tests = obj.test();
console.log(tests);
const passing = Object.values(tests).reduce((v, acc) => v && acc, true);
if(!passing) {
console.log('Some tests failed!');
process.exit(1);
};

View File

@ -1,57 +1,4 @@
import { Serializable } from '../out/index.js'
import './Serializable.js';
import './Frigid.js';
class Sub extends Serializable {
otherData = sharedObject;
root;
static serializationDependencies() {
return [Root];
}
}
class Root extends Serializable{
stuff = sharedObject;
child;
static serializationDependencies() {
return [Sub];
}
test() {
return {
circular: this.child.root === this,
shared: this.stuff === this.child.otherData
}
}
}
const sharedObject = {shared: 'data'}
const root = new Root();
const sub = new Sub();
root.child = sub;
sub.root = root;
console.clear();
console.log('#'.repeat(process.stdout.columns));
console.log(root);
const json = root.toJson();
console.log(json);
const obj = Root.fromJson(json);
console.log(obj);
const tests = obj.test();
console.log(tests);
const passing = Object.values(tests).reduce((v, acc) => v && acc, true);
if(!passing) {
console.log('Some tests failed!');
process.exit(1);
} else {
console.log('All tests Passed!');
}
console.log('All tests passed!');

View File

@ -6,6 +6,43 @@
version "15.12.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-15.12.2.tgz#1f2b42c4be7156ff4a6f914b2fb03d05fa84e38d"
assertion-error@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
chai@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
dependencies:
assertion-error "^1.1.0"
check-error "^1.0.2"
deep-eql "^3.0.1"
get-func-name "^2.0.0"
pathval "^1.1.1"
type-detect "^4.0.5"
check-error@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82"
deep-eql@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
dependencies:
type-detect "^4.0.0"
get-func-name@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
pathval@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
type-detect@^4.0.0, type-detect@^4.0.5:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
typescript@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.2.tgz#399ab18aac45802d6f2498de5054fcbbe716a805"