changeset 97:26c55d5d5202

WIP on views & joins
author drewp@bigasterisk.com
date Fri, 11 Feb 2022 20:27:02 -0800
parents 4d19759d0d9a
children 6807ee85d031
files demo/public/repos.n3 src/graph_view.ts src/suffixLabels.ts src/tabulate.ts src/view_loader.ts
diffstat 5 files changed, 57 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/demo/public/repos.n3	Thu Jan 13 21:32:18 2022 -0800
+++ b/demo/public/repos.n3	Fri Feb 11 20:27:02 2022 -0800
@@ -5,4 +5,7 @@
 
 <> a :View ; rdfs:label "repos" .
 <> :table demo:table1 .
-demo:table1 :showsType :Repo .
+demo:table1 
+  :primaryType :Repo;
+  :joinType :HgRepo;
+  :joinType :GithubRepo .
--- a/src/graph_view.ts	Thu Jan 13 21:32:18 2022 -0800
+++ b/src/graph_view.ts	Fri Feb 11 20:27:02 2022 -0800
@@ -1,5 +1,5 @@
 import { html, TemplateResult } from "lit";
-import { DataFactory, Literal, NamedNode, Quad, Store, Term, Util } from "n3";
+import { DataFactory, Literal, NamedNode, Quad, Store, Term } from "n3";
 import { NodeDisplay } from "./NodeDisplay";
 import { SuffixLabels } from "./suffixLabels";
 import {
@@ -8,7 +8,7 @@
   predsForSubj,
   TypeToSubjs,
 } from "./tabulate";
-import { View } from "./view_loader";
+import { TableDesc, View } from "./view_loader";
 
 const { namedNode } = DataFactory;
 
@@ -30,12 +30,18 @@
     this.graph = graph;
 
     const labels = new SuffixLabels();
-    this._addLabelsForAllTerms(labels);
+    this._addLabelsForAllTerms(this.graph, labels);
+    
+    if (this.view.graph) {
+      this._addLabelsForAllTerms(this.view.graph, labels);
+    }
     this.nodeDisplay = new NodeDisplay(labels);
   }
 
-  _addLabelsForAllTerms(labels: SuffixLabels) {
-    return this.graph.forEach(
+  _addLabelsForAllTerms(graph: Store, labels: SuffixLabels) {
+    console.log("_addLabelsForAllTerms");
+
+    graph.forEach(
       (q: Quad) => {
         if (q.subject.termType === "NamedNode") {
           labels.planDisplayForNode(q.subject);
@@ -144,11 +150,20 @@
     };
   }
 
-  _multiSubjsTypeBlock(byType: TypeToSubjs, typeUri: NamedNode) {
-    const layout = new MultiSubjsTypeBlockLayout(this.graph, byType, typeUri);
+  _multiSubjsTypeBlock(byType: TypeToSubjs, table: TableDesc) {
+    const layout = new MultiSubjsTypeBlockLayout(this.graph, byType, table);
+
+    let typeNames = [html`${this.nodeDisplay.render(table.primary)}`];
+    if (table.joins) {
+      typeNames.push(html` joined with [`);
+      for (let j of table.joins) {
+        typeNames.push(html`${this.nodeDisplay.render(j)}`);
+      }
+      typeNames.push(html`]`);
+    }
 
     return html`
-      <div>[icon] ${this.nodeDisplay.render(typeUri)} type resources</div>
+      <div>[icon] Resources of type ${typeNames}</div>
       <div class="typeBlockScroll">
         <table class="typeBlock">
           ${this._thead(layout)} ${layout.subjs.map(this._instanceRow(layout))}
@@ -162,9 +177,10 @@
     const { byType, typesPresent, untypedSubjs } = groupByRdfType(this.graph);
     let viewTitle = html` (no view)`;
     if (this.view.url) {
-      viewTitle = html` using view <a href="${this.view.url}">${this.view.label()}</a>`;
+      viewTitle = html` using view
+        <a href="${this.view.url}">${this.view.label()}</a>`;
     }
-    const typesToShow = this.view.typesToShow(typesPresent);
+    const tables = this.view.toplevelTables(typesPresent);
     return html`
       <section>
         <h2>
@@ -175,9 +191,7 @@
             These statements are all in the
             <span data-bind="html: $root.createCurie(graphUri())">...</span> graph.-->
         </div>
-        ${typesToShow.map((t: NamedNode) =>
-          this._multiSubjsTypeBlock(byType, t)
-        )}
+        ${tables.map((t: TableDesc) => this._multiSubjsTypeBlock(byType, t))}
         <div class="spoGrid">
           ${untypedSubjs.map(this._subjPredObjsBlock.bind(this))}
         </div>
--- a/src/suffixLabels.ts	Thu Jan 13 21:32:18 2022 -0800
+++ b/src/suffixLabels.ts	Fri Feb 11 20:27:02 2022 -0800
@@ -2,7 +2,8 @@
 
 type SuffixesNode = { usedBy?: string; children: Map<string, SuffixesNode> };
 type DisplayNode = { label?: string; link?: string };
-class SuffixLabels {
+
+export class SuffixLabels {
   displayNodes: Map<string, DisplayNode>;
   usedSuffixes: SuffixesNode;
   constructor() {
@@ -63,7 +64,11 @@
 
   // a substring to show for this uri
   getLabelForNode(node: string) {
-    return this.displayNodes.get(node)!.label;
+    const dn = this.displayNodes.get(node);
+    if (dn === undefined) {
+      throw new Error(`you never called planDisplayForNode on ${node}`);
+    }
+    return dn.label;
   }
 
   static _tailSegments(uri: string, n: number) {
@@ -74,5 +79,3 @@
     return uri.substr(i + 1);
   }
 }
-
-export { SuffixLabels };
--- a/src/tabulate.ts	Thu Jan 13 21:32:18 2022 -0800
+++ b/src/tabulate.ts	Fri Feb 11 20:27:02 2022 -0800
@@ -10,6 +10,7 @@
   Term,
   Util,
 } from "n3";
+import { TableDesc } from "./view_loader";
 
 const { namedNode } = DataFactory;
 
@@ -110,8 +111,8 @@
   subjs: NamedNode[];
   preds: NamedNode[];
   graphCells: Immutable.Map<ISP, Immutable.Set<Term>>;
-  constructor(graph: Store, byType: TypeToSubjs, typeUri: NamedNode) {
-    const subjSet = byType.get(typeUri);
+  constructor(graph: Store, byType: TypeToSubjs, table: TableDesc) {
+    const subjSet = byType.get(table.primary);
     this.subjs = subjSet ? Array.from(subjSet) : [];
     this.subjs.sort();
 
--- a/src/view_loader.ts	Thu Jan 13 21:32:18 2022 -0800
+++ b/src/view_loader.ts	Fri Feb 11 20:27:02 2022 -0800
@@ -12,6 +12,13 @@
   throw new Error("no elems");
 }
 
+export interface TableDesc {
+  uri: NamedNode;
+  primary: NamedNode;
+  joins: NamedNode[];
+}
+
+
 export class View {
   graph: Store;
   ready: Promise<null>;
@@ -42,11 +49,16 @@
   }
 
   // filtered+ordered list of types to show at the top level
-  typesToShow(typesPresent: NamedNode[]): NamedNode[] {
-    const ret: NamedNode[] = [];
+  toplevelTables(typesPresent: NamedNode[]): TableDesc[] {
+    const ret: TableDesc[] = [];
     for (let table of this.graph.getObjects(this.viewRoot, EX("table"), null)) {
-      const tableType = uriValue(this.graph, table, EX("showsType"));
-      ret.push(tableType);
+      const tableType = uriValue(this.graph, table, EX("primaryType"));
+      const joins: NamedNode[] = [];
+      for (let joinType of this.graph.getObjects(table, EX("joinType"), null)) {
+        joins.push(joinType as NamedNode);
+      }
+      joins.sort();
+      ret.push({ uri: table as NamedNode, primary: tableType, joins: joins });
     }
     ret.sort();
     return ret;