diff src/graph_view.ts @ 15:7ca4ff2088c3

managed to use a newer ts or something, so this includes a bunch of type fixes too
author drewp@bigasterisk.com
date Sun, 08 Dec 2019 23:32:12 -0800
parents 26d3e4860adc
children 9ec3cbc8791a
line wrap: on
line diff
--- a/src/graph_view.ts	Fri Dec 06 20:34:01 2019 -0800
+++ b/src/graph_view.ts	Sun Dec 08 23:32:12 2019 -0800
@@ -1,208 +1,238 @@
 // from /my/site/homepage/www/rdf/browse/graphView.js
 
-/// <reference types="./n3.d.ts">
+//reference types="./n3.d.ts">
 
-import { html } from 'lit-html';
+import { html, TemplateResult } from 'lit-html';
 import { SuffixLabels } from './suffixLabels';
 
-import { NamedNode, N3Store } from 'n3';
-
-import ns from 'n3/src/IRIs';
-const {rdf} = ns;
+import { Quad, Term, NamedNode, N3Store } from '../node_modules/@types/n3/index';
+import { DataFactory, Util } from 'n3';
+const { namedNode } = DataFactory;
+// import ns from 'n3/src/IRIs';
+// const { rdf } = ns;
 
-const groupByRdfType = (graph: N3Store) => {
-  const rdfType = new NamedNode(rdf.type);
-  const byType: Map<NamedNode, Set<NamedNode>> = new Map(); // type : subjs
-  const untyped = new Set(); // subjs
-  graph.getQuads({}, (q) => {
-    let subjType = null;
-    graph.getQuads({
-      subject: q.subject,
-      predicate: rdfType
-    },
-      (q2) => { subjType = q2.object; });
-    if (subjType) {
-      subjType = subjType.toString();
+type TypeToSubjs = Map<NamedNode, Set<NamedNode>>;
+function groupByRdfType(graph: N3Store): { byType: TypeToSubjs, untyped: Set<NamedNode> } {
+  const rdfType = namedNode('rdf:type');
+  const byType: TypeToSubjs = new Map(); // type : subjs
+  const untyped: Set<NamedNode> = new Set(); // subjs
+  graph.forEach((q) => {
+    let subjType: NamedNode | null = null;
+
+    graph.forObjects((o: Quad) => {
+      if (Util.isNamedNode(o.object)) {
+        subjType = o.object as NamedNode;
+      }
+    }, q.subject, rdfType, null);
+
+    if (subjType !== null) {
       if (!byType.has(subjType)) {
         byType.set(subjType, new Set());
       }
-      byType.get(subjType).add(q.subject.toString());
+      (byType.get(subjType) as Set<NamedNode>).add(q.subject as NamedNode);
     } else {
-      untyped.add(q.subject.toString());
+      untyped.add(q.subject as NamedNode);
     }
-
-  });
+  }, null, null, null, null);
   return { byType: byType, untyped: untyped };
-};
+}
 
-const graphView = (graph: N3Store) => {
-  const labels = new SuffixLabels();
-  graph.getQuads({}, (q) => {
-    if (q.subject.interfaceName == "NamedNode") { labels.planDisplayForNode(q.subject); }
-    if (q.predicate.interfaceName == "NamedNode") { labels.planDisplayForNode(q.predicate); }
-    if (q.object.interfaceName == "NamedNode") { labels.planDisplayForNode(q.object); }
-    if (q.object.interfaceName == "Literal" && q.object.datatype) { labels.planDisplayForNode(new NamedNode(q.object.datatype)); }
-  });
 
-  const rdfNode = (n) => {
-    if (n.interfaceName == "Literal") {
+class NodeDisplay {
+  labels: SuffixLabels;
+  constructor(labels: SuffixLabels) {
+    this.labels = labels;
+  }
+  getHtml(n: Term): TemplateResult {
+    if (n.termType == "Literal") {
       let dtPart: any = "";
       if (n.datatype) {
         dtPart = html`
-        ^^<span class="literalType">
-          ${rdfNode(new NamedNode(n.datatype))}
-        </span>`;
+            ^^<span class="literalType">
+              ${this.getHtml(n.datatype)}
+            </span>`;
       }
-      return html`<span class="literal">${n.nominalValue}${dtPart}</span>`;
-    }
-    if (n.interfaceName == "NamedNode") {
-      let dn = labels.getLabelForNode(n);
-      if (dn.match(/XMLSchema#.*/)) { dn = dn.replace('XMLSchema#', 'xsd:'); }
-      if (dn.match(/rdf-schema#.*/)) { dn = dn.replace('rdf-schema#', 'rdfs:'); }
-      return html`<a class="graphUri" href="${n.toString()}">${dn}</a>`;
+      return html`<span class="literal">${n.value}${dtPart}</span>`;
     }
 
-    return html`[${n.interfaceName} ${n.toNT()}]`;
+    if (n.termType  == "NamedNode") {
+      let dn: string | undefined = this.labels.getLabelForNode(n.value);
+      if (dn === undefined) {
+        throw new Error(`dn=${dn}`);
+      }
+      if (dn!.match(/XMLSchema#.*/)) {
+        dn = dn!.replace('XMLSchema#', 'xsd:');
+      }
+      if (dn!.match(/rdf-schema#.*/)) {
+        dn = dn!.replace('rdf-schema#', 'rdfs:');
+      }
+      return html`<a class="graphUri" href="${n.value}">${dn}</a>`;
+    }
+
+    return html`[${n.termType} ${n.value}]`;
+  }
+}
+
+export class GraphView {
+  url: string;
+  graph: N3Store;
+  nodeDisplay: NodeDisplay;
+  constructor(url: string, graph: N3Store) {
+    this.url = url;
+    this.graph = graph;
+
+    const labels = new SuffixLabels();
+    this._addLabelsForAllTerms(labels);
+    this.nodeDisplay = new NodeDisplay(labels);
   }
 
-  const objBlock = (obj) => {
-    return html`
-        <div class="object">
-          ${rdfNode(obj)} <!-- indicate what source or graph said this stmt -->
-        </div>
-    `;
-  };
+  _addLabelsForAllTerms(labels: SuffixLabels) {
+    return this.graph.forEach((q: Quad) => {
+      if (q.subject.termType === "NamedNode") { labels.planDisplayForNode(q.subject); }
+      if (q.predicate.termType === "NamedNode") { labels.planDisplayForNode(q.predicate); }
+      if (q.object.termType === "NamedNode") { labels.planDisplayForNode(q.object); }
+      if (q.object.termType === "Literal" && q.object.datatype) {
+        labels.planDisplayForNode(q.object.datatype);
+      }
+    }, null, null, null, null);
+  }
 
-  /// bunch of table rows
-  const predBlock = (subj, pred) => {
-    const objsSet = new Set();
-    graph.getQuads({ subject: subj, predicate: pred }, (q) => {
-
-      if (q.object.length) {
-        console.log(q.object)
-      }
-      objsSet.add(q.object);
-    });
-    const objs = Array.from(objsSet.values());
-    objs.sort();
+  _subjBlock(subj: NamedNode) {
+    const predsSet: Set<NamedNode> = new Set();
+    this.graph.forEach((q: Quad) => {
+      predsSet.add(q.predicate as NamedNode);
+    }, subj, null, null, null);
+    const preds = Array.from(predsSet.values());
+    preds.sort();
     return html`
-      <div class="predicate">${rdfNode(pred)}
+      <div class="subject">${this.nodeDisplay.getHtml(subj)}
+        <!-- todo: special section for uri/type-and-icon/label/comment -->
         <div>
-          ${objs.map(objBlock)}
+          ${preds.map((p) => { return this._predBlock(subj, p); })}
         </div>
       </div>
     `;
-  };
+  }
 
-  const { byType, untyped } = groupByRdfType(graph);
-  const typedSubjs = Array.from(byType.keys());
-  typedSubjs.sort();
-
-  const untypedSubjs = Array.from(untyped.values());
-  untypedSubjs.sort();
+  _objBlock(obj: Term) {
+    return html`
+      <div class="object">
+        ${this.nodeDisplay.getHtml(obj)} <!-- indicate what source or graph said this stmt -->
+      </div>
+    `;
+  }
 
-  const subjBlock = (subj) => {
-    const subjNode = new NamedNode(subj);
-    const predsSet = new Set();
-    graph.getQuads({ subject: subjNode }, (q) => {
-      predsSet.add(q.predicate);
-    });
-    const preds = Array.from(predsSet.values());
-    preds.sort();
+  _predBlock(subj: NamedNode, pred: NamedNode) {
+    const objsSet = new Set();
+    this.graph.forEach((q: Quad) => {
+      objsSet.add(q.object);
+    }, subj, pred, null, null);
+    const objs = Array.from(objsSet.values());
+    objs.sort();
     return html`
-      <div class="subject">${rdfNode(subjNode)}
-        <!-- todo: special section for uri/type-and-icon/label/comment -->
+      <div class="predicate">${this.nodeDisplay.getHtml(pred)}
         <div>
-          ${preds.map((p) => { return predBlock(subjNode, p); })}
+          ${objs.map(this._objBlock.bind(this))}
         </div>
       </div>
     `;
-  };
-  const byTypeBlock = (typeUri) => {
-    const subjs = Array.from(byType.get(typeUri));
-    subjs.sort();
+  }
+
 
-    const graphCells = new Map(); // [subj, pred] : objs
-    const preds = new Set();
+  //   const byTypeBlock = (typeUri) => {
+  //     const subjs = Array.from(byType.get(typeUri));
+  //     subjs.sort();
+
+  //     const graphCells = new Map(); // [subj, pred] : objs
+  //     const preds = new Set();
 
-    subjs.forEach((subj) => {
-      graph.getQuads({ subject: new NamedNode(subj) }, (q) => {
-        preds.add(q.predicate.toString());
-        const cellKey = subj + '|||' + q.predicate.toString();
-        if (!graphCells.has(cellKey)) {
-          graphCells.set(cellKey, new Set());
-        }
-        graphCells.get(cellKey).add(q.object);
-      });
-    });
-    const predsList = Array.from(preds);
-    predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1);
-    // also pull out label, which should be used on 1st column
-    predsList.sort();
+  //     subjs.forEach((subj) => {
+  //       graph.getQuads({ subject: new NamedNode(subj) }, (q) => {
+  //         preds.add(q.predicate.toString());
+  //         const cellKey = subj + '|||' + q.predicate.toString();
+  //         if (!graphCells.has(cellKey)) {
+  //           graphCells.set(cellKey, new Set());
+  //         }
+  //         graphCells.get(cellKey).add(q.object);
+  //       });
+  //     });
+  //     const predsList = Array.from(preds);
+  //     predsList.splice(predsList.indexOf('http://www.w3.org/1999/02/22-rdf-syntax-ns#type'), 1);
+  //     // also pull out label, which should be used on 1st column
+  //     predsList.sort();
+
+  //     const thead = () => {
+  //       const predColumnHead = (pred) => {
+  //         return html`<th>${rdfNode(new NamedNode(pred))}</th>`;
+  //       };
+  //       return html`
+  //               <thead>
+  //                 <tr>
+  //                   <th></th>
+  //                   ${predsList.map(predColumnHead)}
+  //                 </tr>
+  //               </thead>`;
+  //     };
 
-    const thead = () => {
-      const predColumnHead = (pred) => {
-        return html`<th>${rdfNode(new NamedNode(pred))}</th>`;
-      };
-      return html`
-              <thead>
-                <tr>
-                  <th></th>
-                  ${predsList.map(predColumnHead)}
-                </tr>
-              </thead>`;
-    };
+  //     const instanceRow = (subj) => {
+  //       const cell = (pred) => {
+  //         const objs = graphCells.get(subj + '|||' + pred);
+  //         if (!objs) {
+  //           return html`<td></td>`;
+  //         }
+  //         const objsList = Array.from(objs);
+  //         objsList.sort();
+  //         const draw = (obj) => {
+  //           return html`<div>${rdfNode(obj)}</div>`
+  //         };
+  //         return html`<td>${objsList.map(draw)}</td>`;
+  //       };
 
-    const instanceRow = (subj) => {
-      const cell = (pred) => {
-        const objs = graphCells.get(subj + '|||' + pred);
-        if (!objs) {
-          return html`<td></td>`;
-        }
-        const objsList = Array.from(objs);
-        objsList.sort();
-        const draw = (obj) => {
-          return html`<div>${rdfNode(obj)}</div>`
-        };
-        return html`<td>${objsList.map(draw)}</td>`;
-      };
+  //       return html`
+  //               <tr>
+  //                 <td>${rdfNode(new NamedNode(subj))}</td>
+  //                 ${predsList.map(cell)}
+  //               </tr>
+  //             `;
+  //     };
 
-      return html`
-              <tr>
-                <td>${rdfNode(new NamedNode(subj))}</td>
-                ${predsList.map(cell)}
-              </tr>
-            `;
-    };
+  //     return html`
+  //           <div>[icon] ${rdfNode(new NamedNode(typeUri))} resources</div>
+  // <div class="typeBlockScroll">
+  //           <table class="typeBlock">
+  //             ${thead()}
+  //             ${subjs.map(instanceRow)}
+  //           </table>
+  // </div>
+  //         `;
+  //   };
+
+  makeTemplate(): TemplateResult {
+
+    const { byType, untyped } = groupByRdfType(this.graph);
+    const typedSubjs = Array.from(byType.keys());
+    typedSubjs.sort();
+
+    const untypedSubjs = Array.from(untyped.values());
+    untypedSubjs.sort();
 
     return html`
-          <div>[icon] ${rdfNode(new NamedNode(typeUri))} resources</div>
-<div class="typeBlockScroll">
-          <table class="typeBlock">
-            ${thead()}
-            ${subjs.map(instanceRow)}
-          </table>
-</div>
-        `;
-  };
-
-  return html`
-      <link rel="stylesheet" href="/rdf/browse/style.css">
+        <link rel="stylesheet" href="../src/streamed-graph.css">
 
-      <section>
-        <h2>
-          Current graph (<a href="${graph.events.url}">${graph.events.url}</a>)
-        </h2>
-        <div>
-         <!-- todo: graphs and provenance.
-          These statements are all in the
-          <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
-        </div>
-        ${typedSubjs.map(byTypeBlock)}
-        <div class="spoGrid">
-          ${untypedSubjs.map(subjBlock)}
-        </div>
-      </section>
-    `;
+        <section>
+          <h2>
+            Current graph (<a href="${this.url}">${this.url}</a>)
+          </h2>
+          <div>
+           <!-- todo: graphs and provenance.
+            These statements are all in the
+            <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
+          </div>
+          {typedSubjs.map(byTypeBlock)}
+          <div class="spoGrid">
+            ${untypedSubjs.map(this._subjBlock.bind(this))}
+          </div>
+        </section>
+      `;
+  }
 }
-export { graphView }