Rename Lossless/Lossy to Hyperview/View #6
@ -1,4 +1,4 @@
|
|||||||
import { HyperviewViewOne } from '@src/views/hyperview';
|
import { HyperviewOne } from '@src/views/hyperview';
|
||||||
import {
|
import {
|
||||||
SchemaBuilder,
|
SchemaBuilder,
|
||||||
PrimitiveSchemas,
|
PrimitiveSchemas,
|
||||||
@ -158,7 +158,7 @@ describe('Schema System', () => {
|
|||||||
schemaRegistry.register(userSchema);
|
schemaRegistry.register(userSchema);
|
||||||
|
|
||||||
// Create a valid hyperview
|
// Create a valid hyperview
|
||||||
const validView: HyperviewViewOne = {
|
const validView: HyperviewOne = {
|
||||||
id: 'user123',
|
id: 'user123',
|
||||||
propertyDeltas: {
|
propertyDeltas: {
|
||||||
name: [
|
name: [
|
||||||
@ -179,7 +179,7 @@ describe('Schema System', () => {
|
|||||||
expect(result.errors).toHaveLength(0);
|
expect(result.errors).toHaveLength(0);
|
||||||
|
|
||||||
// Test invalid view (missing required property)
|
// Test invalid view (missing required property)
|
||||||
const invalidView: HyperviewViewOne = {
|
const invalidView: HyperviewOne = {
|
||||||
id: 'user456',
|
id: 'user456',
|
||||||
propertyDeltas: {
|
propertyDeltas: {
|
||||||
age: [
|
age: [
|
||||||
@ -212,7 +212,7 @@ describe('Schema System', () => {
|
|||||||
schemaRegistry.register(schema);
|
schemaRegistry.register(schema);
|
||||||
|
|
||||||
// Valid types
|
// Valid types
|
||||||
const validView: HyperviewViewOne = {
|
const validView: HyperviewOne = {
|
||||||
id: 'test1',
|
id: 'test1',
|
||||||
propertyDeltas: {
|
propertyDeltas: {
|
||||||
stringProp: [
|
stringProp: [
|
||||||
@ -240,7 +240,7 @@ describe('Schema System', () => {
|
|||||||
expect(validResult.valid).toBe(true);
|
expect(validResult.valid).toBe(true);
|
||||||
|
|
||||||
// Invalid types
|
// Invalid types
|
||||||
const invalidView: HyperviewViewOne = {
|
const invalidView: HyperviewOne = {
|
||||||
id: 'test2',
|
id: 'test2',
|
||||||
propertyDeltas: {
|
propertyDeltas: {
|
||||||
stringProp: [
|
stringProp: [
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import { PointerTarget } from "@src/core/delta";
|
import { PointerTarget } from "@src/core/delta";
|
||||||
import { Hyperview, HyperviewViewOne } from "@src/views/hyperview";
|
import { Hyperview, HyperviewOne } from "@src/views/hyperview";
|
||||||
import { Lossy } from "@src/views/view";
|
import { Lossy } from "@src/views/view";
|
||||||
import { RhizomeNode } from "@src/node";
|
import { RhizomeNode } from "@src/node";
|
||||||
import { valueFromDelta } from "@src/views/hyperview";
|
import { valueFromDelta } from "@src/views/hyperview";
|
||||||
@ -37,7 +37,7 @@ class Summarizer extends Lossy<Summary> {
|
|||||||
// it's really not CRDT, it likely depends on the order of the pointers.
|
// it's really not CRDT, it likely depends on the order of the pointers.
|
||||||
// TODO: Prove with failing test
|
// TODO: Prove with failing test
|
||||||
|
|
||||||
reducer(acc: Summary, cur: HyperviewViewOne): Summary {
|
reducer(acc: Summary, cur: HyperviewOne): Summary {
|
||||||
this.debug(`Processing view for entity ${cur.id} (referenced as: ${cur.referencedAs?.join(', ')})`);
|
this.debug(`Processing view for entity ${cur.id} (referenced as: ${cur.referencedAs?.join(', ')})`);
|
||||||
this.debug(`hyperview:`, JSON.stringify(cur));
|
this.debug(`hyperview:`, JSON.stringify(cur));
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ classDiagram
|
|||||||
class Hyperview {
|
class Hyperview {
|
||||||
-domainEntities: Map<DomainEntityID, HyperviewEntity>
|
-domainEntities: Map<DomainEntityID, HyperviewEntity>
|
||||||
-transactions: Transactions
|
-transactions: Transactions
|
||||||
+view(ids: DomainEntityID[]): HyperviewViewMany
|
+view(ids: DomainEntityID[]): HyperviewMany
|
||||||
+compose(ids: DomainEntityID[]): HyperviewViewMany
|
+compose(ids: DomainEntityID[]): HyperviewMany
|
||||||
}
|
}
|
||||||
|
|
||||||
class QueryEngine {
|
class QueryEngine {
|
||||||
|
@ -14,7 +14,7 @@ class CustomResolver {
|
|||||||
* @param config Plugin configuration
|
* @param config Plugin configuration
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
private readonly view: HyperviewView,
|
private readonly view: Hyperview,
|
||||||
private readonly config: ResolverConfig
|
private readonly config: ResolverConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ class CustomResolver {
|
|||||||
Creates a new instance of the CustomResolver.
|
Creates a new instance of the CustomResolver.
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
- `view: HyperviewView` - The hyperview containing the data to resolve
|
- `view: Hyperview` - The hyperview containing the data to resolve
|
||||||
- `config: ResolverConfig` - Configuration object mapping property IDs to their resolver plugins
|
- `config: ResolverConfig` - Configuration object mapping property IDs to their resolver plugins
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
@ -146,10 +146,10 @@ The resolver may throw the following errors:
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { CustomResolver, LastWriteWinsPlugin } from './resolver';
|
import { CustomResolver, LastWriteWinsPlugin } from './resolver';
|
||||||
import { HyperviewView } from '../hyperview-view';
|
import { Hyperview } from '../hyperview-view';
|
||||||
|
|
||||||
// Create a hyperview with some data
|
// Create a hyperview with some data
|
||||||
const view = new HyperviewView();
|
const view = new Hyperview();
|
||||||
// ... add data to the view ...
|
// ... add data to the view ...
|
||||||
|
|
||||||
// Configure the resolver
|
// Configure the resolver
|
||||||
|
@ -78,11 +78,11 @@ Create tests to verify your plugin's behavior:
|
|||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
describe('DiscountedPricePlugin', () => {
|
describe('DiscountedPricePlugin', () => {
|
||||||
let view: HyperviewView;
|
let view: Hyperview;
|
||||||
let resolver: CustomResolver;
|
let resolver: CustomResolver;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
view = new HyperviewView();
|
view = new Hyperview();
|
||||||
resolver = new CustomResolver(view, {
|
resolver = new CustomResolver(view, {
|
||||||
basePrice: new LastWriteWinsPlugin(),
|
basePrice: new LastWriteWinsPlugin(),
|
||||||
discount: new LastWriteWinsPlugin(),
|
discount: new LastWriteWinsPlugin(),
|
||||||
|
@ -15,7 +15,7 @@ The rhizome-node implementation demonstrates strong alignment with core spec con
|
|||||||
|
|
||||||
2. **Hyperview Views**
|
2. **Hyperview Views**
|
||||||
- **Spec**: Full inventory of all deltas composing an object
|
- **Spec**: Full inventory of all deltas composing an object
|
||||||
- **Implementation**: `HyperviewViewDomain` correctly accumulates deltas by entity/property
|
- **Implementation**: `HyperviewDomain` correctly accumulates deltas by entity/property
|
||||||
- **Tests**: Good coverage of basic transformation, filtering by creator/host
|
- **Tests**: Good coverage of basic transformation, filtering by creator/host
|
||||||
|
|
||||||
3. **Lossy Views**
|
3. **Lossy Views**
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
SchemaApplicationOptions
|
SchemaApplicationOptions
|
||||||
} from '../schema/schema';
|
} from '../schema/schema';
|
||||||
import { DefaultSchemaRegistry } from '../schema/schema-registry';
|
import { DefaultSchemaRegistry } from '../schema/schema-registry';
|
||||||
import { HyperviewViewOne } from '../views/hyperview';
|
import { HyperviewOne } from '../views/hyperview';
|
||||||
import { DomainEntityID } from '../core/types';
|
import { DomainEntityID } from '../core/types';
|
||||||
import { EntityProperties } from '../core/entity';
|
import { EntityProperties } from '../core/entity';
|
||||||
import { createDelta } from '@src/core';
|
import { createDelta } from '@src/core';
|
||||||
@ -72,24 +72,24 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
|
|||||||
// Validate an entity against the schema
|
// Validate an entity against the schema
|
||||||
validate(entity: T): SchemaValidationResult {
|
validate(entity: T): SchemaValidationResult {
|
||||||
// Convert entity to a mock hyperview for validation
|
// Convert entity to a mock hyperview for validation
|
||||||
const mockHyperviewView: HyperviewViewOne = {
|
const mockHyperview: HyperviewOne = {
|
||||||
id: 'validation-mock',
|
id: 'validation-mock',
|
||||||
referencedAs: [],
|
referencedAs: [],
|
||||||
propertyDeltas: {},
|
propertyDeltas: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(entity)) {
|
for (const [key, value] of Object.entries(entity)) {
|
||||||
mockHyperviewView.propertyDeltas[key] = [createDelta('validation', 'validation')
|
mockHyperview.propertyDeltas[key] = [createDelta('validation', 'validation')
|
||||||
.addPointer(key, value as string)
|
.addPointer(key, value as string)
|
||||||
.buildV1(),
|
.buildV1(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.schemaRegistry.validate('validation-mock', this.schema.id, mockHyperviewView);
|
return this.schemaRegistry.validate('validation-mock', this.schema.id, mockHyperview);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply schema to a hyperview
|
// Apply schema to a hyperview
|
||||||
apply(view: HyperviewViewOne): SchemaAppliedView {
|
apply(view: HyperviewOne): SchemaAppliedView {
|
||||||
return this.schemaRegistry.applySchema(view, this.schema.id, this.applicationOptions);
|
return this.schemaRegistry.applySchema(view, this.schema.id, this.applicationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,10 +97,10 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
|
|||||||
getValidatedView(entityId: DomainEntityID): SchemaAppliedView | undefined {
|
getValidatedView(entityId: DomainEntityID): SchemaAppliedView | undefined {
|
||||||
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
|
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
|
||||||
|
|
||||||
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
||||||
if (!hyperviewView) return undefined;
|
if (!hyperview) return undefined;
|
||||||
|
|
||||||
return this.apply(hyperviewView);
|
return this.apply(hyperview);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all entities in this collection with schema validation
|
// Get all entities in this collection with schema validation
|
||||||
@ -169,10 +169,10 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
|
|||||||
for (const entityId of entityIds) {
|
for (const entityId of entityIds) {
|
||||||
if (!this.rhizomeNode) continue;
|
if (!this.rhizomeNode) continue;
|
||||||
|
|
||||||
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
||||||
if (!hyperviewView) continue;
|
if (!hyperview) continue;
|
||||||
|
|
||||||
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperviewView);
|
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperview);
|
||||||
|
|
||||||
if (validationResult.valid) {
|
if (validationResult.valid) {
|
||||||
stats.validEntities++;
|
stats.validEntities++;
|
||||||
@ -200,16 +200,16 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
|
|||||||
debug(`No rhizome node connected`)
|
debug(`No rhizome node connected`)
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const hyperviewView = this.rhizomeNode.hyperview.compose(this.getIds());
|
const hyperview = this.rhizomeNode.hyperview.compose(this.getIds());
|
||||||
if (!hyperviewView) {
|
if (!hyperview) {
|
||||||
debug(`No hyperview found`)
|
debug(`No hyperview found`)
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
debug(`getValidEntities, hyperviewView: ${JSON.stringify(hyperviewView, null, 2)}`)
|
debug(`getValidEntities, hyperview: ${JSON.stringify(hyperview, null, 2)}`)
|
||||||
debug(`Validating ${this.getIds().length} entities`)
|
debug(`Validating ${this.getIds().length} entities`)
|
||||||
return this.getIds().filter(entityId => {
|
return this.getIds().filter(entityId => {
|
||||||
debug(`Validating entity ${entityId}`)
|
debug(`Validating entity ${entityId}`)
|
||||||
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperviewView[entityId]);
|
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperview[entityId]);
|
||||||
debug(`Validation result for entity ${entityId}: ${JSON.stringify(validationResult)}`)
|
debug(`Validation result for entity ${entityId}: ${JSON.stringify(validationResult)}`)
|
||||||
return validationResult.valid;
|
return validationResult.valid;
|
||||||
});
|
});
|
||||||
@ -221,10 +221,10 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
|
|||||||
const invalid: Array<{ entityId: DomainEntityID; errors: string[] }> = [];
|
const invalid: Array<{ entityId: DomainEntityID; errors: string[] }> = [];
|
||||||
|
|
||||||
for (const entityId of this.getIds()) {
|
for (const entityId of this.getIds()) {
|
||||||
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
|
||||||
if (!hyperviewView) continue;
|
if (!hyperview) continue;
|
||||||
|
|
||||||
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperviewView);
|
const validationResult = this.schemaRegistry.validate(entityId, this.schema.id, hyperview);
|
||||||
if (!validationResult.valid) {
|
if (!validationResult.valid) {
|
||||||
invalid.push({
|
invalid.push({
|
||||||
entityId,
|
entityId,
|
||||||
|
@ -2,7 +2,7 @@ import jsonLogic from 'json-logic-js';
|
|||||||
const { apply, is_logic } = jsonLogic;
|
const { apply, is_logic } = jsonLogic;
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import { SchemaRegistry, SchemaID, ObjectSchema } from '../schema/schema';
|
import { SchemaRegistry, SchemaID, ObjectSchema } from '../schema/schema';
|
||||||
import { Hyperview, HyperviewViewMany, HyperviewViewOne, valueFromDelta } from '../views/hyperview';
|
import { Hyperview, HyperviewMany, HyperviewOne, valueFromDelta } from '../views/hyperview';
|
||||||
import { DomainEntityID } from '../core/types';
|
import { DomainEntityID } from '../core/types';
|
||||||
import { Delta, DeltaFilter } from '../core/delta';
|
import { Delta, DeltaFilter } from '../core/delta';
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export interface QueryOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface QueryResult {
|
export interface QueryResult {
|
||||||
entities: HyperviewViewMany;
|
entities: HyperviewMany;
|
||||||
totalFound: number;
|
totalFound: number;
|
||||||
limited: boolean;
|
limited: boolean;
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ export class QueryEngine {
|
|||||||
debug(`Composed ${Object.keys(allViews).length} hyperviews`);
|
debug(`Composed ${Object.keys(allViews).length} hyperviews`);
|
||||||
|
|
||||||
// 3. Apply JSON Logic filter if provided
|
// 3. Apply JSON Logic filter if provided
|
||||||
let filteredViews: HyperviewViewMany = allViews;
|
let filteredViews: HyperviewMany = allViews;
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
filteredViews = this.applyJsonLogicFilter(allViews, filter, schemaId);
|
filteredViews = this.applyJsonLogicFilter(allViews, filter, schemaId);
|
||||||
@ -132,7 +132,7 @@ export class QueryEngine {
|
|||||||
/**
|
/**
|
||||||
* Query for a single entity by ID with schema validation
|
* Query for a single entity by ID with schema validation
|
||||||
*/
|
*/
|
||||||
async queryOne(schemaId: SchemaID, entityId: DomainEntityID): Promise<HyperviewViewOne | null> {
|
async queryOne(schemaId: SchemaID, entityId: DomainEntityID): Promise<HyperviewOne | null> {
|
||||||
debug(`Querying single entity ${entityId} with schema ${schemaId}`);
|
debug(`Querying single entity ${entityId} with schema ${schemaId}`);
|
||||||
|
|
||||||
const views = this.hyperview.compose([entityId]);
|
const views = this.hyperview.compose([entityId]);
|
||||||
@ -199,24 +199,24 @@ export class QueryEngine {
|
|||||||
* This requires converting each hyperview to a queryable object
|
* This requires converting each hyperview to a queryable object
|
||||||
*/
|
*/
|
||||||
private applyJsonLogicFilter(
|
private applyJsonLogicFilter(
|
||||||
views: HyperviewViewMany,
|
views: HyperviewMany,
|
||||||
filter: JsonLogic,
|
filter: JsonLogic,
|
||||||
schemaId: SchemaID
|
schemaId: SchemaID
|
||||||
): HyperviewViewMany {
|
): HyperviewMany {
|
||||||
const schema = this.schemaRegistry.get(schemaId);
|
const schema = this.schemaRegistry.get(schemaId);
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
debug(`Cannot filter without schema ${schemaId}`);
|
debug(`Cannot filter without schema ${schemaId}`);
|
||||||
return views;
|
return views;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filteredViews: HyperviewViewMany = {};
|
const filteredViews: HyperviewMany = {};
|
||||||
let hasFilterErrors = false;
|
let hasFilterErrors = false;
|
||||||
const filterErrors: string[] = [];
|
const filterErrors: string[] = [];
|
||||||
|
|
||||||
for (const [entityId, view] of Object.entries(views)) {
|
for (const [entityId, view] of Object.entries(views)) {
|
||||||
try {
|
try {
|
||||||
// Convert hyperview to queryable object using schema
|
// Convert hyperview to queryable object using schema
|
||||||
const queryableObject = this.hyperviewViewToQueryableObject(view, schema);
|
const queryableObject = this.hyperviewToQueryableObject(view, schema);
|
||||||
|
|
||||||
// Apply JSON Logic filter
|
// Apply JSON Logic filter
|
||||||
const matches = apply(filter, queryableObject);
|
const matches = apply(filter, queryableObject);
|
||||||
@ -249,7 +249,7 @@ export class QueryEngine {
|
|||||||
* Convert a hyperview to a queryable object based on schema
|
* Convert a hyperview to a queryable object based on schema
|
||||||
* Uses simple resolution strategies for now
|
* Uses simple resolution strategies for now
|
||||||
*/
|
*/
|
||||||
private hyperviewViewToQueryableObject(view: HyperviewViewOne, schema: ObjectSchema): Record<string, unknown> {
|
private hyperviewToQueryableObject(view: HyperviewOne, schema: ObjectSchema): Record<string, unknown> {
|
||||||
const obj: Record<string, unknown> = {
|
const obj: Record<string, unknown> = {
|
||||||
id: view.id,
|
id: view.id,
|
||||||
_referencedAs: view.referencedAs
|
_referencedAs: view.referencedAs
|
||||||
@ -315,7 +315,7 @@ export class QueryEngine {
|
|||||||
/**
|
/**
|
||||||
* Check if an entity matches a schema (basic validation)
|
* Check if an entity matches a schema (basic validation)
|
||||||
*/
|
*/
|
||||||
private entityMatchesSchema(view: HyperviewViewOne, schemaId: SchemaID): boolean {
|
private entityMatchesSchema(view: HyperviewOne, schemaId: SchemaID): boolean {
|
||||||
const schema = this.schemaRegistry.get(schemaId);
|
const schema = this.schemaRegistry.get(schemaId);
|
||||||
if (!schema) return false;
|
if (!schema) return false;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
SchemaApplicationOptions,
|
SchemaApplicationOptions,
|
||||||
ResolutionContext
|
ResolutionContext
|
||||||
} from '../schema/schema';
|
} from '../schema/schema';
|
||||||
import { Hyperview, HyperviewViewOne } from '../views/hyperview';
|
import { Hyperview, HyperviewOne } from '../views/hyperview';
|
||||||
import { DomainEntityID, PropertyID, PropertyTypes } from '../core/types';
|
import { DomainEntityID, PropertyID, PropertyTypes } from '../core/types';
|
||||||
import { CollapsedDelta } from '../views/hyperview';
|
import { CollapsedDelta } from '../views/hyperview';
|
||||||
import { Delta } from '@src/core';
|
import { Delta } from '@src/core';
|
||||||
@ -103,7 +103,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewViewOne): SchemaValidationResult {
|
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewOne): SchemaValidationResult {
|
||||||
const schema = this.get(schemaId);
|
const schema = this.get(schemaId);
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
return {
|
return {
|
||||||
@ -282,7 +282,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applySchema(
|
applySchema(
|
||||||
view: HyperviewViewOne,
|
view: HyperviewOne,
|
||||||
schemaId: SchemaID,
|
schemaId: SchemaID,
|
||||||
options: SchemaApplicationOptions = {}
|
options: SchemaApplicationOptions = {}
|
||||||
): SchemaAppliedView {
|
): SchemaAppliedView {
|
||||||
@ -333,9 +333,9 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
* Resolves references to other entities according to schema specifications
|
* Resolves references to other entities according to schema specifications
|
||||||
*/
|
*/
|
||||||
applySchemaWithNesting(
|
applySchemaWithNesting(
|
||||||
view: HyperviewViewOne,
|
view: HyperviewOne,
|
||||||
schemaId: SchemaID,
|
schemaId: SchemaID,
|
||||||
hyperviewView: Hyperview,
|
hyperview: Hyperview,
|
||||||
options: SchemaApplicationOptions = {}
|
options: SchemaApplicationOptions = {}
|
||||||
): SchemaAppliedViewWithNesting {
|
): SchemaAppliedViewWithNesting {
|
||||||
const { maxDepth = 3, includeMetadata = true, strictValidation = false } = options;
|
const { maxDepth = 3, includeMetadata = true, strictValidation = false } = options;
|
||||||
@ -344,16 +344,16 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
return this.resolveNestedView(
|
return this.resolveNestedView(
|
||||||
view,
|
view,
|
||||||
schemaId,
|
schemaId,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
resolutionContext,
|
resolutionContext,
|
||||||
{ includeMetadata, strictValidation }
|
{ includeMetadata, strictValidation }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveNestedView(
|
private resolveNestedView(
|
||||||
view: HyperviewViewOne,
|
view: HyperviewOne,
|
||||||
schemaId: SchemaID,
|
schemaId: SchemaID,
|
||||||
hyperviewView: Hyperview,
|
hyperview: Hyperview,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
options: { includeMetadata: boolean; strictValidation: boolean }
|
options: { includeMetadata: boolean; strictValidation: boolean }
|
||||||
): SchemaAppliedViewWithNesting {
|
): SchemaAppliedViewWithNesting {
|
||||||
@ -401,7 +401,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
const nestedViews = this.resolveReferenceProperty(
|
const nestedViews = this.resolveReferenceProperty(
|
||||||
deltas,
|
deltas,
|
||||||
referenceSchema,
|
referenceSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context.withDepth(context.currentDepth + 1),
|
context.withDepth(context.currentDepth + 1),
|
||||||
options,
|
options,
|
||||||
view.id
|
view.id
|
||||||
@ -415,7 +415,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
const nestedViews = this.resolveReferenceProperty(
|
const nestedViews = this.resolveReferenceProperty(
|
||||||
deltas,
|
deltas,
|
||||||
referenceSchema,
|
referenceSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context.withDepth(context.currentDepth + 1),
|
context.withDepth(context.currentDepth + 1),
|
||||||
options,
|
options,
|
||||||
view.id
|
view.id
|
||||||
@ -449,7 +449,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
private resolveReferenceProperty(
|
private resolveReferenceProperty(
|
||||||
deltas: Delta[],
|
deltas: Delta[],
|
||||||
referenceSchema: ReferenceSchema,
|
referenceSchema: ReferenceSchema,
|
||||||
hyperviewView: Hyperview,
|
hyperview: Hyperview,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
options: { includeMetadata: boolean; strictValidation: boolean },
|
options: { includeMetadata: boolean; strictValidation: boolean },
|
||||||
parentEntityId: string
|
parentEntityId: string
|
||||||
@ -469,7 +469,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
delta,
|
delta,
|
||||||
parentEntityId,
|
parentEntityId,
|
||||||
referenceSchema.targetSchema,
|
referenceSchema.targetSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context,
|
context,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
@ -481,7 +481,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
for (const referenceId of referenceIds) {
|
for (const referenceId of referenceIds) {
|
||||||
try {
|
try {
|
||||||
// Get the referenced entity's hyperview
|
// Get the referenced entity's hyperview
|
||||||
const referencedViews = hyperviewView.compose([referenceId]);
|
const referencedViews = hyperview.compose([referenceId]);
|
||||||
const referencedView = referencedViews[referenceId];
|
const referencedView = referencedViews[referenceId];
|
||||||
|
|
||||||
if (referencedView) {
|
if (referencedView) {
|
||||||
@ -489,7 +489,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
const nestedView = this.resolveNestedView(
|
const nestedView = this.resolveNestedView(
|
||||||
referencedView,
|
referencedView,
|
||||||
referenceSchema.targetSchema,
|
referenceSchema.targetSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context,
|
context,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
@ -514,7 +514,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
delta: Delta,
|
delta: Delta,
|
||||||
parentEntityId: string,
|
parentEntityId: string,
|
||||||
targetSchema: SchemaID,
|
targetSchema: SchemaID,
|
||||||
hyperviewView: Hyperview,
|
hyperview: Hyperview,
|
||||||
context: ResolutionContext,
|
context: ResolutionContext,
|
||||||
options: { includeMetadata: boolean; strictValidation: boolean }
|
options: { includeMetadata: boolean; strictValidation: boolean }
|
||||||
): SchemaAppliedViewWithNesting | null {
|
): SchemaAppliedViewWithNesting | null {
|
||||||
@ -536,7 +536,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
|
|
||||||
// Count entity references vs scalars
|
// Count entity references vs scalars
|
||||||
if (typeof target === 'string') {
|
if (typeof target === 'string') {
|
||||||
const referencedViews = hyperviewView.compose([target]);
|
const referencedViews = hyperview.compose([target]);
|
||||||
if (referencedViews[target]) {
|
if (referencedViews[target]) {
|
||||||
entityReferenceCount++;
|
entityReferenceCount++;
|
||||||
} else {
|
} else {
|
||||||
@ -568,7 +568,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
if (typeof target === 'string') {
|
if (typeof target === 'string') {
|
||||||
// Try to resolve as entity reference
|
// Try to resolve as entity reference
|
||||||
try {
|
try {
|
||||||
const referencedViews = hyperviewView.compose([target]);
|
const referencedViews = hyperview.compose([target]);
|
||||||
const referencedView = referencedViews[target];
|
const referencedView = referencedViews[target];
|
||||||
|
|
||||||
if (referencedView) {
|
if (referencedView) {
|
||||||
@ -576,7 +576,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
const nestedView = this.resolveNestedView(
|
const nestedView = this.resolveNestedView(
|
||||||
referencedView,
|
referencedView,
|
||||||
targetSchema,
|
targetSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context,
|
context,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
@ -601,14 +601,14 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
|
|||||||
if (typeof target === 'string') {
|
if (typeof target === 'string') {
|
||||||
// Try to resolve as entity reference
|
// Try to resolve as entity reference
|
||||||
try {
|
try {
|
||||||
const referencedViews = hyperviewView.compose([target]);
|
const referencedViews = hyperview.compose([target]);
|
||||||
const referencedView = referencedViews[target];
|
const referencedView = referencedViews[target];
|
||||||
|
|
||||||
if (referencedView) {
|
if (referencedView) {
|
||||||
const nestedView = this.resolveNestedView(
|
const nestedView = this.resolveNestedView(
|
||||||
referencedView,
|
referencedView,
|
||||||
targetSchema,
|
targetSchema,
|
||||||
hyperviewView,
|
hyperview,
|
||||||
context,
|
context,
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { DomainEntityID, PropertyID, PropertyTypes } from "../core/types";
|
import { DomainEntityID, PropertyID, PropertyTypes } from "../core/types";
|
||||||
import { HyperviewViewOne } from "../views/hyperview";
|
import { HyperviewOne } from "../views/hyperview";
|
||||||
import { CollapsedDelta } from "../views/hyperview";
|
import { CollapsedDelta } from "../views/hyperview";
|
||||||
|
|
||||||
// Base schema types
|
// Base schema types
|
||||||
@ -52,7 +52,7 @@ export interface SchemaRegistry {
|
|||||||
register(schema: ObjectSchema): void;
|
register(schema: ObjectSchema): void;
|
||||||
get(id: SchemaID): ObjectSchema | undefined;
|
get(id: SchemaID): ObjectSchema | undefined;
|
||||||
list(): ObjectSchema[];
|
list(): ObjectSchema[];
|
||||||
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewViewOne): SchemaValidationResult;
|
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewOne): SchemaValidationResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation result types
|
// Validation result types
|
||||||
@ -105,7 +105,7 @@ export interface SchemaAppliedViewWithNesting extends SchemaAppliedView {
|
|||||||
export interface TypedCollection<T> {
|
export interface TypedCollection<T> {
|
||||||
schema: ObjectSchema;
|
schema: ObjectSchema;
|
||||||
validate(entity: T): SchemaValidationResult;
|
validate(entity: T): SchemaValidationResult;
|
||||||
apply(view: HyperviewViewOne): SchemaAppliedView;
|
apply(view: HyperviewOne): SchemaAppliedView;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Built-in schema helpers
|
// Built-in schema helpers
|
||||||
|
@ -49,7 +49,7 @@ export function valueFromDelta(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Store property deltas as references to reduce memory footprint
|
// TODO: Store property deltas as references to reduce memory footprint
|
||||||
export type HyperviewViewOne = {
|
export type HyperviewOne = {
|
||||||
id: DomainEntityID,
|
id: DomainEntityID,
|
||||||
referencedAs?: string[];
|
referencedAs?: string[];
|
||||||
propertyDeltas: {
|
propertyDeltas: {
|
||||||
@ -57,13 +57,13 @@ export type HyperviewViewOne = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CollapsedViewOne = Omit<HyperviewViewOne, 'propertyDeltas'> & {
|
export type CollapsedViewOne = Omit<HyperviewOne, 'propertyDeltas'> & {
|
||||||
propertyCollapsedDeltas: {
|
propertyCollapsedDeltas: {
|
||||||
[key: PropertyID]: CollapsedDelta[]
|
[key: PropertyID]: CollapsedDelta[]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export type HyperviewViewMany = ViewMany<HyperviewViewOne>;
|
export type HyperviewMany = ViewMany<HyperviewOne>;
|
||||||
export type CollapsedViewMany = ViewMany<CollapsedViewOne>;
|
export type CollapsedViewMany = ViewMany<CollapsedViewOne>;
|
||||||
|
|
||||||
class HyperviewEntityMap extends Map<DomainEntityID, HyperviewEntity> {};
|
class HyperviewEntityMap extends Map<DomainEntityID, HyperviewEntity> {};
|
||||||
@ -208,7 +208,7 @@ export class Hyperview {
|
|||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
decompose(view: HyperviewViewOne): Delta[] {
|
decompose(view: HyperviewOne): Delta[] {
|
||||||
const allDeltas: Delta[] = [];
|
const allDeltas: Delta[] = [];
|
||||||
const seenDeltaIds = new Set<DeltaID>();
|
const seenDeltaIds = new Set<DeltaID>();
|
||||||
|
|
||||||
@ -225,8 +225,8 @@ export class Hyperview {
|
|||||||
return allDeltas;
|
return allDeltas;
|
||||||
}
|
}
|
||||||
|
|
||||||
compose(entityIds?: DomainEntityID[], deltaFilter?: DeltaFilter): HyperviewViewMany {
|
compose(entityIds?: DomainEntityID[], deltaFilter?: DeltaFilter): HyperviewMany {
|
||||||
const view: HyperviewViewMany = {};
|
const view: HyperviewMany = {};
|
||||||
entityIds = entityIds ?? Array.from(this.domainEntities.keys());
|
entityIds = entityIds ?? Array.from(this.domainEntities.keys());
|
||||||
|
|
||||||
for (const entityId of entityIds) {
|
for (const entityId of entityIds) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Hyperview, HyperviewViewOne } from "../hyperview";
|
import { Hyperview, HyperviewOne } from "../hyperview";
|
||||||
import { Lossy } from '../view';
|
import { Lossy } from '../view';
|
||||||
import { DomainEntityID, PropertyID, ViewMany } from "../../core/types";
|
import { DomainEntityID, PropertyID, ViewMany } from "../../core/types";
|
||||||
import { valueFromDelta } from "../hyperview";
|
import { valueFromDelta } from "../hyperview";
|
||||||
@ -59,7 +59,7 @@ export class AggregationResolver extends Lossy<Accumulator, Result> {
|
|||||||
super(hyperview);
|
super(hyperview);
|
||||||
}
|
}
|
||||||
|
|
||||||
reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator {
|
reducer(acc: Accumulator, cur: HyperviewOne): Accumulator {
|
||||||
if (!acc[cur.id]) {
|
if (!acc[cur.id]) {
|
||||||
acc[cur.id] = { id: cur.id, properties: {} };
|
acc[cur.id] = { id: cur.id, properties: {} };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Hyperview, HyperviewViewOne } from "../../hyperview";
|
import { Hyperview, HyperviewOne } from "../../hyperview";
|
||||||
import { Lossy } from '../../view';
|
import { Lossy } from '../../view';
|
||||||
import { DomainEntityID, PropertyID, PropertyTypes } from "../../../core/types";
|
import { DomainEntityID, PropertyID, PropertyTypes } from "../../../core/types";
|
||||||
import { ResolverPlugin, DependencyStates } from "./plugin";
|
import { ResolverPlugin, DependencyStates } from "./plugin";
|
||||||
@ -244,7 +244,7 @@ export class CustomResolver extends Lossy<Accumulator, Result> {
|
|||||||
/**
|
/**
|
||||||
* Update the state with new deltas from the view
|
* Update the state with new deltas from the view
|
||||||
*/
|
*/
|
||||||
reducer(acc: Accumulator, {id: entityId, propertyDeltas}: HyperviewViewOne): Accumulator {
|
reducer(acc: Accumulator, {id: entityId, propertyDeltas}: HyperviewOne): Accumulator {
|
||||||
debug(`Processing deltas for entity: ${entityId}`);
|
debug(`Processing deltas for entity: ${entityId}`);
|
||||||
debug('Property deltas:', JSON.stringify(propertyDeltas));
|
debug('Property deltas:', JSON.stringify(propertyDeltas));
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { EntityProperties } from "../../core/entity";
|
import { EntityProperties } from "../../core/entity";
|
||||||
import { Hyperview, CollapsedDelta, valueFromDelta, HyperviewViewOne } from "../hyperview";
|
import { Hyperview, CollapsedDelta, valueFromDelta, HyperviewOne } from "../hyperview";
|
||||||
import { Lossy } from '../view';
|
import { Lossy } from '../view';
|
||||||
import { DomainEntityID, PropertyID, PropertyTypes, Timestamp, ViewMany } from "../../core/types";
|
import { DomainEntityID, PropertyID, PropertyTypes, Timestamp, ViewMany } from "../../core/types";
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
@ -83,7 +83,7 @@ export class TimestampResolver extends Lossy<Accumulator, Result> {
|
|||||||
super(hyperview);
|
super(hyperview);
|
||||||
}
|
}
|
||||||
|
|
||||||
reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator {
|
reducer(acc: Accumulator, cur: HyperviewOne): Accumulator {
|
||||||
if (!acc[cur.id]) {
|
if (!acc[cur.id]) {
|
||||||
acc[cur.id] = { id: cur.id, properties: {} };
|
acc[cur.id] = { id: cur.id, properties: {} };
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
import Debug from 'debug';
|
import Debug from 'debug';
|
||||||
import {Delta, DeltaFilter, DeltaID} from "../core/delta";
|
import {Delta, DeltaFilter, DeltaID} from "../core/delta";
|
||||||
import {Hyperview, HyperviewViewOne} from "./hyperview";
|
import {Hyperview, HyperviewOne} from "./hyperview";
|
||||||
import {DomainEntityID, PropertyID, PropertyTypes, ViewMany} from "../core/types";
|
import {DomainEntityID, PropertyID, PropertyTypes, ViewMany} from "../core/types";
|
||||||
const debug = Debug('rz:view');
|
const debug = Debug('rz:view');
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ export abstract class Lossy<Accumulator, Result = Accumulator> {
|
|||||||
private accumulator?: Accumulator;
|
private accumulator?: Accumulator;
|
||||||
|
|
||||||
initializer?(): Accumulator;
|
initializer?(): Accumulator;
|
||||||
abstract reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator;
|
abstract reducer(acc: Accumulator, cur: HyperviewOne): Accumulator;
|
||||||
resolver?(acc: Accumulator, entityIds: DomainEntityID[]): Result;
|
resolver?(acc: Accumulator, entityIds: DomainEntityID[]): Result;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user