solis 0.64.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +287 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/after_hooks.rb +24 -0
- data/examples/config.yml.template +15 -0
- data/examples/read_from_shacl.rb +22 -0
- data/examples/read_from_shacl_abv.rb +84 -0
- data/examples/read_from_sheet.rb +22 -0
- data/lib/solis/config_file.rb +91 -0
- data/lib/solis/error/cursor_error.rb +6 -0
- data/lib/solis/error/general_error.rb +6 -0
- data/lib/solis/error/invalid_attribute_error.rb +6 -0
- data/lib/solis/error/invalid_datatype_error.rb +6 -0
- data/lib/solis/error/not_found_error.rb +6 -0
- data/lib/solis/error/query_error.rb +6 -0
- data/lib/solis/error.rb +3 -0
- data/lib/solis/graph.rb +360 -0
- data/lib/solis/model.rb +565 -0
- data/lib/solis/options.rb +19 -0
- data/lib/solis/query/construct.rb +93 -0
- data/lib/solis/query/filter.rb +133 -0
- data/lib/solis/query/run.rb +97 -0
- data/lib/solis/query.rb +347 -0
- data/lib/solis/resource.rb +37 -0
- data/lib/solis/shape/data_types.rb +280 -0
- data/lib/solis/shape/reader/csv.rb +12 -0
- data/lib/solis/shape/reader/file.rb +16 -0
- data/lib/solis/shape/reader/sheet.rb +777 -0
- data/lib/solis/shape/reader/simple_sheets/sheet.rb +59 -0
- data/lib/solis/shape/reader/simple_sheets/worksheet.rb +173 -0
- data/lib/solis/shape/reader/simple_sheets.rb +40 -0
- data/lib/solis/shape.rb +189 -0
- data/lib/solis/sparql_adaptor.rb +318 -0
- data/lib/solis/store/sparql/client/query.rb +35 -0
- data/lib/solis/store/sparql/client.rb +41 -0
- data/lib/solis/version.rb +3 -0
- data/lib/solis.rb +13 -0
- data/solis.gemspec +50 -0
- metadata +304 -0
@@ -0,0 +1,318 @@
|
|
1
|
+
require 'graphiti'
|
2
|
+
module Solis
|
3
|
+
class SparqlAdaptor < Graphiti::Adapters::Abstract
|
4
|
+
def self.sideloading_classes
|
5
|
+
{
|
6
|
+
has_many: HasMany,
|
7
|
+
belongs_to: BelongsTo,
|
8
|
+
has_one: ::Graphiti::Sideload::HasOne,
|
9
|
+
many_to_many: ::Graphiti::Sideload::ManyToMany,
|
10
|
+
polymorphic_belongs_to: ::Graphiti::Sideload::PolymorphicBelongsTo
|
11
|
+
}
|
12
|
+
end
|
13
|
+
|
14
|
+
def base_scope(*scope)
|
15
|
+
types = ObjectSpace.each_object(Class).select { |klass| klass < self.resource.model}.map{|m| m.name.tableize.pluralize.to_sym}
|
16
|
+
types << self.resource.model.name.tableize.pluralize.to_sym if types.empty?
|
17
|
+
|
18
|
+
{ type: types, sort: {}, filters: {} }
|
19
|
+
rescue Exception => e
|
20
|
+
types = [self.resource.model.name.tableize.pluralize.to_sym]
|
21
|
+
{ type: types, sort: {}, filters: {} }
|
22
|
+
end
|
23
|
+
|
24
|
+
def paginate(scope, current, per)
|
25
|
+
scope.merge!(current_page: current, per_page: per)
|
26
|
+
end
|
27
|
+
|
28
|
+
def count(scope, attr)
|
29
|
+
count = self.resource.model.new().query.paging(scope).filter(scope).sort(scope).count
|
30
|
+
scope[attr] = count
|
31
|
+
end
|
32
|
+
|
33
|
+
def order(scope, att, dir)
|
34
|
+
scope[:sort].merge!({ att => dir })
|
35
|
+
scope
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.default_operators
|
39
|
+
{
|
40
|
+
string: [:eq, :not_eq, :contains],
|
41
|
+
lang_string: [:eq, :not_eq, :contains],
|
42
|
+
integer: [:eq, :not_eq, :gt, :lt],
|
43
|
+
float: [:eq, :not_eq, :gt, :lt],
|
44
|
+
big_decimal: [:eq, :not_eq, :gt, :lt],
|
45
|
+
date: [:eq, :not_eq, :gt, :lt],
|
46
|
+
boolean: [:eq, :not_eq],
|
47
|
+
uuid: [:eq, :not_eq],
|
48
|
+
enum: [:eq],
|
49
|
+
datetime: [:eq, :not_eq, :gt, :lt],
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def filter(scope, attribute, value, is_not = false, operator = '=')
|
55
|
+
scope[:filters][attribute] = {value: value, operator: operator, is_not: is_not}
|
56
|
+
scope
|
57
|
+
end
|
58
|
+
|
59
|
+
alias :filter_eq :filter
|
60
|
+
alias :filter_string_eq :filter
|
61
|
+
alias :filter_integer_eq :filter
|
62
|
+
alias :filter_float_eq :filter
|
63
|
+
alias :filter_big_decimal_eq :filter
|
64
|
+
alias :filter_date_eq :filter
|
65
|
+
alias :filter_boolean_eq :filter
|
66
|
+
alias :filter_uuid_eq :filter
|
67
|
+
alias :filter_enum_eq :filter
|
68
|
+
alias :filter_datetime_eq :filter
|
69
|
+
alias :filter_lang_string_eq :filter
|
70
|
+
|
71
|
+
def filter_not_eq(scope, attribute, value)
|
72
|
+
filter_eq(scope, attribute, value, true, '=')
|
73
|
+
end
|
74
|
+
|
75
|
+
alias :filter_string_not_eq :filter_not_eq
|
76
|
+
alias :filter_integer_not_eq :filter_not_eq
|
77
|
+
alias :filter_float_not_eq :filter_not_eq
|
78
|
+
alias :filter_big_decimal_not_eq :filter_not_eq
|
79
|
+
alias :filter_date_not_eq :filter_not_eq
|
80
|
+
alias :filter_boolean_not_eq :filter_not_eq
|
81
|
+
alias :filter_uuid_not_eq :filter_not_eq
|
82
|
+
alias :filter_enum_not_eq :filter_not_eq
|
83
|
+
alias :filter_datetime_not_eq :filter_not_eq
|
84
|
+
alias :filter_lang_string_not_eq :filter_not_eq
|
85
|
+
|
86
|
+
def filter_contains(scope, attribute, value)
|
87
|
+
filter_eq(scope, attribute, value, false, '~')
|
88
|
+
end
|
89
|
+
|
90
|
+
alias :filter_string_contains :filter_contains
|
91
|
+
alias :filter_lang_string_contains :filter_contains
|
92
|
+
|
93
|
+
def filter_gt(scope, attribute, value)
|
94
|
+
filter_eq(scope, attribute, value, false, '>')
|
95
|
+
end
|
96
|
+
|
97
|
+
alias :filter_string_gt :filter_gt
|
98
|
+
alias :filter_integer_gt :filter_gt
|
99
|
+
alias :filter_float_gt :filter_gt
|
100
|
+
alias :filter_big_decimal_gt :filter_gt
|
101
|
+
alias :filter_date_gt :filter_gt
|
102
|
+
alias :filter_boolean_gt :filter_gt
|
103
|
+
alias :filter_uuid_gt :filter_gt
|
104
|
+
alias :filter_enum_gt :filter_gt
|
105
|
+
alias :filter_datetime_gt :filter_gt
|
106
|
+
|
107
|
+
def filter_not_gt(scope, attribute, value)
|
108
|
+
filter_eq(scope, attribute, value, true, '>')
|
109
|
+
end
|
110
|
+
|
111
|
+
alias :filter_string_not_gt :filter_not_gt
|
112
|
+
alias :filter_integer_not_gt :filter_not_gt
|
113
|
+
alias :filter_float_not_gt :filter_not_gt
|
114
|
+
alias :filter_big_decimal_not_gt :filter_not_gt
|
115
|
+
alias :filter_date_not_gt :filter_not_gt
|
116
|
+
alias :filter_boolean_not_gt :filter_not_gt
|
117
|
+
alias :filter_uuid_not_gt :filter_not_gt
|
118
|
+
alias :filter_enum_not_gt :filter_not_gt
|
119
|
+
alias :filter_datetime_not_gt :filter_not_gt
|
120
|
+
|
121
|
+
def filter_lt(scope, attribute, value)
|
122
|
+
filter_eq(scope, attribute, value, false, '<')
|
123
|
+
end
|
124
|
+
|
125
|
+
alias :filter_string_lt :filter_lt
|
126
|
+
alias :filter_integer_lt :filter_lt
|
127
|
+
alias :filter_float_lt :filter_lt
|
128
|
+
alias :filter_big_decimal_lt :filter_lt
|
129
|
+
alias :filter_date_lt :filter_lt
|
130
|
+
alias :filter_boolean_lt :filter_lt
|
131
|
+
alias :filter_uuid_lt :filter_lt
|
132
|
+
alias :filter_enum_lt :filter_lt
|
133
|
+
alias :filter_datetime_lt :filter_lt
|
134
|
+
|
135
|
+
def filter_not_lt(scope, attribute, value)
|
136
|
+
filter_eq(scope, attribute, value, true, '<')
|
137
|
+
end
|
138
|
+
|
139
|
+
alias :filter_string_not_lt :filter_not_lt
|
140
|
+
alias :filter_integer_not_lt :filter_not_lt
|
141
|
+
alias :filter_float_not_lt :filter_not_lt
|
142
|
+
alias :filter_big_decimal_not_lt :filter_not_lt
|
143
|
+
alias :filter_date_not_lt :filter_not_lt
|
144
|
+
alias :filter_boolean_not_lt :filter_not_lt
|
145
|
+
alias :filter_uuid_not_lt :filter_not_lt
|
146
|
+
alias :filter_enum_not_lt :filter_not_lt
|
147
|
+
alias :filter_datetime_not_lt :filter_not_lt
|
148
|
+
|
149
|
+
def transaction(*)
|
150
|
+
yield
|
151
|
+
end
|
152
|
+
|
153
|
+
# def destroy(model_instance)
|
154
|
+
# super
|
155
|
+
# end
|
156
|
+
|
157
|
+
# def save(model_instance)
|
158
|
+
# pp model_instance
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
# def build(model_class)
|
162
|
+
# model_class.new
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# def assign_attributes(model_instance, attributes)
|
166
|
+
# attributes.each_pair do |key, value|
|
167
|
+
# model_instance.send(:"#{key}=", value)
|
168
|
+
# end
|
169
|
+
# end
|
170
|
+
|
171
|
+
# def associate(parent, child, association_name, association_type)
|
172
|
+
# pp parent, children, association_name, association_type
|
173
|
+
# super
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# def associate_all(parent, children, association_name, association_type)
|
177
|
+
# pp parent, children, association_name, association_type
|
178
|
+
# super
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# def disassociate(parent, child, association_name, association_type)
|
182
|
+
# pp parent, children, association_name, association_type
|
183
|
+
# super
|
184
|
+
# end
|
185
|
+
|
186
|
+
def resolve(scope)
|
187
|
+
self.resource.model.before_read_proc&.call(scope)
|
188
|
+
query = self.resource.model.new().query.paging(scope).filter(scope).sort(scope)
|
189
|
+
data = query.find_all.map { |m|
|
190
|
+
m
|
191
|
+
}
|
192
|
+
self.resource.model.after_read_proc&.call(data)
|
193
|
+
data
|
194
|
+
end
|
195
|
+
|
196
|
+
# def associate_all(parent, children, association_name, association_type)
|
197
|
+
# children.each do |c|
|
198
|
+
# associate(parent, c, association_name, association_type)
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
|
202
|
+
# geeft fout als associate super gebruikt wordt
|
203
|
+
# http://127.0.0.1:9292/autocirculaties?filter%5Bgebruiker_id%5D%5Beq%5D=1221&include=uitleenformaat,wat_uitlenen
|
204
|
+
def associate(parent, child, association_name, association_type)
|
205
|
+
if activerecord_associate?(parent, child, association_name)
|
206
|
+
activerecord_adapter.associate \
|
207
|
+
parent, child, association_name, association_type
|
208
|
+
elsif [:has_many, :many_to_many].include?(association_type)
|
209
|
+
if parent.send(:"#{association_name}").nil?
|
210
|
+
parent.send(:"#{association_name}=", [child])
|
211
|
+
else
|
212
|
+
parent_child_data = parent.send(:"#{association_name}")
|
213
|
+
|
214
|
+
if parent_child_data.is_a?(Array)
|
215
|
+
parent_child_data = parent_child_data.map do |m|
|
216
|
+
m.id.eql?(child.id) ? child : m
|
217
|
+
end
|
218
|
+
else
|
219
|
+
if parent_child_data.id.eql?(child.id)
|
220
|
+
parent_child_data = [child]
|
221
|
+
# else
|
222
|
+
# parent_child_data = nil
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
parent.send(:"#{association_name}=", parent_child_data)
|
227
|
+
#parent.send(:"#{association_name}") << child
|
228
|
+
end
|
229
|
+
else
|
230
|
+
parent_child_data = parent.send(:"#{association_name}")
|
231
|
+
|
232
|
+
if parent_child_data.is_a?(Array)
|
233
|
+
parent_child_data = parent_child_data.map do |m|
|
234
|
+
m.id.eql?(child.id) ? child : m
|
235
|
+
end
|
236
|
+
else
|
237
|
+
if parent_child_data&.id.eql?(child.id)
|
238
|
+
parent_child_data = [child]
|
239
|
+
else
|
240
|
+
parent_child_data = nil
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
parent.send(:"#{association_name}=", parent_child_data)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
class BelongsTo < Graphiti::Sideload::BelongsTo
|
250
|
+
def load_params(parents, query)
|
251
|
+
query.hash.tap do |hash|
|
252
|
+
hash[:filter] ||= {}
|
253
|
+
unless hash[:filter].include?(:id)
|
254
|
+
all_ids = parents.map{|m| m.instance_variable_get("@#{query.association_name.to_s}")}.flatten.map{|m| m.instance_variable_get("@#{primary_key}")}.uniq.compact.join(',')
|
255
|
+
|
256
|
+
hash[:filter].merge!({primary_key => all_ids})
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
private
|
262
|
+
|
263
|
+
# relations are included here
|
264
|
+
def children_for(parent, map)
|
265
|
+
map.values
|
266
|
+
end
|
267
|
+
|
268
|
+
# def child_map(children)
|
269
|
+
# children.index_by(&primary_key)
|
270
|
+
# end
|
271
|
+
#
|
272
|
+
# def children_for(parent, map)
|
273
|
+
# fk = parent.send(name).send(foreign_key) rescue nil #TODO: this is bad
|
274
|
+
# children = map[fk]
|
275
|
+
# return children if children
|
276
|
+
#
|
277
|
+
# keys = map.keys
|
278
|
+
# if fk.is_a?(String) && keys[0].is_a?(Integer)
|
279
|
+
# fk = fk.to_i
|
280
|
+
# elsif fk.is_a?(Integer) && keys[0].is_a?(String)
|
281
|
+
# fk = fk.to_s
|
282
|
+
# end
|
283
|
+
# map[fk] || []
|
284
|
+
# end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
class HasMany < Graphiti::Sideload::HasMany
|
289
|
+
def inverse_filter
|
290
|
+
@inverse_filter || foreign_key
|
291
|
+
end
|
292
|
+
|
293
|
+
def load_params(parents, query)
|
294
|
+
query.hash.tap do |hash|
|
295
|
+
hash[:filter] ||= {}
|
296
|
+
unless hash[:filter].include?(:id)
|
297
|
+
all_ids = parents.map{|m| m.instance_variable_get("@#{query.association_name.to_s}")}.flatten.map{|m| m.instance_variable_get("@#{primary_key}")}.uniq.compact.join(',')
|
298
|
+
|
299
|
+
hash[:filter].merge!({primary_key => all_ids})
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def children_for(parent, map)
|
305
|
+
map.values.flatten
|
306
|
+
end
|
307
|
+
|
308
|
+
def link_filter(parents)
|
309
|
+
{inverse_filter => parent_filter(parents)}
|
310
|
+
end
|
311
|
+
|
312
|
+
private
|
313
|
+
|
314
|
+
def parent_filter(parents)
|
315
|
+
ids_for_parents(parents).join(",")
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Solis
|
2
|
+
module Store
|
3
|
+
module Sparql
|
4
|
+
class Client
|
5
|
+
class Query
|
6
|
+
def initialize(client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def run(query)
|
11
|
+
result = @client.query(query)
|
12
|
+
|
13
|
+
if is_construct?(query)
|
14
|
+
repository = RDF::Repository.new
|
15
|
+
result.each { |s| repository << [s[:s], s[:p], s[:o]] }
|
16
|
+
result = SPARQL::Client.new(repository)
|
17
|
+
end
|
18
|
+
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def is_construct?(query)
|
25
|
+
query =~ /construct/i
|
26
|
+
end
|
27
|
+
|
28
|
+
def is_insert?(query)
|
29
|
+
query =~ /insert/i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'http'
|
2
|
+
require 'connection_pool'
|
3
|
+
require 'sparql'
|
4
|
+
require_relative 'client/query'
|
5
|
+
|
6
|
+
module Solis
|
7
|
+
module Store
|
8
|
+
module Sparql
|
9
|
+
class Client
|
10
|
+
def initialize(endpoint, graph_name)
|
11
|
+
@endpoint = endpoint
|
12
|
+
@graph_name = graph_name
|
13
|
+
|
14
|
+
@pool = ConnectionPool.new(size:5, timeout: 60) do
|
15
|
+
SPARQL::Client.new(@endpoint, graph: @graph_name)
|
16
|
+
#SPARQL::Client.new(@endpoint)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def up?
|
21
|
+
result = nil
|
22
|
+
@pool.with do |c|
|
23
|
+
result = c.query("ASK WHERE { ?s ?p ?o }")
|
24
|
+
end
|
25
|
+
result
|
26
|
+
rescue HTTP::Error => e
|
27
|
+
return false
|
28
|
+
end
|
29
|
+
|
30
|
+
def query(query)
|
31
|
+
raise Solis::Error::NotFoundError, "Server or graph(#{@graph_name} not found" unless up?
|
32
|
+
result = nil
|
33
|
+
@pool.with do |c|
|
34
|
+
result = Query.new(c).run(query)
|
35
|
+
end
|
36
|
+
result
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/solis.rb
ADDED
data/solis.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require_relative 'lib/solis/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'solis'
|
5
|
+
spec.version = Solis::VERSION
|
6
|
+
spec.authors = ['Mehmet Celik']
|
7
|
+
spec.email = ['mehmet@celik.be']
|
8
|
+
|
9
|
+
spec.summary = 'Creates a SHACL, RDF, PlantUML file from a Google sheet and a layer ontop of a data store(RDBMS, Triple store)'
|
10
|
+
spec.description = 'The SUN in latin or is it SILOS spelled backwards. Creates a SHACL, RDF, PlantUML file from a Google sheet and a layer ontop of a data store(RDBMS, Triple store)'
|
11
|
+
spec.homepage = 'https://github.com/mehmetc/solis'
|
12
|
+
spec.license = 'MIT'
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
|
14
|
+
|
15
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
16
|
+
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
18
|
+
spec.metadata['source_code_uri'] = 'https://github.com/mehmetc/solis'
|
19
|
+
spec.metadata['changelog_uri'] = 'https://github.com/mehmetc/solis'
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
24
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
end
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_runtime_dependency 'activesupport', '~> 6.1'
|
31
|
+
spec.add_runtime_dependency 'http', '~> 5.1'
|
32
|
+
spec.add_runtime_dependency 'graphiti', '~> 1.3'
|
33
|
+
spec.add_runtime_dependency 'moneta', '~> 1.4'
|
34
|
+
spec.add_runtime_dependency 'linkeddata', '~> 3.2'
|
35
|
+
spec.add_runtime_dependency 'google_drive', '~> 3.0'
|
36
|
+
spec.add_runtime_dependency 'json', '~> 2.5'
|
37
|
+
spec.add_runtime_dependency 'hashdiff', '~> 1.0'
|
38
|
+
spec.add_runtime_dependency 'iso8601', '~> 0.13.0'
|
39
|
+
spec.add_runtime_dependency 'connection_pool', '~> 2.2.5'
|
40
|
+
spec.add_runtime_dependency 'uuidtools', '~> 2.2.0'
|
41
|
+
spec.add_runtime_dependency 'dry-struct', '~> 1.2'
|
42
|
+
spec.add_runtime_dependency 'psych', '< 4'
|
43
|
+
|
44
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
45
|
+
spec.add_development_dependency 'minitest', '~> 5.15.0'
|
46
|
+
|
47
|
+
# spec.add_development_dependency 'rubocop'
|
48
|
+
|
49
|
+
# spec.add_development_dependency 'webmock'
|
50
|
+
end
|