Class: LD::Patch::Algebra::UpdateList

Inherits:
SPARQL::Algebra::Operator
  • Object
show all
Includes:
SPARQL::Algebra::Evaluatable, SPARQL::Algebra::Update
Defined in:
lib/ld/patch/algebra/update_list.rb

Overview

The LD Patch updateList operator.

The UpdateList operation is used to splice a new list into a subset of an existing list.

Constant Summary collapse

NAME =
:updateList

Instance Method Summary collapse

Instance Method Details

#execute(queryable, options = {}) ⇒ RDF::Query::Solutions

Executes this upate on the given writable graph or repository.

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to write

  • options (Hash{Symbol => Object}) (defaults to: {})

    any additional options

Returns:

  • (RDF::Query::Solutions)

    A single solution including passed bindings with var bound to the solution.

Raises:

  • (Error)

    If the subject and predicate provided to an UpdateList do not have a unique object, or if this object is not a well-formed collection. If an index in a slice expression is greater than the length of the rdf:List or otherwise out of bound.

See Also:



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/ld/patch/algebra/update_list.rb', line 26

def execute(queryable, options = {})
  debug(options) {"UpdateList"}
  bindings = options.fetch(:bindings)
  solution = bindings.first
  var_or_iri, predicate, slice1, slice2, collection = operands

  # Bind variables to path
  if var_or_iri.variable?
    raise LD::Patch::Error("Operand uses unbound variable #{var_or_iri.inspect}", code: 400) unless solution.bound?(var_or_iri)
    var_or_iri = solution[var_or_iri]
  end

  list_heads = queryable.query({subject: var_or_iri, predicate: predicate}).map {|s| s.object}

  raise LD::Patch::Error, "UpdateList ambigious value for #{var_or_iri.to_ntriples} and #{predicate.to_ntriples}" if list_heads.length > 1
  raise LD::Patch::Error, "UpdateList no value found for #{var_or_iri.to_ntriples} and #{predicate.to_ntriples}" if list_heads.empty?
  lh = list_heads.first
  list = RDF::List.new(subject: lh, graph: queryable)
  raise LD::Patch::Error, "Invalid list" unless list.valid?

  start = case
  when slice1.nil? || slice1 == RDF.nil then list.length
  when slice1 < 0 then list.length + slice1.to_i
  else slice1.to_i
  end

  finish = case
  when slice2.nil? || slice2 == RDF.nil then list.length
  when slice2 < 0 then list.length + slice2.to_i
  else slice2.to_i
  end

  raise LD::Patch::Error.new("UpdateList slice indexes out of order #{start}..#{finish}}", code: 400) if finish < start
  
  length = finish - start
  raise LD::Patch::Error, "UpdateList out of bounds #{start}..#{finish}}" if start + length > list.length
  raise LD::Patch::Error, "UpdateList out of bounds #{start}..#{finish}}" if start < 0

  # Uses #[]= logic in RDF::List
  list[start, length] = collection
  new_lh = list.subject

  # If lh was rdf:nil, then we may have a new list head. Similarly, if the list was emptied, we now need to replace the head
  if lh != new_lh
    queryable.delete(RDF::Statement(var_or_iri, predicate, lh))
    queryable.insert(RDF::Statement(var_or_iri, predicate, new_lh))
  end

  bindings
end