comparison src/view_loader.ts @ 95:47d3b5a5bd5e

refactor
author drewp@bigasterisk.com
date Wed, 12 Jan 2022 22:15:13 -0800
parents a5f53d397526
children 26c55d5d5202
comparison
equal deleted inserted replaced
94:a5f53d397526 95:47d3b5a5bd5e
1 // Load requested view and provide access to it 1 // Load requested view and provide access to it
2 import { Store, Parser, Term, NamedNode, DataFactory, Util } from "n3"; 2 import { Store, NamedNode, DataFactory } from "n3";
3 import { fetchAndParse } from "./fetchAndParse";
4 import { RDF, EX } from "./namespaces";
5 import { labelOrTail, uriValue } from "./rdf_value";
3 const Uri = DataFactory.namedNode; 6 const Uri = DataFactory.namedNode;
4 const RDFS = Util.prefix("http://www.w3.org/2000/01/rdf-schema#");
5 const RDF = Util.prefix("http://www.w3.org/1999/02/22-rdf-syntax-ns#");
6 const EX = Util.prefix("http://example.com/");
7 7
8 async function fetchAndParse(url: string): Promise<Store> {
9 const store = new Store();
10 const res = await fetch(url);
11 const body = await res.text();
12 const parser = new Parser({ format: "N3" });
13 await new Promise((done, rej) => {
14 parser.parse(body, (err, quad, prefixes) => {
15 if (err) {
16 throw err;
17 }
18 if (quad) {
19 store.addQuad(quad);
20 } else {
21 done(null);
22 }
23 });
24 });
25 return store;
26 }
27
28 function _singleValue(g: Store, s: Term, p: Term): Term {
29 const quads = g.getQuads(s, p, null, null);
30 const objs = new Set(quads.map((q) => q.object));
31 if (objs.size == 0) {
32 throw new Error("no value for " + s.value + " " + p.value);
33 } else if (objs.size == 1) {
34 const obj = objs.values().next().value;
35 return obj as Term;
36 } else {
37 throw new Error("too many different values: " + JSON.stringify(quads));
38 }
39 }
40
41 function stringValue(g: Store, s: Term, p: Term): string {
42 const ret = _singleValue(g, s, p);
43 if (ret.termType != "Literal") {
44 throw new Error(`ret=${ret}`);
45 }
46 return ret.value as string;
47 }
48
49 function uriValue(g: Store, s: Term, p: Term): NamedNode {
50 const ret = _singleValue(g, s, p);
51 if (ret.termType != "NamedNode") {
52 throw new Error(`ret=${ret}`);
53 }
54
55 return ret;
56 }
57
58 function labelOrTail(g: Store, uri: NamedNode): string {
59 let ret: string;
60 try {
61 ret = stringValue(g, uri, RDFS("label"));
62 } catch (e) {
63 const words = uri.value.split("/");
64 ret = words[words.length - 1];
65 }
66 if (!ret) {
67 ret = uri.value;
68 }
69 return ret;
70 }
71 function objects(g: Store, subj: NamedNode, pred: NamedNode): Term[] {
72 return g.getObjects(subj, pred, null);
73 }
74 function firstElem<E>(seq: Iterable<E>): E { 8 function firstElem<E>(seq: Iterable<E>): E {
75 for (let e of seq) { 9 for (let e of seq) {
76 return e; 10 return e;
77 } 11 }
78 throw new Error("no elems"); 12 throw new Error("no elems");
80 14
81 export class View { 15 export class View {
82 graph: Store; 16 graph: Store;
83 ready: Promise<null>; 17 ready: Promise<null>;
84 viewRoot!: NamedNode; 18 viewRoot!: NamedNode;
19
85 constructor(public url: string | "") { 20 constructor(public url: string | "") {
86 (window as any).v = this; //debug 21 (window as any).v = this; //debug
87 this.graph = new Store(); 22 this.graph = new Store();
88 this.ready = new Promise((res, rej) => { 23 this.ready = new Promise((res, rej) => {
89 if (url) { 24 if (url) {
99 this.viewRoot = firstElem( 34 this.viewRoot = firstElem(
100 this.graph.getSubjects(RDF("type"), EX("View"), null) 35 this.graph.getSubjects(RDF("type"), EX("View"), null)
101 ) as NamedNode; 36 ) as NamedNode;
102 }); 37 });
103 } 38 }
39
104 label() { 40 label() {
105 return labelOrTail(this.graph, Uri(this.url)); 41 return labelOrTail(this.graph, Uri(this.url));
106 } 42 }
43
107 // filtered+ordered list of types to show at the top level 44 // filtered+ordered list of types to show at the top level
108 typesToShow(typesPresent: NamedNode[]): NamedNode[] { 45 typesToShow(typesPresent: NamedNode[]): NamedNode[] {
109 const ret: NamedNode[] = []; 46 const ret: NamedNode[] = [];
110 for (let table of this.graph.getObjects(this.viewRoot, EX("table"), null)) { 47 for (let table of this.graph.getObjects(this.viewRoot, EX("table"), null)) {
111 const tableType = uriValue(this.graph, table, EX("showsType")); 48 const tableType = uriValue(this.graph, table, EX("showsType"));