Changeset - 9324fc8285ad
[Not reviewed]
default
0 3 0
drewp@bigasterisk.com - 3 years ago 2022-05-31 06:21:50
drewp@bigasterisk.com
Effect repairs duplicate :settings edges when it finds them
3 files changed with 22 insertions and 9 deletions:
0 comments (0 inline, 0 general)
light9/web/live/Effect.ts
Show inline comments
 
import debug from "debug";
 
import { Literal, NamedNode, Quad_Object, Quad_Predicate, Quad_Subject, Term } from "n3";
 
import { some } from "underscore";
 
import { Patch, patchContainsPreds } from "../patch";
 
import { Patch, patchContainsPreds, patchUpdate } from "../patch";
 
import { SyncedGraph } from "../SyncedGraph";
 

	
 
type Color = string;
 
export type ControlValue = number | Color | NamedNode;
 

	
 
const log = debug("effect");
 
@@ -62,14 +62,17 @@ export class Effect {
 
      // that's an approx list of preds , but it just means we'll miss some pathological settings edits
 
    //   return;
 
    }
 

	
 
    // log("syncFromGraph", this.uri);
 

	
 
    // this repeats work- it gathers all settings when really some values changed (and we might even know about them). maybe push the value-fetching into a secnod phase of the run, and have the 1st phase drop out early
 
    const newSettings = [];
 

	
 
    const seenDevAttrPairs: Set<string> = new Set();
 

	
 
    for (let setting of Array.from(this.graph.objects(this.uri, U(":setting")))) {
 
      //   log(`  setting ${setting.value}`);
 
      if (!isUri(setting)) throw new Error();
 
      let value: ControlValue;
 
      const device = this.graph.uriValue(setting, U(":device"));
 
      const deviceAttr = this.graph.uriValue(setting, U(":deviceAttr"));
 
@@ -106,33 +109,36 @@ export class Effect {
 
  }
 

	
 
  // change this object now, but return the patch to be applied to the graph so it can be coalesced.
 
  edit(device: NamedNode, deviceAttr: NamedNode, newValue: ControlValue | null): Patch {
 
    log(`edit: value=${newValue}`);
 
    let existingSetting: NamedNode | null = null;
 
    let result = { adds: [], dels: [] };
 
    for (let s of this.settings) {
 
      if (device.equals(s.device) && deviceAttr.equals(s.deviceAttr)) {
 
        if (existingSetting !== null) {
 
          throw new Error(`${this.uri.value} had two settings for ${device.value} - ${deviceAttr.value}`);
 
          // this is corrupt. There was only supposed to be one setting per (dev,attr) pair. But we can fix it because we're going to update existingSetting to the user's requested value.
 
          log(`${this.uri.value} had two settings for ${device.value} - ${deviceAttr.value} - deleting ${s.setting}`);
 
          patchUpdate(result,  this._removeEffectSetting(s.setting));
 
        }
 
        existingSetting = s.setting;
 
      }
 
    }
 

	
 
    if (newValue !== null && this.shouldBeStored(deviceAttr, newValue)) {
 
      if (existingSetting === null) {
 
        return this._addEffectSetting(device, deviceAttr, newValue);
 
        patchUpdate(result, this._addEffectSetting(device, deviceAttr, newValue));
 
      } else {
 
        return this._patchExistingEffectSetting(existingSetting, deviceAttr, newValue);
 
        patchUpdate(result, this._patchExistingEffectSetting(existingSetting, deviceAttr, newValue));
 
      }
 
    } else {
 
      if (existingSetting !== null) {
 
        return this._removeEffectSetting(existingSetting);
 
        patchUpdate(result, this._removeEffectSetting(existingSetting));
 
      }
 
    }
 
    return { adds: [], dels: [] };
 
    return result;
 
  }
 

	
 
  shouldBeStored(deviceAttr: NamedNode, value: ControlValue | null): boolean {
 
    // this is a bug for zoom=0, since collector will default it to
 
    // stick at the last setting if we don't explicitly send the
 
    // 0. rx/ry similar though not the exact same deal because of
light9/web/live/Light9LiveControls.ts
Show inline comments
 
@@ -4,14 +4,14 @@ import { customElement, property } from 
 
import { NamedNode } from "n3";
 
import { sortBy, uniq } from "underscore";
 
import { Patch, patchContainsPreds } from "../patch";
 
import { getTopGraph } from "../RdfdbSyncedGraph";
 
import { SyncedGraph } from "../SyncedGraph";
 
import { GraphToControls } from "./GraphToControls";
 
export { EditChoice } from "../EditChoice";
 
export { Light9DeviceControl as Light9LiveDeviceControl } from "./Light9DeviceControl";
 
export { EditChoice } from "../EditChoice";
 
const log = debug("controls");
 

	
 
@customElement("light9-live-controls")
 
export class Light9LiveControls extends LitElement {
 
  graph!: SyncedGraph;
 

	
light9/web/patch.ts
Show inline comments
 
import * as async from "async";
 
import debug from "debug";
 
import * as async from "async";
 
import { Writer, Parser, Quad, NamedNode } from "n3";
 
import { NamedNode, Parser, Quad, Writer } from "n3";
 
const log = debug("patch");
 

	
 
export interface Patch {
 
  dels: Quad[];
 
  adds: Quad[];
 
  _allPredsCache?: Set<string>;
 
@@ -11,12 +11,18 @@ export interface Patch {
 
}
 

	
 
interface SyncgraphPatchMessage {
 
  patch: { adds: string; deletes: string };
 
}
 

	
 
export function patchUpdate(p1: Patch, p2: Patch): void {
 
  // this is approx, since it doesnt handle matching existing quads.
 
  p1.adds = p1.adds.concat(p2.adds);
 
  p1.dels = p1.dels.concat(p2.dels);
 
}
 

	
 
export function patchSizeSummary(patch: Patch) {
 
  return "-" + patch.dels.length + " +" + patch.adds.length;
 
}
 

	
 
export function parseJsonPatch(input: SyncgraphPatchMessage, cb: (p: Patch) => void) {
 
  // note response cb doesn't have an error arg.
 
@@ -40,12 +46,13 @@ export function parseJsonPatch(input: Sy
 
      } else {
 
        return cb();
 
      }
 
    });
 
  };
 

	
 
  // todo: is it faster to run them in series? might be
 
  return async.parallel([parseAdds, parseDels], (err: any) => cb(patch));
 
}
 

	
 
export function toJsonPatch(jsPatch: Patch, cb: { (json: any): any; (arg0: any): any }) {
 
  const out: SyncgraphPatchMessage = { patch: { adds: "", deletes: "" } };
 

	
0 comments (0 inline, 0 general)