Changeset - 72380e12d86c
[Not reviewed]
default
0 1 0
Drew Perttula - 7 years ago 2018-05-29 07:00:37
drewp@bigasterisk.com
performance: add @cachedUriValues
Ignore-this: f3a707bc25acc028dedd2f115a5d17e5
1 file changed with 10 insertions and 2 deletions:
0 comments (0 inline, 0 general)
light9/web/graph.coffee
Show inline comments
 
@@ -132,49 +132,50 @@ class window.SyncedGraph
 
  #
 
  # Note that _applyPatch is the only method to write to the graph, so
 
  # it can fire subscriptions.
 

	
 
  constructor: (@patchSenderUrl, @prefixes, @setStatus) ->
 
    # patchSenderUrl is the /syncedGraph path of an rdfdb server.
 
    # prefixes can be used in Uri(curie) calls.
 
    @_autoDeps = new AutoDependencies() # replaces GraphWatchers
 
    @clearGraph()
 

	
 
    if @patchSenderUrl
 
      @_client = new RdfDbClient(@patchSenderUrl,
 
                                 @_clearGraphOnNewConnection.bind(@),
 
                                 @_applyPatch.bind(@),
 
                                 @setStatus)
 
    
 
  clearGraph: ->
 
    # just deletes the statements; watchers are unaffected.
 
    if @graph?
 
      @_applyPatch({addQuads: [], delQuads: @graph.getQuads()})
 

	
 
    # if we had a Store already, this lets N3.Store free all its indices/etc
 
    @graph = N3.Store()
 
    @_addPrefixes(@prefixes)
 
    @cachedFloatValues = new Map()
 
    @cachedFloatValues = new Map() # s + '|' + p -> number
 
    @cachedUriValues = new Map() # s + '|' + p -> Uri
 

	
 
  _clearGraphOnNewConnection: -> # must not send a patch to the server!
 
    log('graph: clearGraphOnNewConnection')
 
    @clearGraph()
 
    log('graph: clearGraphOnNewConnection done')
 
      
 
  _addPrefixes: (prefixes) ->
 
    for k in (prefixes or {})
 
      @prefixes[k] = prefixes[k]
 
    @prefixFuncs = N3.Util.prefixes(@prefixes)
 
        
 
  Uri: (curie) ->
 
    if not curie?
 
      throw new Error("no uri")
 
    if curie.match(/^http/)
 
      return N3.DataFactory.namedNode(curie)
 
    part = curie.split(':')
 
    return @prefixFuncs(part[0])(part[1])
 

	
 
  Literal: (jsValue) ->
 
    N3.DataFactory.literal(jsValue)
 

	
 
  LiteralRoundedFloat: (f) ->
 
    N3.DataFactory.literal(d3.format(".3f")(f),
 
@@ -207,48 +208,49 @@ class window.SyncedGraph
 
    if !Array.isArray(patch.addQuads) || !Array.isArray(patch.delQuads)
 
      console.timeEnd('applyAndSendPatch')
 
      log('corrupt patch')
 
      throw new Error("corrupt patch: #{JSON.stringify(patch)}")
 

	
 
    @_validatePatch(patch)
 

	
 
    @_applyPatch(patch)
 
    @_client.sendPatch(patch) if @_client
 
    console.timeEnd('applyAndSendPatch')
 

	
 
  _validatePatch: (patch) ->
 
    for qs in [patch.addQuads, patch.delQuads]
 
      for q in qs
 
        if not q.equals
 
          throw new Error("doesn't look like a proper Quad")
 
        if not q.subject.id or not q.graph.id? or not q.predicate.id?
 
          throw new Error("corrupt patch: #{JSON.stringify(q)}")
 
    
 
  _applyPatch: (patch) ->
 
    # In most cases you want applyAndSendPatch.
 
    #
 
    # This is the only method that writes to @graph!
 
    @cachedFloatValues.clear()
 
    @cachedUriValues.clear()
 
    for quad in patch.delQuads
 
      #log("remove #{JSON.stringify(quad)}")
 
      did = @graph.removeQuad(quad)
 
      #log("removed: #{did}")
 
    for quad in patch.addQuads
 
      @graph.addQuad(quad)
 
    #log('applied patch locally', patchSizeSummary(patch))
 
    @_autoDeps.graphChanged(patch)
 

	
 
  getObjectPatch: (s, p, newObject, g) ->
 
    # make a patch which removes existing values for (s,p,*,c) and
 
    # adds (s,p,newObject,c). Values in other graphs are not affected.
 
    existing = @graph.getQuads(s, p, null, g)
 
    return {
 
      delQuads: existing,
 
      addQuads: [@Quad(s, p, newObject, g)]
 
    }
 

	
 
  patchObject: (s, p, newObject, g) ->
 
    @applyAndSendPatch(@getObjectPatch(s, p, newObject, g))
 
  
 
  runHandler: (func, label) ->
 
    # runs your func once, tracking graph calls. if a future patch
 
    # matches what you queried, we runHandler your func again (and
 
@@ -270,49 +272,55 @@ class window.SyncedGraph
 
    
 
    switch objs.size
 
      when 0
 
        throw new Error("no value for "+s.value+" "+p.value)
 
      when 1
 
        obj = objs.values().next().value
 
        return obj
 
      else
 
        throw new Error("too many different values: " + JSON.stringify(quads))
 

	
 
  floatValue: (s, p) ->
 
    key = s.value + '|' + p.value
 
    hit = @cachedFloatValues.get(key)
 
    return hit if hit != undefined
 
    #log('float miss', s, p)
 

	
 
    ret = parseFloat(@_singleValue(s, p).value)
 
    @cachedFloatValues.set(key, ret)
 
    return ret
 
    
 
  stringValue: (s, p) ->
 
    @_singleValue(s, p).value
 
    
 
  uriValue: (s, p) ->
 
    @_singleValue(s, p)
 
    key = s.value + '|' + p.value
 
    hit = @cachedUriValues.get(key)
 
    return hit if hit != undefined
 

	
 
    ret = @_singleValue(s, p)
 
    @cachedUriValues.set(key, ret)
 
    return ret
 

	
 
  labelOrTail: (uri) ->
 
    try
 
      ret = @stringValue(uri, @Uri('rdfs:label'))
 
    catch
 
      words = uri.value.split('/')
 
      ret = words[words.length-1]
 
    if not ret
 
      ret = uri.value
 
    return ret
 

	
 
  objects: (s, p) ->
 
    @_autoDeps.askedFor(s, p, null, null)
 
    quads = @graph.getQuads(s, p)
 
    return (q.object for q in quads)
 

	
 
  subjects: (p, o) ->
 
    @_autoDeps.askedFor(null, p, o, null)
 
    quads = @graph.getQuads(null, p, o)
 
    return (q.subject for q in quads)
 

	
 
  items: (list) ->
 
    out = []
 
    current = list
0 comments (0 inline, 0 general)