UNPKG

jinaga

Version:

Data management for web and mobile applications.

212 lines (185 loc) 8.31 kB
import { JinagaClient, PurgeConditions } from "../../src"; import { createModel, Store, Order, OrderCancelled, OrderCancelledReason, OrderShipped, Product, Item } from "../orderModel"; describe("Purge conditions", () => { it("should allow a specification when no purge conditions are specified", async () => { const j = createJinagaClient(p => p); const model = createModel(); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) ); const orders = await j.query(ordersInStore, store); expect(orders).toEqual([]); }); it("should throw if the specification does not include the purge condition", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) ); const orders = j.query(ordersInStore, store); await expect(orders).rejects.toThrow(); }); it("should throw if the specification passes through the purge root", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const shipmentsInStore = model.given(Store).match(store => store.successors(OrderShipped, shipped => shipped.order.store) ); const shipments = j.query(shipmentsInStore, store); await expect(shipments).rejects.toThrow( `The match for Order.Shipped passes through types that should have purge conditions: !E (p1: Order) { u1: Order.Cancelled [ u1->order: Order = p1 ] } `); }); it("should allow a specification when the purge condition is included", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) .notExists(order => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order)) ); const orders = await j.query(ordersInStore, store); expect(orders).toEqual([]); }); it("should disallow reversible purge conditions", async () => { const model = createModel(); const jConstructor = () => createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) .notExists(orderCancelled => facts.ofType(OrderCancelledReason) .join(reason => reason.orderCancelled, orderCancelled)) )) ); expect(jConstructor).toThrow("A specified purge condition would reverse the purge of Order with Order.Cancelled.Reason."); }); it("should handle multiple purge conditions correctly", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderShipped) .join(orderShipped => orderShipped.order, order) )) ); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) .notExists(order => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order)) .notExists(order => facts.ofType(OrderShipped) .join(orderShipped => orderShipped.order, order)) ); const orders = await j.query(ordersInStore, store); expect(orders).toEqual([]); }); it("should handle negative existential conditions correctly", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) .notExists(order => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order)) ); const orders = await j.query(ordersInStore, store); expect(orders).toEqual([]); }); it("should fail on positive existential conditions", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const ordersInStore = model.given(Store).match((store, facts) => facts.ofType(Order) .join(order => order.store, store) .exists(order => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order)) ); const orders = j.query(ordersInStore, store); await expect(orders).rejects.toThrow( `The match for Order is missing purge conditions: !E (p1: Order) { u1: Order.Cancelled [ u1->order: Order = p1 ] } `); }); it("should handle complex joins and conditions correctly", async () => { const model = createModel(); const j = createJinagaClient(p => p .whenExists(model.given(Order).match((order, facts) => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order) )) ); const store = await j.fact(new Store("storeId")); const productA = await j.fact(new Product(store, "productA")); const ordersInStore = model.given(Store, Product).match((store, product, facts) => facts.ofType(Order) .join(order => order.store, store) .notExists(order => facts.ofType(OrderCancelled) .join(orderCancelled => orderCancelled.order, order)) .exists(order => facts.ofType(Item) .join(item => item.order, order) .join(item => item.product, product)) ); const orders = await j.query(ordersInStore, store, productA); expect(orders).toEqual([]); }); }); function createJinagaClient(purgeConditions: (p: PurgeConditions) => PurgeConditions) { return JinagaClient.create({ purgeConditions }); }