comparison src/layout/Layout.ts @ 108:5e6840229a05

rewrite freeStatements rendering to put more planning in layout
author drewp@bigasterisk.com
date Fri, 18 Mar 2022 11:57:38 -0700
parents 2468f2227d22
children 3cdbbd913f1d
comparison
equal deleted inserted replaced
107:042bd3361339 108:5e6840229a05
1 // Organize graph data into tables (column orders, etc) for the view layer. 1 // Organize graph data into tables (column orders, etc) for the view layer.
2 2
3 import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x) 3 import Immutable from "immutable"; // mostly using this for the builtin equals() testing, since NamedNode(x)!=NamedNode(x)
4 import { NamedNode, Quad, Store, Term } from "n3"; 4 import { NamedNode, Quad, Store, Term } from "n3";
5 import { rdf } from "./namespaces"; 5 import { rdf } from "./namespaces";
6 import { uniqueSortedTerms } from "./rdf_value";
6 import { TableDesc, ViewConfig } from "./ViewConfig"; 7 import { TableDesc, ViewConfig } from "./ViewConfig";
7 8
8 type UriSet = Immutable.Set<NamedNode>; 9 type UriSet = Immutable.Set<NamedNode>;
9 export type TypeToSubjs = Immutable.Map<NamedNode, UriSet>; 10 export type TypeToSubjs = Immutable.Map<NamedNode, UriSet>;
10
11 // https://github.com/rdfjs/N3.js/issues/265
12 (NamedNode.prototype as any).hashCode = () => 0;
13 11
14 interface ColumnHeader { 12 interface ColumnHeader {
15 rdfType: NamedNode; 13 rdfType: NamedNode;
16 pred: NamedNode; 14 pred: NamedNode;
17 } 15 }
16
18 export interface AlignedTable { 17 export interface AlignedTable {
19 columnHeaders: ColumnHeader[]; 18 columnHeaders: ColumnHeader[];
20 rows: (Term | null)[][]; // each row is 1 wider than columnHeaders since the 1st element is the subject for that row 19 rows: (Term | null)[][]; // each row is 1 wider than columnHeaders since the 1st element is the subject for that row
21 } 20 }
22 interface FreeStatements { 21
23 statements: Quad[]; 22 export interface PredRow {
24 } 23 pred: NamedNode;
24 objs: Term[];
25 }
26
27 export interface SubjRow {
28 subj: NamedNode;
29 predRows: PredRow[];
30 }
31
32 export interface FreeStatements {
33 subjRows: SubjRow[];
34 }
35
25 export interface LayoutResult { 36 export interface LayoutResult {
26 sections: (AlignedTable | FreeStatements)[]; 37 sections: (AlignedTable | FreeStatements)[];
27 } 38 }
28 39
29 class AlignedTableBuilder { 40 class AlignedTableBuilder {
98 null 109 null
99 ); 110 );
100 return Immutable.Set(subjectsToGather); 111 return Immutable.Set(subjectsToGather);
101 } 112 }
102 113
114 function freeStatmentsSection(stmts: Quad[]): FreeStatements {
115 const subjs: NamedNode[] = [];
116 stmts.forEach((q) => {
117 subjs.push(q.subject as NamedNode);
118 });
119 return {
120 subjRows: uniqueSortedTerms(subjs).map((subj) => {
121 const preds: NamedNode[] = [];
122 let po = Immutable.Map<NamedNode, Term[]>();
123 stmts.forEach((q) => {
124 if (q.subject.equals(subj)) {
125 const p = q.predicate as NamedNode;
126 preds.push(p);
127 po = po.set(p, po.get(p, []));
128 po.get(p)?.push(q.object as Term);
129 }
130 });
131
132 const rows: PredRow[] = [];
133 uniqueSortedTerms(preds).forEach((p) => {
134 rows.push({ pred: p, objs: uniqueSortedTerms(po.get(p, [])) });
135 });
136 return { subj: subj, predRows: rows };
137 }),
138 };
139 }
140
141 // The description of how this page should look: sections, tables, etc.
103 export class Layout { 142 export class Layout {
104 constructor(public viewConfig?: ViewConfig) {} 143 constructor(public viewConfig?: ViewConfig) {}
105 plan(graph: Store): LayoutResult { 144 plan(graph: Store): LayoutResult {
106 const typesToGatherSet = findTypesNeededForTables(this.viewConfig); 145 const typesToGatherSet = findTypesNeededForTables(this.viewConfig);
107 146
128 ); 167 );
129 const res: LayoutResult = { sections: [] }; 168 const res: LayoutResult = { sections: [] };
130 if (table) { 169 if (table) {
131 res.sections.push(table.value()); 170 res.sections.push(table.value());
132 } 171 }
133 res.sections.push({ statements: ungrouped }); 172 res.sections.push(freeStatmentsSection(ungrouped));
134 return res; 173 return res;
135 } 174 }
136 } 175 }
137 176
138 // interface ISP { 177 // interface ISP {