Rename Lossless/Lossy to Hyperview/View #6

Merged
lentil merged 4 commits from chore/rename-as-hyperview into main 2025-07-09 14:37:37 -05:00
15 changed files with 81 additions and 81 deletions
Showing only changes of commit f004aba795 - Show all commits

View File

@ -1,4 +1,4 @@
import { HyperviewViewOne } from '@src/views/hyperview';
import { HyperviewOne } from '@src/views/hyperview';
import {
SchemaBuilder,
PrimitiveSchemas,
@ -158,7 +158,7 @@ describe('Schema System', () => {
schemaRegistry.register(userSchema);
// Create a valid hyperview
const validView: HyperviewViewOne = {
const validView: HyperviewOne = {
id: 'user123',
propertyDeltas: {
name: [
@ -179,7 +179,7 @@ describe('Schema System', () => {
expect(result.errors).toHaveLength(0);
// Test invalid view (missing required property)
const invalidView: HyperviewViewOne = {
const invalidView: HyperviewOne = {
id: 'user456',
propertyDeltas: {
age: [
@ -212,7 +212,7 @@ describe('Schema System', () => {
schemaRegistry.register(schema);
// Valid types
const validView: HyperviewViewOne = {
const validView: HyperviewOne = {
id: 'test1',
propertyDeltas: {
stringProp: [
@ -240,7 +240,7 @@ describe('Schema System', () => {
expect(validResult.valid).toBe(true);
// Invalid types
const invalidView: HyperviewViewOne = {
const invalidView: HyperviewOne = {
id: 'test2',
propertyDeltas: {
stringProp: [

View File

@ -1,6 +1,6 @@
import Debug from 'debug';
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 { RhizomeNode } from "@src/node";
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.
// 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(`hyperview:`, JSON.stringify(cur));

View File

@ -30,8 +30,8 @@ classDiagram
class Hyperview {
-domainEntities: Map<DomainEntityID, HyperviewEntity>
-transactions: Transactions
+view(ids: DomainEntityID[]): HyperviewViewMany
+compose(ids: DomainEntityID[]): HyperviewViewMany
+view(ids: DomainEntityID[]): HyperviewMany
+compose(ids: DomainEntityID[]): HyperviewMany
}
class QueryEngine {

View File

@ -14,7 +14,7 @@ class CustomResolver {
* @param config Plugin configuration
*/
constructor(
private readonly view: HyperviewView,
private readonly view: Hyperview,
private readonly config: ResolverConfig
);
@ -48,7 +48,7 @@ class CustomResolver {
Creates a new instance of the CustomResolver.
**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
**Example:**
@ -146,10 +146,10 @@ The resolver may throw the following errors:
```typescript
import { CustomResolver, LastWriteWinsPlugin } from './resolver';
import { HyperviewView } from '../hyperview-view';
import { Hyperview } from '../hyperview-view';
// Create a hyperview with some data
const view = new HyperviewView();
const view = new Hyperview();
// ... add data to the view ...
// Configure the resolver

View File

@ -78,11 +78,11 @@ Create tests to verify your plugin's behavior:
```typescript
describe('DiscountedPricePlugin', () => {
let view: HyperviewView;
let view: Hyperview;
let resolver: CustomResolver;
beforeEach(() => {
view = new HyperviewView();
view = new Hyperview();
resolver = new CustomResolver(view, {
basePrice: new LastWriteWinsPlugin(),
discount: new LastWriteWinsPlugin(),

View File

@ -15,7 +15,7 @@ The rhizome-node implementation demonstrates strong alignment with core spec con
2. **Hyperview Views**
- **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
3. **Lossy Views**

View File

@ -10,7 +10,7 @@ import {
SchemaApplicationOptions
} from '../schema/schema';
import { DefaultSchemaRegistry } from '../schema/schema-registry';
import { HyperviewViewOne } from '../views/hyperview';
import { HyperviewOne } from '../views/hyperview';
import { DomainEntityID } from '../core/types';
import { EntityProperties } from '../core/entity';
import { createDelta } from '@src/core';
@ -72,24 +72,24 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
// Validate an entity against the schema
validate(entity: T): SchemaValidationResult {
// Convert entity to a mock hyperview for validation
const mockHyperviewView: HyperviewViewOne = {
const mockHyperview: HyperviewOne = {
id: 'validation-mock',
referencedAs: [],
propertyDeltas: {},
};
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)
.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(view: HyperviewViewOne): SchemaAppliedView {
apply(view: HyperviewOne): SchemaAppliedView {
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 {
if (!this.rhizomeNode) throw new Error('collection not connected to rhizome');
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
if (!hyperviewView) return undefined;
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
if (!hyperview) return undefined;
return this.apply(hyperviewView);
return this.apply(hyperview);
}
// 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) {
if (!this.rhizomeNode) continue;
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
if (!hyperviewView) continue;
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
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) {
stats.validEntities++;
@ -200,16 +200,16 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
debug(`No rhizome node connected`)
return [];
}
const hyperviewView = this.rhizomeNode.hyperview.compose(this.getIds());
if (!hyperviewView) {
const hyperview = this.rhizomeNode.hyperview.compose(this.getIds());
if (!hyperview) {
debug(`No hyperview found`)
return [];
}
debug(`getValidEntities, hyperviewView: ${JSON.stringify(hyperviewView, null, 2)}`)
debug(`getValidEntities, hyperview: ${JSON.stringify(hyperview, null, 2)}`)
debug(`Validating ${this.getIds().length} entities`)
return this.getIds().filter(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)}`)
return validationResult.valid;
});
@ -221,10 +221,10 @@ export class TypedCollectionImpl<T extends Record<string, unknown>>
const invalid: Array<{ entityId: DomainEntityID; errors: string[] }> = [];
for (const entityId of this.getIds()) {
const hyperviewView = this.rhizomeNode.hyperview.compose([entityId])[entityId];
if (!hyperviewView) continue;
const hyperview = this.rhizomeNode.hyperview.compose([entityId])[entityId];
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) {
invalid.push({
entityId,

View File

@ -2,7 +2,7 @@ import jsonLogic from 'json-logic-js';
const { apply, is_logic } = jsonLogic;
import Debug from 'debug';
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 { Delta, DeltaFilter } from '../core/delta';
@ -31,7 +31,7 @@ export interface QueryOptions {
}
export interface QueryResult {
entities: HyperviewViewMany;
entities: HyperviewMany;
totalFound: number;
limited: boolean;
}
@ -101,7 +101,7 @@ export class QueryEngine {
debug(`Composed ${Object.keys(allViews).length} hyperviews`);
// 3. Apply JSON Logic filter if provided
let filteredViews: HyperviewViewMany = allViews;
let filteredViews: HyperviewMany = allViews;
if (filter) {
filteredViews = this.applyJsonLogicFilter(allViews, filter, schemaId);
@ -132,7 +132,7 @@ export class QueryEngine {
/**
* 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}`);
const views = this.hyperview.compose([entityId]);
@ -199,24 +199,24 @@ export class QueryEngine {
* This requires converting each hyperview to a queryable object
*/
private applyJsonLogicFilter(
views: HyperviewViewMany,
views: HyperviewMany,
filter: JsonLogic,
schemaId: SchemaID
): HyperviewViewMany {
): HyperviewMany {
const schema = this.schemaRegistry.get(schemaId);
if (!schema) {
debug(`Cannot filter without schema ${schemaId}`);
return views;
}
const filteredViews: HyperviewViewMany = {};
const filteredViews: HyperviewMany = {};
let hasFilterErrors = false;
const filterErrors: string[] = [];
for (const [entityId, view] of Object.entries(views)) {
try {
// Convert hyperview to queryable object using schema
const queryableObject = this.hyperviewViewToQueryableObject(view, schema);
const queryableObject = this.hyperviewToQueryableObject(view, schema);
// Apply JSON Logic filter
const matches = apply(filter, queryableObject);
@ -249,7 +249,7 @@ export class QueryEngine {
* Convert a hyperview to a queryable object based on schema
* 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> = {
id: view.id,
_referencedAs: view.referencedAs
@ -315,7 +315,7 @@ export class QueryEngine {
/**
* 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);
if (!schema) return false;

View File

@ -14,7 +14,7 @@ import {
SchemaApplicationOptions,
ResolutionContext
} from '../schema/schema';
import { Hyperview, HyperviewViewOne } from '../views/hyperview';
import { Hyperview, HyperviewOne } from '../views/hyperview';
import { DomainEntityID, PropertyID, PropertyTypes } from '../core/types';
import { CollapsedDelta } from '../views/hyperview';
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);
if (!schema) {
return {
@ -282,7 +282,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
}
applySchema(
view: HyperviewViewOne,
view: HyperviewOne,
schemaId: SchemaID,
options: SchemaApplicationOptions = {}
): SchemaAppliedView {
@ -333,9 +333,9 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
* Resolves references to other entities according to schema specifications
*/
applySchemaWithNesting(
view: HyperviewViewOne,
view: HyperviewOne,
schemaId: SchemaID,
hyperviewView: Hyperview,
hyperview: Hyperview,
options: SchemaApplicationOptions = {}
): SchemaAppliedViewWithNesting {
const { maxDepth = 3, includeMetadata = true, strictValidation = false } = options;
@ -344,16 +344,16 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
return this.resolveNestedView(
view,
schemaId,
hyperviewView,
hyperview,
resolutionContext,
{ includeMetadata, strictValidation }
);
}
private resolveNestedView(
view: HyperviewViewOne,
view: HyperviewOne,
schemaId: SchemaID,
hyperviewView: Hyperview,
hyperview: Hyperview,
context: ResolutionContext,
options: { includeMetadata: boolean; strictValidation: boolean }
): SchemaAppliedViewWithNesting {
@ -401,7 +401,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
const nestedViews = this.resolveReferenceProperty(
deltas,
referenceSchema,
hyperviewView,
hyperview,
context.withDepth(context.currentDepth + 1),
options,
view.id
@ -415,7 +415,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
const nestedViews = this.resolveReferenceProperty(
deltas,
referenceSchema,
hyperviewView,
hyperview,
context.withDepth(context.currentDepth + 1),
options,
view.id
@ -449,7 +449,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
private resolveReferenceProperty(
deltas: Delta[],
referenceSchema: ReferenceSchema,
hyperviewView: Hyperview,
hyperview: Hyperview,
context: ResolutionContext,
options: { includeMetadata: boolean; strictValidation: boolean },
parentEntityId: string
@ -469,7 +469,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
delta,
parentEntityId,
referenceSchema.targetSchema,
hyperviewView,
hyperview,
context,
options
);
@ -481,7 +481,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
for (const referenceId of referenceIds) {
try {
// Get the referenced entity's hyperview
const referencedViews = hyperviewView.compose([referenceId]);
const referencedViews = hyperview.compose([referenceId]);
const referencedView = referencedViews[referenceId];
if (referencedView) {
@ -489,7 +489,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
const nestedView = this.resolveNestedView(
referencedView,
referenceSchema.targetSchema,
hyperviewView,
hyperview,
context,
options
);
@ -514,7 +514,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
delta: Delta,
parentEntityId: string,
targetSchema: SchemaID,
hyperviewView: Hyperview,
hyperview: Hyperview,
context: ResolutionContext,
options: { includeMetadata: boolean; strictValidation: boolean }
): SchemaAppliedViewWithNesting | null {
@ -536,7 +536,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
// Count entity references vs scalars
if (typeof target === 'string') {
const referencedViews = hyperviewView.compose([target]);
const referencedViews = hyperview.compose([target]);
if (referencedViews[target]) {
entityReferenceCount++;
} else {
@ -568,7 +568,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
if (typeof target === 'string') {
// Try to resolve as entity reference
try {
const referencedViews = hyperviewView.compose([target]);
const referencedViews = hyperview.compose([target]);
const referencedView = referencedViews[target];
if (referencedView) {
@ -576,7 +576,7 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
const nestedView = this.resolveNestedView(
referencedView,
targetSchema,
hyperviewView,
hyperview,
context,
options
);
@ -601,14 +601,14 @@ export class DefaultSchemaRegistry implements SchemaRegistry {
if (typeof target === 'string') {
// Try to resolve as entity reference
try {
const referencedViews = hyperviewView.compose([target]);
const referencedViews = hyperview.compose([target]);
const referencedView = referencedViews[target];
if (referencedView) {
const nestedView = this.resolveNestedView(
referencedView,
targetSchema,
hyperviewView,
hyperview,
context,
options
);

View File

@ -1,5 +1,5 @@
import { DomainEntityID, PropertyID, PropertyTypes } from "../core/types";
import { HyperviewViewOne } from "../views/hyperview";
import { HyperviewOne } from "../views/hyperview";
import { CollapsedDelta } from "../views/hyperview";
// Base schema types
@ -52,7 +52,7 @@ export interface SchemaRegistry {
register(schema: ObjectSchema): void;
get(id: SchemaID): ObjectSchema | undefined;
list(): ObjectSchema[];
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewViewOne): SchemaValidationResult;
validate(entityId: DomainEntityID, schemaId: SchemaID, view: HyperviewOne): SchemaValidationResult;
}
// Validation result types
@ -105,7 +105,7 @@ export interface SchemaAppliedViewWithNesting extends SchemaAppliedView {
export interface TypedCollection<T> {
schema: ObjectSchema;
validate(entity: T): SchemaValidationResult;
apply(view: HyperviewViewOne): SchemaAppliedView;
apply(view: HyperviewOne): SchemaAppliedView;
}
// Built-in schema helpers

View File

@ -49,7 +49,7 @@ export function valueFromDelta(
}
// TODO: Store property deltas as references to reduce memory footprint
export type HyperviewViewOne = {
export type HyperviewOne = {
id: DomainEntityID,
referencedAs?: string[];
propertyDeltas: {
@ -57,13 +57,13 @@ export type HyperviewViewOne = {
}
}
export type CollapsedViewOne = Omit<HyperviewViewOne, 'propertyDeltas'> & {
export type CollapsedViewOne = Omit<HyperviewOne, 'propertyDeltas'> & {
propertyCollapsedDeltas: {
[key: PropertyID]: CollapsedDelta[]
}
};
export type HyperviewViewMany = ViewMany<HyperviewViewOne>;
export type HyperviewMany = ViewMany<HyperviewOne>;
export type CollapsedViewMany = ViewMany<CollapsedViewOne>;
class HyperviewEntityMap extends Map<DomainEntityID, HyperviewEntity> {};
@ -208,7 +208,7 @@ export class Hyperview {
return transactionId;
}
decompose(view: HyperviewViewOne): Delta[] {
decompose(view: HyperviewOne): Delta[] {
const allDeltas: Delta[] = [];
const seenDeltaIds = new Set<DeltaID>();
@ -225,8 +225,8 @@ export class Hyperview {
return allDeltas;
}
compose(entityIds?: DomainEntityID[], deltaFilter?: DeltaFilter): HyperviewViewMany {
const view: HyperviewViewMany = {};
compose(entityIds?: DomainEntityID[], deltaFilter?: DeltaFilter): HyperviewMany {
const view: HyperviewMany = {};
entityIds = entityIds ?? Array.from(this.domainEntities.keys());
for (const entityId of entityIds) {

View File

@ -1,4 +1,4 @@
import { Hyperview, HyperviewViewOne } from "../hyperview";
import { Hyperview, HyperviewOne } from "../hyperview";
import { Lossy } from '../view';
import { DomainEntityID, PropertyID, ViewMany } from "../../core/types";
import { valueFromDelta } from "../hyperview";
@ -59,7 +59,7 @@ export class AggregationResolver extends Lossy<Accumulator, Result> {
super(hyperview);
}
reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator {
reducer(acc: Accumulator, cur: HyperviewOne): Accumulator {
if (!acc[cur.id]) {
acc[cur.id] = { id: cur.id, properties: {} };
}

View File

@ -1,4 +1,4 @@
import { Hyperview, HyperviewViewOne } from "../../hyperview";
import { Hyperview, HyperviewOne } from "../../hyperview";
import { Lossy } from '../../view';
import { DomainEntityID, PropertyID, PropertyTypes } from "../../../core/types";
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
*/
reducer(acc: Accumulator, {id: entityId, propertyDeltas}: HyperviewViewOne): Accumulator {
reducer(acc: Accumulator, {id: entityId, propertyDeltas}: HyperviewOne): Accumulator {
debug(`Processing deltas for entity: ${entityId}`);
debug('Property deltas:', JSON.stringify(propertyDeltas));

View File

@ -1,5 +1,5 @@
import { EntityProperties } from "../../core/entity";
import { Hyperview, CollapsedDelta, valueFromDelta, HyperviewViewOne } from "../hyperview";
import { Hyperview, CollapsedDelta, valueFromDelta, HyperviewOne } from "../hyperview";
import { Lossy } from '../view';
import { DomainEntityID, PropertyID, PropertyTypes, Timestamp, ViewMany } from "../../core/types";
import Debug from 'debug';
@ -83,7 +83,7 @@ export class TimestampResolver extends Lossy<Accumulator, Result> {
super(hyperview);
}
reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator {
reducer(acc: Accumulator, cur: HyperviewOne): Accumulator {
if (!acc[cur.id]) {
acc[cur.id] = { id: cur.id, properties: {} };
}

View File

@ -4,7 +4,7 @@
import Debug from 'debug';
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";
const debug = Debug('rz:view');
@ -23,7 +23,7 @@ export abstract class Lossy<Accumulator, Result = Accumulator> {
private accumulator?: Accumulator;
initializer?(): Accumulator;
abstract reducer(acc: Accumulator, cur: HyperviewViewOne): Accumulator;
abstract reducer(acc: Accumulator, cur: HyperviewOne): Accumulator;
resolver?(acc: Accumulator, entityIds: DomainEntityID[]): Result;
constructor(