Changeset - 702c1fd95dfd
[Not reviewed]
default
0 1 0
drewp@bigasterisk.com - 20 months ago 2023-05-29 22:18:32
drewp@bigasterisk.com
another empty-patch guard, to cause me to fix problems upstream of this call
1 file changed with 1 insertions and 0 deletions:
0 comments (0 inline, 0 general)
light9/web/SyncedGraph.ts
Show inline comments
 
@@ -77,192 +77,193 @@ export class SyncedGraph {
 
  }
 

	
 
  U() {
 
    // just a shorthand
 
    return this.Uri.bind(this);
 
  }
 

	
 
  Uri(curie: string) {
 
    if (curie == null) {
 
      throw new Error("no uri");
 
    }
 
    if (curie.match(/^http/)) {
 
      return N3.DataFactory.namedNode(curie);
 
    }
 
    const part = curie.split(":");
 
    return this.prefixFuncs(part[0])(part[1]);
 
  }
 

	
 
  // Uri(shorten(u)).value==u
 
  shorten(uri: N3.NamedNode): string {
 
    for (let row of [
 
      { sh: "dev", lo: "http://light9.bigasterisk.com/theater/vet/device/" },
 
      { sh: "effect", lo: "http://light9.bigasterisk.com/effect/" },
 
      { sh: "", lo: "http://light9.bigasterisk.com/" },
 
      { sh: "rdfs", lo: "http://www.w3.org/2000/01/rdf-schema#" },
 
      { sh: "xsd", lo: "http://www.w3.org/2001/XMLSchema#" },
 
    ]) {
 
      if (uri.value.startsWith(row.lo)) {
 
        return row.sh + ":" + uri.value.substring(row.lo.length);
 
      }
 
    }
 
    return uri.value;
 
  }
 

	
 
  Literal(jsValue: string | number) {
 
    return N3.DataFactory.literal(jsValue);
 
  }
 

	
 
  LiteralRoundedFloat(f: number) {
 
    return N3.DataFactory.literal(f.toPrecision(3), this.Uri("http://www.w3.org/2001/XMLSchema#decimal"));
 
  }
 

	
 
  Quad(s: any, p: any, o: any, g: any) {
 
    return N3.DataFactory.quad(s, p, o, g);
 
  }
 

	
 
  toJs(literal: { value: any }) {
 
    // incomplete
 
    return parseFloat(literal.value);
 
  }
 

	
 
  loadTrig(trig: any, cb: () => any) {
 
    // for debugging
 
    const adds: Quad[] = [];
 
    const parser = new N3.Parser();
 
    parser.parse(trig, (error: any, quad: any, prefixes: any) => {
 
      if (error) {
 
        throw new Error(error);
 
      }
 
      if (quad) {
 
        adds.push(quad);
 
      } else {
 
        this._applyPatch(new Patch([], adds));
 
        // todo: here, add those prefixes to our known set
 
        if (cb) {
 
          cb();
 
        }
 
      }
 
    });
 
  }
 

	
 
  quads(): any {
 
    // for debugging
 
    return Array.from(this.graph.getQuads(null, null, null, null)).map((q: Quad) => [q.subject, q.predicate, q.object, q.graph]);
 
  }
 

	
 
  applyAndSendPatch(patch: Patch) {
 
    console.time("applyAndSendPatch");
 
    if (!this.client) {
 
      log("not connected-- dropping patch");
 
      return;
 
    }
 
    if (patch.isEmpty()) throw "should not get to this point with empty patch";
 

	
 
    this._applyPatch(patch);
 
    if (this.client) {
 
      log("sending patch:\n", patch.dump());
 
      this.client.sendPatch(patch);
 
    }
 
    console.timeEnd("applyAndSendPatch");
 
  }
 

	
 
  _applyPatch(patch: Patch) {
 
    // In most cases you want applyAndSendPatch.
 
    //
 
    // This is the only method that writes to this.graph!
 
    if (patch.isEmpty()) throw "dont send empty patches here";
 
    log("_applyPatch [1] \n", patch.dump());
 
    this.cachedFloatValues.clear();
 
    this.cachedUriValues.clear();
 
    patch.applyToGraph(this.graph);
 
    if (false) {
 
      log("applied patch locally", patch.summary());
 
    } else {
 
      log("applied patch locally:\n" + patch.dump());
 
    }
 
    this.autoDeps.graphChanged(patch);
 
  }
 

	
 
  getObjectPatch(s: N3.NamedNode, p: N3.NamedNode, newObject: N3.Quad_Object | null, g: N3.NamedNode): Patch {
 
    // make a patch which removes existing values for (s,p,*,c) and
 
    // adds (s,p,newObject,c). Values in other graphs are not affected.
 
    const existing = this.graph.getQuads(s, p, null, g);
 
    return new Patch(existing, newObject !== null ? [this.Quad(s, p, newObject, g)] : []);
 
  }
 

	
 
  patchObject(s: N3.NamedNode, p: N3.NamedNode, newObject: N3.Quad_Object | null, g: N3.NamedNode) {
 
    this.applyAndSendPatch(this.getObjectPatch(s, p, newObject, g));
 
  }
 

	
 
  clearObjects(s: N3.NamedNode, p: N3.NamedNode, g: N3.NamedNode) {
 
    this.applyAndSendPatch(new Patch(this.graph.getQuads(s, p, null, g), []));
 
  }
 

	
 
  public runHandler(func: HandlerFunc, label: string) {
 
    // runs your func once, tracking graph calls. if a future patch
 
    // matches what you queried, we runHandler your func again (and
 
    // forget your queries from the first time).
 

	
 
    // helps with memleak? not sure yet. The point was if two matching
 
    // labels get puushed on, we should run only one. So maybe
 
    // appending a serial number is backwards.
 
    if (!this.serial) {
 
      this.serial = 1;
 
    }
 
    this.serial += 1;
 
    //label = label + @serial
 

	
 
    this.autoDeps.runHandler(func, label);
 
  }
 

	
 
  _singleValue(s: Quad_Subject, p: Quad_Predicate) {
 
    this.autoDeps.askedFor(s, p, null, null);
 
    const quads = this.graph.getQuads(s, p, null, null);
 
    const objs = new Set(Array.from(quads).map((q: Quad) => q.object));
 

	
 
    switch (objs.size) {
 
      case 0:
 
        throw new Error("no value for " + s.value + " " + p.value);
 
      case 1:
 
        var obj = objs.values().next().value;
 
        return obj;
 
      default:
 
        throw new Error("too many different values: " + JSON.stringify(quads));
 
    }
 
  }
 

	
 
  floatValue(s: Quad_Subject, p: Quad_Predicate) {
 
    const key = s.value + "|" + p.value;
 
    const hit = this.cachedFloatValues.get(key);
 
    if (hit !== undefined) {
 
      return hit;
 
    }
 
    //log('float miss', s, p)
 

	
 
    const v = this._singleValue(s, p).value;
 
    const ret = parseFloat(v);
 
    if (isNaN(ret)) {
 
      throw new Error(`${s.value} ${p.value} -> ${v} not a float`);
 
    }
 
    this.cachedFloatValues.set(key, ret);
 
    return ret;
 
  }
 

	
 
  stringValue(s: any, p: any) {
 
    return this._singleValue(s, p).value;
 
  }
 

	
 
  uriValue(s: Quad_Subject, p: Quad_Predicate) {
 
    const key = s.value + "|" + p.value;
 
    const hit = this.cachedUriValues.get(key);
 
    if (hit !== undefined) {
 
      return hit;
 
    }
 

	
 
    const ret = this._singleValue(s, p);
 
    this.cachedUriValues.set(key, ret);
 
    return ret;
 
  }
 

	
 
  labelOrTail(uri: { value: { split: (arg0: string) => any } }) {
 
    let ret: any;
 
    try {
0 comments (0 inline, 0 general)