diff src/layout/Layout.ts @ 110:3cdbbd913f1d

table displays now just barely
author drewp@bigasterisk.com
date Fri, 18 Mar 2022 23:41:24 -0700
parents 5e6840229a05
children 4b33a479dc2f
line wrap: on
line diff
--- a/src/layout/Layout.ts	Fri Mar 18 12:00:33 2022 -0700
+++ b/src/layout/Layout.ts	Fri Mar 18 23:41:24 2022 -0700
@@ -2,7 +2,7 @@
 
 import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x)
 import { NamedNode, Quad, Store, Term } from "n3";
-import { rdf } from "./namespaces";
+import { rdf, rdfs } from "./namespaces";
 import { uniqueSortedTerms } from "./rdf_value";
 import { TableDesc, ViewConfig } from "./ViewConfig";
 
@@ -16,7 +16,8 @@
 
 export interface AlignedTable {
   columnHeaders: ColumnHeader[];
-  rows: (Term | null)[][]; // each row is 1 wider than columnHeaders since the 1st element is the subject for that row
+  rowHeaders: NamedNode[];
+  rows: Term[][][];
 }
 
 export interface PredRow {
@@ -37,51 +38,72 @@
   sections: (AlignedTable | FreeStatements)[];
 }
 
+interface ISP {
+  subj: NamedNode;
+  pred: NamedNode;
+}
+const makeSP = Immutable.Record<ISP>({
+  subj: new NamedNode(""),
+  pred: new NamedNode(""),
+});
+
 class AlignedTableBuilder {
-  columnPreds = Immutable.List<NamedNode>();
-  subjRowIndices = Immutable.Map<NamedNode, number>();
-  rows: (Term | null)[][] = [];
+  subjSet = Immutable.Set<NamedNode>();
+  predSet = Immutable.Set<NamedNode>();
+  cell = Immutable.Map<string, Immutable.Set<Term>>();
   constructor(
     public rdfType: NamedNode /* plus join types, sort instructions */
   ) {}
 
   addQuad(q: Quad) {
+    const subj = q.subject as NamedNode;
     const pred = q.predicate as NamedNode;
-    const omittedColumn = pred.equals(rdf.type);
-    if (!this.columnPreds.contains(pred) && !omittedColumn) {
-      this.columnPreds = this.columnPreds.push(pred); // this is putting cols in random order
-      this.rows.forEach((r) => r.push(null));
+    this.subjSet = this.subjSet.add(subj);
+    this.predSet = this.predSet.add(pred);
+
+    const key =subj.id+pred.id//makeSP({ subj, pred });
+    const cur = this.cell.get(key, undefined);
+    const newval =
+      cur === undefined ? Immutable.Set([q.object]) : cur.add(q.object);
+
+    this.cell = this.cell.set(key, newval);
+  }
+  
+  value(): AlignedTable {
+    let preds = uniqueSortedTerms(this.predSet);
+    const tagged = preds.map((p, i)=>{
+      if (p.equals(rdf.type)) {
+        i=999;
+      }
+      if (p.equals(rdfs.label)) {
+        i=-1
+      }
+      return {sort:i, val: p}
+    })
+    tagged.sort((a,b)=>{
+      return a.sort - b.sort;
+    });
+    preds = tagged.map((e)=>e.val);
+
+    // const omittedColumn = pred.equals(rdf.type);
+    const subjs = uniqueSortedTerms(this.subjSet);
+    const outputGrid: Term[][][] = [];
+    for (let subj of subjs) {
+      const row: Term[][] = [];
+      preds.forEach((pred) => {
+        const key = subj.id+pred.id;//makeSP({ subj, pred });
+        const objs = this.cell.get(key, Immutable.Set<Term>([]));
+        const uniq = uniqueSortedTerms(objs);
+        console.log("cell objs", objs.size, uniq.length);
+        row.push(uniq);
+      });
+      outputGrid.push(row);
     }
 
-    const predIndex = omittedColumn ? null : this.columnPreds.indexOf(pred);
-    let rowIndex = this.subjRowIndices.get(q.subject as NamedNode);
-    if (rowIndex === undefined) {
-      const newRow = new Array(1 + this.columnPreds.size).fill(null);
-      newRow[0] = q.subject;
-      this.rows.push(newRow);
-      rowIndex = this.rows.length - 1;
-      this.subjRowIndices = this.subjRowIndices.set(
-        q.subject as NamedNode,
-        rowIndex
-      );
-    }
-    if (predIndex !== null) {
-      this.rows[rowIndex][1 + predIndex] = q.object;
-    }
-  }
-
-  value(): AlignedTable {
-    this.rows.sort((a, b) => {
-      const uriA = (a[0] as NamedNode).value,
-        uriB = (b[0] as NamedNode).value;
-      return uriA.localeCompare(uriB);
+    const headers = preds.map((pred) => {
+      return { rdfType: this.rdfType, pred: pred };
     });
-    const headers = this.columnPreds
-      .map((pred) => {
-        return { rdfType: this.rdfType, pred: pred };
-      })
-      .toArray();
-    return { columnHeaders: headers, rows: this.rows };
+    return { columnHeaders: headers, rowHeaders: subjs, rows: outputGrid };
   }
 }
 
@@ -95,11 +117,13 @@
   return Immutable.Set(typesToGather);
 }
 
-function findSubjectsWithTypes(graph: Store, typesToGatherSet: UriSet): UriSet {
+function findSubjectsWithTypes(graph: Store, typesToGather: UriSet): UriSet {
   const subjectsToGather: NamedNode[] = [];
+  const ft = typesToGather.toArray()[0];
   graph.forEach(
     (q: Quad) => {
-      if (typesToGatherSet.contains(q.object as NamedNode)) {
+      if (q.object.equals(ft)) {
+        //typesToGather.has(q.object as NamedNode)) {
         subjectsToGather.push(q.subject as NamedNode);
       }
     },
@@ -142,22 +166,30 @@
 export class Layout {
   constructor(public viewConfig?: ViewConfig) {}
   plan(graph: Store): LayoutResult {
-    const typesToGatherSet = findTypesNeededForTables(this.viewConfig);
+    const typesToTable = findTypesNeededForTables(this.viewConfig);
 
-    const subjectsToGatherSet = findSubjectsWithTypes(graph, typesToGatherSet);
+    const subjectsToTable = findSubjectsWithTypes(graph, typesToTable);
     const ungrouped: Quad[] = [];
     const vc = this.viewConfig;
     const table =
       vc && vc.tables.length > 0
-        ? new AlignedTableBuilder(vc.tables[0].primary)
+        ? new AlignedTableBuilder(vc.tables[0].primary) //todo multiple tables
         : null;
 
     graph.forEach(
       (q: Quad) => {
-        if (!subjectsToGatherSet.contains(q.subject as NamedNode) || !table) {
+        let contains = false;
+        subjectsToTable.forEach((s) => {
+          if (s.equals(q.subject)) {
+            contains = true;
+          }
+        });
+
+        // if (subjectsToTable.has(q.subject as NamedNode) && table) { // not working
+        if (contains && table) {
+          table.addQuad(q);
+        } else {
           ungrouped.push(q);
-        } else {
-          table.addQuad(q);
         }
       },
       null,
@@ -167,6 +199,7 @@
     );
     const res: LayoutResult = { sections: [] };
     if (table) {
+      console.log("table value");
       res.sections.push(table.value());
     }
     res.sections.push(freeStatmentsSection(ungrouped));
@@ -174,15 +207,6 @@
   }
 }
 
-// interface ISP {
-//   subj: NamedNode;
-//   pred: NamedNode;
-// }
-// const SP = Immutable.Record<ISP>({
-//   subj: new NamedNode(""),
-//   pred: new NamedNode(""),
-// });
-
 // // One table of rows with a common rdf:type.
 // export class MultiSubjsTypeBlockLayout {
 //   subjs: NamedNode[];