fix: lire un document par la requête ancrée, readUnion ayant quitté le polyfill
Le contrat polyfill-surface passe de 1.0.0-dev.6 à 1.0.0-dev.15, épinglé désormais sur le tag polyfill/v1.0.0-dev.15. readUnion et UnionSubject ont été retirés en dev.8 : l'application e2e lit un document par un SELECT ancré regroupé par sujet, en ignorant les registres urn:ng-eventually: que la requête renvoie désormais. La déclaration usage_ng-helpers retire ce que l'engagement a absorbé (exemple de forme, initNg, orm_start_graph corrigé en dev.7, comportement d'un document illisible, lecture d'un document public par sa seule référence, pin par tag) et garde les demandes encore ouvertes. contract_indexing-layer 4.0.1 (patch) : la lecture d'un index ne cite plus readUnion.
This commit is contained in:
+14
-5
@@ -14,14 +14,23 @@
|
||||
* ends up typed as a reference.
|
||||
*/
|
||||
|
||||
import type { UnionSubject } from "@ng-eventually/polyfill";
|
||||
/**
|
||||
* One subject of a document and everything the document says about it, keyed by
|
||||
* predicate. Declared here because nothing publishes it: the polyfill withdrew its own
|
||||
* (`UnionSubject`, with `readUnion`) in `1.0.0-dev.8`, and grouping the rows of an
|
||||
* anchored query is the application's business -- see `readDocument` in the page.
|
||||
*/
|
||||
export interface DocumentSubject {
|
||||
readonly subject: string;
|
||||
readonly props: Readonly<Record<string, readonly string[]>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* One entry, as THIS APPLICATION decodes one out of the index document.
|
||||
*
|
||||
* It is declared here and not imported, because `@ng-helpers/indexing` publishes no
|
||||
* such type and no call that produces one: an index is an ordinary document, so its
|
||||
* contents are whatever `readUnion` hands back, read with the two published IRIs.
|
||||
* contents are whatever an anchored query hands back, read with the two published IRIs.
|
||||
* A subject carrying several values shows up as several rows — the document's own
|
||||
* truth, and the application's business to make something of.
|
||||
*/
|
||||
@@ -120,13 +129,13 @@ export interface IndexingBridge {
|
||||
rebuildHandle(): Promise<void>;
|
||||
/**
|
||||
* The index's entries, ordered by value — decoded BY THIS APPLICATION, out of an
|
||||
* ordinary `readUnion` of the index document, with nothing from the library but the
|
||||
* ordinary anchored read of the index document, with nothing from the library but the
|
||||
* two IRIs it publishes. That the suite can do this at all is the claim under test.
|
||||
*/
|
||||
read(index: string): Promise<IndexRow[]>;
|
||||
|
||||
/** What a document literally holds, straight off `readUnion` — the write-form probe. */
|
||||
readRaw(doc: string): Promise<UnionSubject[]>;
|
||||
/** What a document literally holds, grouped by subject — the write-form probe. */
|
||||
readRaw(doc: string): Promise<DocumentSubject[]>;
|
||||
/**
|
||||
* Run a SPARQL SELECT anchored on a document, through `docs.sparqlQuery`.
|
||||
*
|
||||
|
||||
+51
-13
@@ -15,9 +15,9 @@
|
||||
* Nothing here makes an entry of a deposit, and nothing here can ask for one: that is
|
||||
* the business of the layer below, and this page is where that shows or does not.
|
||||
* Everything else here is the polyfill (`configure`, `ensureIdentity`, `init`, `initNg`,
|
||||
* `ng`, `readUnion`, `docs`, `useShapeQuery`) -- including reading the index, which is an
|
||||
* ordinary `readUnion` of an ordinary document. If something here is awkward, it is
|
||||
* awkward for every consumer, which is the second reason to write it this way.
|
||||
* `ng`, `docs`, `useShapeQuery`) -- including reading the index, which is an ordinary
|
||||
* anchored `docs.sparqlQuery` of an ordinary document. If something here is awkward, it
|
||||
* is awkward for every consumer, which is the second reason to write it this way.
|
||||
*
|
||||
* This page WIRES THE ORM, because one thing here has no other door: the store enumeration it
|
||||
* used to discover a leaked document left the engagement, and what replaces it is a shape
|
||||
@@ -43,13 +43,11 @@ import {
|
||||
init,
|
||||
initNg,
|
||||
ng,
|
||||
readUnion,
|
||||
useShapeQuery,
|
||||
type Scope,
|
||||
type ShapeObservable,
|
||||
type ShapeQuery,
|
||||
type ShapeType,
|
||||
type UnionSubject,
|
||||
} from "@ng-eventually/polyfill";
|
||||
import { ng as realNg, init as realInit } from "@ng-org/web";
|
||||
import { RdfOrmSubscription, initNg as ormInitNg } from "@ng-org/orm";
|
||||
@@ -60,7 +58,13 @@ import { ENTRY_VALUE, INDEX_FIELD, indexing, type Indexing } from "../src/index"
|
||||
import { indexingOn } from "../src/indexing";
|
||||
import type { NextGraphPort } from "../src/port";
|
||||
import { polyfillPort } from "../src/polyfill-adapter";
|
||||
import type { BrokenInboxOutcome, IndexRow, IndexingBridge, SelectOutcome } from "./bridge";
|
||||
import type {
|
||||
BrokenInboxOutcome,
|
||||
DocumentSubject,
|
||||
IndexRow,
|
||||
IndexingBridge,
|
||||
SelectOutcome,
|
||||
} from "./bridge";
|
||||
|
||||
// bootstrap: the one polyfill-era call, then the SDK-shaped ones
|
||||
//
|
||||
@@ -82,7 +86,7 @@ configure({
|
||||
useShape: () => {
|
||||
throw new Error(
|
||||
"[e2e] useShape was never wired: this page has no framework adapter to give it, " +
|
||||
"and it reads through readUnion and useShapeQuery instead",
|
||||
"and it reads through docs.sparqlQuery and useShapeQuery instead",
|
||||
);
|
||||
},
|
||||
ormSubscription: RdfOrmSubscription.getOrCreate,
|
||||
@@ -129,8 +133,8 @@ async function boot(): Promise<void> {
|
||||
// through it, and this package's own `initNg` is the one to CALL -- not the SDK's,
|
||||
// which was handed to `configure` and is reached from there. The `ng` it is given is
|
||||
// this package's too, the one the surface says to call instead of the one `configure`
|
||||
// was passed. Measured: the argument makes no difference either way, because the call
|
||||
// substitutes its own -- see `usage_ng-helpers`'s `## Frictions`.
|
||||
// was passed. The engagement states the argument is discarded either way: the call
|
||||
// substitutes that same published `ng`.
|
||||
initNg(ng, session);
|
||||
// The session id, and nothing else — this application never names a port, and never
|
||||
// awaits anything here: a handle reaches nothing. A reference this application hands
|
||||
@@ -325,6 +329,40 @@ function rowsOf(result: unknown): Array<Record<string, string>> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Everything a document holds, grouped by subject -- what an application writes in place
|
||||
* of the `readUnion` the polyfill withdrew in `1.0.0-dev.8`.
|
||||
*
|
||||
* One anchored `SELECT ?s ?p ?o`: the anchor makes the document the query's default graph,
|
||||
* so the body names no graph and reads that document and nothing else. A document this
|
||||
* identity cannot read REJECTS, and the rejection is left to reach the caller -- an
|
||||
* unreadable document is "unknown", never "empty". The polyfill's own registers live
|
||||
* under `urn:ng-eventually:` in the same graph and come back with the rest; they are the
|
||||
* polyfill's, not the document's, so they are dropped here.
|
||||
*/
|
||||
async function readDocument(doc: string): Promise<DocumentSubject[]> {
|
||||
const session = await sessionReady;
|
||||
const result = await docs.sparqlQuery(
|
||||
session.session_id,
|
||||
"SELECT ?s ?p ?o WHERE { ?s ?p ?o }",
|
||||
undefined,
|
||||
doc,
|
||||
);
|
||||
const bySubject = new Map<string, Record<string, string[]>>();
|
||||
for (const row of rowsOf(result)) {
|
||||
const { s, p, o } = row;
|
||||
if (s === undefined || p === undefined || o === undefined) continue;
|
||||
if (s.startsWith(RESERVED_PREFIX)) continue;
|
||||
const props = bySubject.get(s) ?? {};
|
||||
(props[p] ??= []).push(o);
|
||||
bySubject.set(s, props);
|
||||
}
|
||||
return [...bySubject].map(([subject, props]) => ({ subject, props }));
|
||||
}
|
||||
|
||||
/** The polyfill's reserved prefix: what it writes into a document under it is its own. */
|
||||
const RESERVED_PREFIX = "urn:ng-eventually:";
|
||||
|
||||
// the acts
|
||||
|
||||
const bridge: IndexingBridge = {
|
||||
@@ -372,12 +410,12 @@ const bridge: IndexingBridge = {
|
||||
/**
|
||||
* The index read BY THIS APPLICATION, with nothing the package publishes but
|
||||
* `ENTRY_VALUE` — the claim "an index is an ordinary document" performed rather than
|
||||
* repeated. `readUnion([index])` is the same call this page makes on any other
|
||||
* repeated. `readDocument(index)` is the same read this page makes of any other
|
||||
* document; the index's own subject is the one that is not an entry, told apart by
|
||||
* being the document itself.
|
||||
*/
|
||||
async read(index: string): Promise<IndexRow[]> {
|
||||
const subjects = await readUnion([index]);
|
||||
const subjects = await readDocument(index);
|
||||
const rows: IndexRow[] = [];
|
||||
for (const subject of subjects) {
|
||||
if (subject.subject === index) continue;
|
||||
@@ -394,8 +432,8 @@ const bridge: IndexingBridge = {
|
||||
return rows;
|
||||
},
|
||||
|
||||
async readRaw(doc: string): Promise<UnionSubject[]> {
|
||||
return readUnion([doc]);
|
||||
async readRaw(doc: string): Promise<DocumentSubject[]> {
|
||||
return readDocument(doc);
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+8
-8
@@ -221,7 +221,7 @@ const { check, journey, finish } = declareSuite({
|
||||
{
|
||||
name: "The index answers an ordinary SPARQL query",
|
||||
checks: [
|
||||
"readUnion returns both entries and the index's own declaration",
|
||||
"reading the document returns both entries and the index's own declaration",
|
||||
"a SELECT for the entry predicate returns both entries, with their values",
|
||||
"a SELECT of the index's own subject returns the field it declares",
|
||||
"a stranger's SELECT returns the same entries",
|
||||
@@ -278,7 +278,7 @@ function step<T>(what: string, ms: number, task: () => Promise<T>): Promise<T> {
|
||||
* to suit it.
|
||||
*
|
||||
* ── It reads the way an application reads ───────────────────────────────────
|
||||
* `read` is an ordinary `readUnion` of an ordinary document, or an anchored SELECT — the
|
||||
* `read` is an ordinary anchored read of an ordinary document, or a narrower SELECT — the
|
||||
* only two ways anyone has of reading an index, the harness included. Nothing here reaches
|
||||
* for a way to hurry the layer below, because a consumer has none either.
|
||||
*
|
||||
@@ -455,9 +455,9 @@ async function main(): Promise<void> {
|
||||
const declared = self?.props[INDEX_FIELD] ?? [];
|
||||
check(
|
||||
"the index document declares the field it indexes by",
|
||||
declared.length === 1 && declared[0] === PUBLISHED_AT && self?.graph === index,
|
||||
declared.length === 1 && declared[0] === PUBLISHED_AT,
|
||||
`subjects=${raw.length} self=${self === undefined ? "(not found)" : "found"} ` +
|
||||
`graph=${self?.graph} declared=${JSON.stringify(declared)}`,
|
||||
`declared=${JSON.stringify(declared)}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -762,8 +762,8 @@ async function main(): Promise<void> {
|
||||
// which is the state the question is about — one entry cannot tell a query that
|
||||
// returns everything from one that returns the first thing it finds.
|
||||
//
|
||||
// WHAT IS BEING ASKED. This package documents one way of reading an index
|
||||
// (`readUnion`) and issues no query of its own, so "an index is an ordinary document
|
||||
// WHAT IS BEING ASKED. This package documents how to read an index and issues no
|
||||
// query of its own, so "an index is an ordinary document
|
||||
// anyone queries normally" has never been anything but plausible. These four checks
|
||||
// are a measurement of that sentence, not a feature: an empty answer is a RESULT and
|
||||
// is reported as one, and a rejection is reported apart from it, because "the query
|
||||
@@ -789,7 +789,7 @@ async function main(): Promise<void> {
|
||||
PUBLISHED_AT,
|
||||
);
|
||||
check(
|
||||
"readUnion returns both entries and the index's own declaration",
|
||||
"reading the document returns both entries and the index's own declaration",
|
||||
held.size === 2 && declares,
|
||||
`entries=${JSON.stringify([...held.keys()])} declares=${declares}`,
|
||||
);
|
||||
@@ -826,7 +826,7 @@ async function main(): Promise<void> {
|
||||
);
|
||||
|
||||
// The reader who matters: an index exists to be read by people who own neither it
|
||||
// nor anything in it. `readUnion` already answers him (the journey above); whether
|
||||
// nor anything in it. Reading the whole document already answers him (the journey above); whether
|
||||
// a query does is a separate question, and it is the one an application asks.
|
||||
const theirs = await step("Bob querying the index he does not own", BRIDGE_MS, () =>
|
||||
bob!.frame.evaluate(
|
||||
|
||||
Reference in New Issue
Block a user