Class: Solis::Query

Inherits:
Object
  • Object
show all
Includes:
Enumerable, QueryFilter
Defined in:
lib/solis/query.rb,
lib/solis/query/construct.rb

Defined Under Namespace

Classes: Construct, Runner

Class Method Summary collapse

Instance Method Summary collapse

Methods included from QueryFilter

#filter

Constructor Details

#initialize(model) ⇒ Query

Returns a new instance of Query.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/solis/query.rb', line 85

def initialize(model)
  @construct_cache = File.absolute_path(Solis::Options.instance.get[:cache])
  @model = model
  @shapes = @model.class.shapes
  @metadata = @model.class.
  @sparql_endpoint = @model.class.sparql_endpoint
  if Solis::Options.instance.get.key?(:graphs) && Solis::Options.instance.get[:graphs].size > 0
    @sparql_client = Solis::Store::Sparql::Client.new(@sparql_endpoint)
  else
    @sparql_client = Solis::Store::Sparql::Client.new(@sparql_endpoint, graph: @model.class.graph_name)
  end
  @filter = {values: ["VALUES ?type {#{target_class}}"], concepts: ['?concept a ?type .'] }
  @sort = 'ORDER BY ?concept'
  @sort_select = ''
  @language = Graphiti.context[:object]&.language || Solis::Options.instance.get[:language] || 'en'
  @query_cache = self.class.shared_query_cache
end

Class Method Details

.graph_nameObject



57
58
59
# File 'lib/solis/query.rb', line 57

def self.graph_name
  Solis::Options.instance.get.key?(:graphs) ? Solis::Options.instance.get[:graphs].select{|s| s['type'].eql?(:main)}&.first['name'] : ''
end

.invalidate_cache_for(model_class_name, cache_dir = nil) ⇒ Object

Invalidate all cached query results for a given model type.



73
74
75
76
77
78
79
80
81
82
83
# File 'lib/solis/query.rb', line 73

def self.invalidate_cache_for(model_class_name, cache_dir = nil)
  cache = shared_query_cache
  tag_key = "TAG:#{model_class_name}"
  if cache.key?(tag_key)
    cache[tag_key].each { |key| cache.delete(key) }
    cache.delete(tag_key)
    Solis::LOGGER.info("CACHE: invalidated entries for #{model_class_name}") if ConfigFile[:debug]
  end
rescue StandardError => e
  Solis::LOGGER.warn("CACHE: invalidation failed for #{model_class_name}: #{e.message}")
end

.reset_shared_query_cache!Object

Reset the shared cache (useful when config changes, e.g., in tests)



68
69
70
# File 'lib/solis/query.rb', line 68

def self.reset_shared_query_cache!
  @shared_query_cache = nil
end

.run(entity, query, options = {}) ⇒ Object



14
15
16
# File 'lib/solis/query.rb', line 14

def self.run(entity, query, options = {})
  Solis::Query::Runner.run(entity, query, options)
end

.run_construct(query, id_name, entity, ids, from_cache = '1') ⇒ Object



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
# File 'lib/solis/query.rb', line 27

def self.run_construct(query, id_name, entity, ids, from_cache = '1')
  raise 'Please supply one or more uuid\'s' if ids.nil? || ids.empty?

  result = {}

  key = uuid("#{entity}-#{ids}")

  if result.nil? || result.empty? || (from_cache.eql?('0'))
    ids = ids.split(',') if ids.is_a?(String)
    ids = [ids] unless ids.is_a?(Array)
    ids = ids.map do |m|
      if URI(m).class.eql?(URI::Generic)
        "<#{graph_name}#{entity.tableize}/#{m}>"
      else
        "<#{m}>"
      end
    end
    ids = ids.join(" ")

    language = Graphiti.context[:object]&.language || Solis::Options.instance.get[:language] || 'en'
    q = query.gsub(/{ ?{ ?VALUES ?} ?}/, "VALUES ?#{id_name} { #{ids} }").gsub(/{ ?{ ?LANGUAGE ?} ?}/, "bind(\"#{language}\" as ?filter_language).").gsub(/{ ?{ ?ENTITY ?} ?}/, "<#{graph_name}#{entity.classify}>")

    result = Solis::Query.run(entity, q)
  end
  result
rescue StandardError => e
  puts e.message
  raise e
end

.run_construct_with_file(filename, id_name, entity, ids, from_cache = '1') ⇒ Object



18
19
20
21
# File 'lib/solis/query.rb', line 18

def self.run_construct_with_file(filename, id_name, entity, ids, from_cache = '1')
  f = File.read(filename)
  run_construct(f, id_name, entity, ids, from_cache)
end

.shared_query_cacheObject

Shared class-level query cache to ensure consistent reads/writes/invalidations



62
63
64
65
# File 'lib/solis/query.rb', line 62

def self.shared_query_cache
  cache_dir = File.absolute_path(Solis::Options.instance.get[:cache])
  @shared_query_cache ||= Moneta.new(:HashFile, dir: cache_dir)
end

.uuid(key) ⇒ Object



23
24
25
# File 'lib/solis/query.rb', line 23

def self.uuid(key)
  UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, key).to_s
end

Instance Method Details

#countObject



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/solis/query.rb', line 144

def count
  sparql_client = @sparql_client
  if model_construct?
    sparql_client = Solis::Query::Construct.new(@model).run
  end

  relationship = ''
  core_query = core_query(relationship)
  count_query = core_query.gsub(/SELECT .* WHERE/, 'SELECT (COUNT(distinct ?concept) as ?count) WHERE')

  # count_query = count_query.split('a ?type')[0]+'a ?type }'
  result = sparql_client.query(count_query)
  solution = result.first
  solution.nil? ? 0 : solution[:count].object || 0
end

#each(&block) ⇒ Object



103
104
105
106
107
108
109
110
111
# File 'lib/solis/query.rb', line 103

def each(&block)
  data = query
  return unless data.methods.include?(:each)
  data.each(&block)
rescue StandardError => e
  message = "Unable to get next record: #{e.message}"
  LOGGER.error(message)
  raise Error::CursorError, message
end

#paging(params = {}) ⇒ Object



134
135
136
137
138
139
140
141
142
# File 'lib/solis/query.rb', line 134

def paging(params = {})
  current_page = params[:current_page] || 1
  per_page = params[:per_page] || 10

  @offset = 0
  @offset = (current_page - 1) * per_page if current_page > 1
  @limit = per_page
  self
end

#sort(params) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/solis/query.rb', line 113

def sort(params)
  @sort = ''
  @sort_select = ''
  if params.key?(:sort)
    i = 0
    params[:sort].each do |attribute, direction|
      path = @model.class.[:attributes][attribute.to_s][:path]
      @sort_select += "optional {\n" if @model.class.[:attributes][attribute.to_s][:mincount] == 0
      @sort_select += "?concept <#{path}> ?__#{attribute} . "
      @sort_select += "}\n" if @model.class.[:attributes][attribute.to_s][:mincount] == 0
      @sort += ',' if i.positive?
      @sort += "#{direction.to_s.upcase}(?__#{attribute})"
      i += 1
    end

    @sort = "ORDER BY #{@sort}" if i.positive?
  end

  self
end