mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
feat: Implemented Delta generator for time advancement
This commit is contained in:
@@ -1,7 +1,22 @@
|
||||
import { AttributableObject } from "./attribute.js";
|
||||
|
||||
export class Entity extends AttributableObject {
|
||||
constructor(id?: string) {
|
||||
locationId: string | null = null;
|
||||
|
||||
constructor(id?: string, locationId?: string | null) {
|
||||
super(id);
|
||||
this.locationId = locationId ?? null;
|
||||
}
|
||||
|
||||
override serialize(): string {
|
||||
const lines: string[] = [];
|
||||
if (this.locationId) {
|
||||
lines.push(`* Location ID: ${this.locationId}`);
|
||||
}
|
||||
const selfSerialized = super.serialize();
|
||||
if (selfSerialized) {
|
||||
lines.push(selfSerialized);
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export class SQLiteRepository {
|
||||
type TEXT NOT NULL,
|
||||
world_id TEXT,
|
||||
clock_iso TEXT,
|
||||
location_id TEXT,
|
||||
FOREIGN KEY (world_id) REFERENCES objects(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
@@ -48,6 +49,13 @@ export class SQLiteRepository {
|
||||
} catch {
|
||||
// Column already exists, ignore error
|
||||
}
|
||||
|
||||
// Safely add location_id column if it does not exist in an existing database
|
||||
try {
|
||||
this.db.exec("ALTER TABLE objects ADD COLUMN location_id TEXT;");
|
||||
} catch {
|
||||
// Column already exists, ignore error
|
||||
}
|
||||
}
|
||||
|
||||
save(obj: AttributableObject, type: string, worldId?: string): void {
|
||||
@@ -57,19 +65,25 @@ export class SQLiteRepository {
|
||||
clockIso = obj.clock.get().toISOString();
|
||||
}
|
||||
|
||||
let locationId: string | null = null;
|
||||
if (obj instanceof Entity) {
|
||||
locationId = obj.locationId;
|
||||
}
|
||||
|
||||
// 1. Insert or ignore the object in the objects table
|
||||
this.db
|
||||
.prepare(
|
||||
`
|
||||
INSERT INTO objects (id, type, world_id, clock_iso)
|
||||
VALUES (?, ?, ?, ?)
|
||||
INSERT INTO objects (id, type, world_id, clock_iso, location_id)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id) DO UPDATE SET
|
||||
type = excluded.type,
|
||||
world_id = excluded.world_id,
|
||||
clock_iso = excluded.clock_iso
|
||||
clock_iso = excluded.clock_iso,
|
||||
location_id = excluded.location_id
|
||||
`,
|
||||
)
|
||||
.run(obj.id, type, worldId || null, clockIso);
|
||||
.run(obj.id, type, worldId || null, clockIso, locationId);
|
||||
|
||||
// Get current attributes from db to delete the ones that are no longer present
|
||||
const existingAttrs = this.db
|
||||
@@ -155,16 +169,16 @@ export class SQLiteRepository {
|
||||
const objRow = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT type FROM objects WHERE id = ?
|
||||
SELECT type, location_id FROM objects WHERE id = ?
|
||||
`,
|
||||
)
|
||||
.get(id) as { type: string } | undefined;
|
||||
.get(id) as { type: string; location_id: string | null } | undefined;
|
||||
|
||||
if (!objRow || objRow.type !== "entity") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const entity = new Entity(id);
|
||||
const entity = new Entity(id, objRow.location_id);
|
||||
this.reconstituteAttributes(entity);
|
||||
return entity;
|
||||
}
|
||||
@@ -190,13 +204,13 @@ export class SQLiteRepository {
|
||||
const entityRows = this.db
|
||||
.prepare(
|
||||
`
|
||||
SELECT id FROM objects WHERE type = 'entity' AND world_id = ?
|
||||
SELECT id, location_id FROM objects WHERE type = 'entity' AND world_id = ?
|
||||
`,
|
||||
)
|
||||
.all(id) as { id: string }[];
|
||||
.all(id) as { id: string; location_id: string | null }[];
|
||||
|
||||
for (const row of entityRows) {
|
||||
const entity = new Entity(row.id);
|
||||
const entity = new Entity(row.id, row.location_id);
|
||||
this.reconstituteAttributes(entity);
|
||||
worldState.addEntity(entity);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => {
|
||||
world.addAttribute("location", "Outer Rim", AttributeVisibility.PUBLIC);
|
||||
|
||||
// 2. Setup Entities and add attributes with ACL grants
|
||||
const alice = new Entity("alice");
|
||||
const alice = new Entity("alice", "location-a");
|
||||
alice.addAttribute("name", "Alice Smith", AttributeVisibility.PUBLIC);
|
||||
// Secret attribute visible only to 'bob'
|
||||
alice.addAttribute("diaries", "Private thoughts", AttributeVisibility.PRIVATE, new Set(["bob"]));
|
||||
@@ -156,6 +156,8 @@ describe("SQLiteRepository Unit Tests (Tier 1)", () => {
|
||||
expect(loadedBob).toBeDefined();
|
||||
|
||||
// 7. Assert entity attributes and access controls are preserved
|
||||
expect(loadedAlice!.locationId).toBe("location-a");
|
||||
expect(loadedBob!.locationId).toBeNull();
|
||||
expect(loadedAlice!.attributes.get("name")?.getValue()).toBe("Alice Smith");
|
||||
expect(loadedAlice!.attributes.get("name")?.visibility).toBe(AttributeVisibility.PUBLIC);
|
||||
|
||||
@@ -184,7 +186,7 @@ describe("Serializer Unit Tests (Tier 1)", () => {
|
||||
const world = new WorldState("world-1");
|
||||
world.addAttribute("gravity", "9.8", AttributeVisibility.PUBLIC);
|
||||
|
||||
const alice = new Entity("alice");
|
||||
const alice = new Entity("alice", "location-a");
|
||||
alice.addAttribute("role", "warrior", AttributeVisibility.PUBLIC);
|
||||
world.addEntity(alice);
|
||||
|
||||
@@ -196,6 +198,7 @@ describe("Serializer Unit Tests (Tier 1)", () => {
|
||||
expect(result).toContain(" * gravity: 9.8 (Visibility: PUBLIC)");
|
||||
expect(result).toContain("Entities:");
|
||||
expect(result).toContain(" - Entity [ID: alice]:");
|
||||
expect(result).toContain(" * Location ID: location-a");
|
||||
expect(result).toContain(" * role: warrior (Visibility: PUBLIC)");
|
||||
expect(result).toContain(" - Entity [ID: bob]:");
|
||||
expect(result).toContain(" * (No attributes)");
|
||||
|
||||
Reference in New Issue
Block a user