view src/layout/ViewConfig.ts @ 122:2e8fa3fec0c8

support joining subjects into wider rows
author drewp@bigasterisk.com
date Sun, 20 Mar 2022 14:12:03 -0700
parents 3cdbbd913f1d
children 5a1a79f54779
line wrap: on
line source

// Load requested view (rdf data) and provide access to it
import { DataFactory, NamedNode, Store } from "n3";
import { fetchAndParse, n3Graph } from "./fetchAndParse";
import { EX, RDF } from "./namespaces";
import { labelOrTail, uriValue } from "./rdf_value";
const Uri = DataFactory.namedNode;

function firstElem<E>(seq: Iterable<E>): E {
  for (let e of seq) {
    return e;
  }
  throw new Error("no elems");
}

export interface Link {
  // If you display a subject u1 with a `pred` edge to u2, then treat u2 as an alias of u1.
  pred: NamedNode;
}

interface TableDesc {
  uri: NamedNode;
  primary: NamedNode;
  joins: NamedNode[];
  links: Link[];
}

export class ViewConfig {
  graph: Store;
  viewRoot!: NamedNode;
  url?: string;
  tables: TableDesc[] = [];

  constructor() {
    this.graph = new Store();
  }

  async readFromUrl(url: string | "") {
    if (!url) {
      return;
    }
    this.url = url;
    await fetchAndParse(url, this.graph);

    this._read();
  }

  async readFromGraph(n3: string) {
    this.graph = await n3Graph(n3);
    this._read();
  }

  _read() {
    this.viewRoot = firstElem(
      this.graph.getSubjects(RDF("type"), EX("View"), null)
    ) as NamedNode;
    for (let table of this.graph.getObjects(this.viewRoot, EX("table"), null)) {
      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();

      const links: Link[] = [];
      for (let linkDesc of this.graph.getObjects(table, EX("link"), null)) {
        links.push({
          pred: uriValue(this.graph, linkDesc, EX("predicate")),
        });
      }

      this.tables.push({
        uri: table as NamedNode,
        primary: tableType,
        joins: joins,
        links: links,
      });
    }
    this.tables.sort();
  }

  label(): string {
    return this.url !== undefined
      ? labelOrTail(this.graph, Uri(this.url))
      : "unnamed";
  }
}