refactored collection into abstract and basic in preparation for adding relational
This commit is contained in:
parent
c6f6ece504
commit
6e0dccdfea
|
@ -1,5 +1,5 @@
|
|||
import Debug from 'debug';
|
||||
import {Collection} from "../src/collection";
|
||||
import {BasicCollection} from '../src/collection-basic';
|
||||
import {Entity} from "../src/entity";
|
||||
import {RhizomeNode} from "../src/node";
|
||||
const debug = Debug('example-app');
|
||||
|
@ -23,7 +23,7 @@ type User = {
|
|||
// Enable API to read lossless view
|
||||
rhizomeNode.httpServer.httpApi.serveLossless();
|
||||
|
||||
const users = new Collection("user");
|
||||
const users = new BasicCollection("user");
|
||||
users.rhizomeConnect(rhizomeNode);
|
||||
|
||||
users.onUpdate((u: Entity) => {
|
||||
|
|
|
@ -1,38 +1,31 @@
|
|||
// A basic collection of entities
|
||||
// This may be extended to house a collection of objects that all follow a common schema.
|
||||
// It should enable operations like removing a property removes the value from the entities in the collection
|
||||
// It could then be further extended with e.g. table semantics like filter, sort, join
|
||||
|
||||
import Debug from 'debug';
|
||||
import {randomUUID} from "node:crypto";
|
||||
import EventEmitter from "node:events";
|
||||
import {Delta} from "./delta";
|
||||
import {Entity, EntityProperties} from "./entity";
|
||||
import {LastWriteWins, ResolvedViewOne} from './last-write-wins';
|
||||
import {ResolvedViewOne} from './last-write-wins';
|
||||
import {RhizomeNode} from "./node";
|
||||
import {DomainEntityID} from "./types";
|
||||
const debug = Debug('rz:collection');
|
||||
const debug = Debug('rz:abstract-collection');
|
||||
|
||||
export class Collection {
|
||||
export abstract class Collection<T> {
|
||||
rhizomeNode?: RhizomeNode;
|
||||
name: string;
|
||||
eventStream = new EventEmitter();
|
||||
lossy?: LastWriteWins;
|
||||
lossy?: T;
|
||||
|
||||
constructor(name: string) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// Instead of trying to update our final view of the entity with every incoming delta,
|
||||
// let's try this:
|
||||
// - keep a lossless view (of everything)
|
||||
// - build a lossy view when needed
|
||||
// This approach is simplistic, but can then be optimized and enhanced.
|
||||
abstract initializeView(): void;
|
||||
|
||||
abstract resolve(id: string): ResolvedViewOne | undefined;
|
||||
|
||||
rhizomeConnect(rhizomeNode: RhizomeNode) {
|
||||
this.rhizomeNode = rhizomeNode;
|
||||
|
||||
this.lossy = new LastWriteWins(this.rhizomeNode.lossless);
|
||||
this.initializeView();
|
||||
|
||||
// Listen for completed transactions, and emit updates to event stream
|
||||
this.rhizomeNode.lossless.eventStream.on("updated", (id) => {
|
||||
|
@ -43,13 +36,12 @@ export class Collection {
|
|||
this.eventStream.emit("update", res);
|
||||
});
|
||||
|
||||
rhizomeNode.httpServer.httpApi.serveCollection(this);
|
||||
// TODO: Fix this
|
||||
rhizomeNode.httpServer.httpApi.serveCollection<T>(this);
|
||||
|
||||
debug(`[${this.rhizomeNode.config.peerId}]`, `Connected ${this.name} to rhizome`);
|
||||
}
|
||||
|
||||
// Applies the javascript rules for updating object values,
|
||||
// e.g. set to `undefined` to delete a property.
|
||||
// This function is here instead of Entity so that it can:
|
||||
// - read the current state in order to build its delta
|
||||
// - include the collection name in the delta it produces
|
||||
|
@ -206,14 +198,4 @@ export class Collection {
|
|||
return res;
|
||||
}
|
||||
|
||||
resolve(
|
||||
id: string
|
||||
): ResolvedViewOne | undefined {
|
||||
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
|
||||
if (!this.lossy) throw new Error('lossy view not initialized');
|
||||
|
||||
const res = this.lossy.resolve([id]) || {};
|
||||
|
||||
return res[id];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// A basic collection of entities
|
||||
// This may be extended to house a collection of objects that all follow a common schema.
|
||||
// It should enable operations like removing a property removes the value from the entities in the collection
|
||||
// It could then be further extended with e.g. table semantics like filter, sort, join
|
||||
|
||||
import {Collection} from './collection-abstract';
|
||||
import {LastWriteWins, ResolvedViewOne} from './last-write-wins';
|
||||
|
||||
export class BasicCollection extends Collection<LastWriteWins> {
|
||||
lossy?: LastWriteWins;
|
||||
|
||||
initializeView() {
|
||||
if (!this.rhizomeNode) throw new Error('not connected to rhizome');
|
||||
this.lossy = new LastWriteWins(this.rhizomeNode.lossless);
|
||||
}
|
||||
|
||||
resolve(
|
||||
id: string
|
||||
): ResolvedViewOne | undefined {
|
||||
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
|
||||
if (!this.lossy) throw new Error('lossy view not initialized');
|
||||
|
||||
const res = this.lossy.resolve([id]) || {};
|
||||
|
||||
return res[id];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import {Collection} from "./collection-abstract";
|
||||
import {LastWriteWins, ResolvedViewOne} from "./last-write-wins";
|
||||
|
||||
class RelationalView extends LastWriteWins {
|
||||
}
|
||||
|
||||
export class RelationalCollection extends Collection<RelationalView> {
|
||||
lossy?: RelationalView;
|
||||
|
||||
initializeView() {
|
||||
if (!this.rhizomeNode) throw new Error('not connected to rhizome');
|
||||
this.lossy = new RelationalView(this.rhizomeNode.lossless);
|
||||
}
|
||||
|
||||
resolve(
|
||||
id: string
|
||||
): ResolvedViewOne | undefined {
|
||||
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
|
||||
if (!this.lossy) throw new Error('lossy view not initialized');
|
||||
|
||||
const res = this.lossy.resolve([id]) || {};
|
||||
|
||||
return res[id];
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
// - As typescript interfaces?
|
||||
// - As typescript classes?
|
||||
|
||||
import {Collection} from "./collection";
|
||||
import {PropertyTypes} from "./types";
|
||||
|
||||
export type EntityProperties = {
|
||||
|
@ -20,11 +19,5 @@ export class Entity {
|
|||
|
||||
constructor(
|
||||
readonly id: string,
|
||||
readonly collection?: Collection
|
||||
) {}
|
||||
|
||||
async save() {
|
||||
if (!this.collection) throw new Error('to save this entity you must specify the collection');
|
||||
return this.collection.put(this.id, this.properties);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import express, {Router} from "express";
|
||||
import {Collection} from "../collection";
|
||||
import {Collection} from "../collection-abstract";
|
||||
import {Delta} from "../delta";
|
||||
import {RhizomeNode} from "../node";
|
||||
|
||||
|
@ -57,7 +57,8 @@ export class HttpApi {
|
|||
});
|
||||
}
|
||||
|
||||
serveCollection(collection: Collection) {
|
||||
// serveCollection<T extends Collection>(collection: T) {
|
||||
serveCollection<View>(collection: Collection<View>) {
|
||||
const {name} = collection;
|
||||
|
||||
// Get the ID of all domain entities
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import {Collection} from "./collection";
|
||||
|
||||
|
||||
|
||||
|
||||
export class RelationalCollection extends Collection {
|
||||
// lossy?:
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import {Collection} from "../src/collection";
|
||||
import {BasicCollection} from "../src/collection-basic";
|
||||
import {RhizomeNode, RhizomeNodeConfig} from "../src/node";
|
||||
|
||||
const start = 5000;
|
||||
|
@ -17,7 +17,7 @@ export class App extends RhizomeNode {
|
|||
...config,
|
||||
});
|
||||
|
||||
const users = new Collection("user");
|
||||
const users = new BasicCollection("user");
|
||||
users.rhizomeConnect(this);
|
||||
|
||||
const {httpAddr, httpPort} = this.config;
|
||||
|
|
Loading…
Reference in New Issue