solis 0.70.0 → 0.72.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/solis/config_file.rb +6 -1
- data/lib/solis/graph.rb +8 -0
- data/lib/solis/model.rb +71 -23
- data/lib/solis/query/filter.rb +7 -2
- data/lib/solis/query.rb +2 -2
- data/lib/solis/shape/reader/sheet.rb +237 -377
- data/lib/solis/shape.rb +3 -0
- data/lib/solis/version.rb +1 -1
- data/solis.gemspec +9 -8
- metadata +21 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa7c729b1acbe8c1881ebf3cc00ac228830bf04d269447f55b2f029c7eef703c
|
4
|
+
data.tar.gz: 81ceb99f9f6284b8c4163bfe4d263f6703edbe1733eb42fcc6c31530be2c8d91
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a5fe949952a2931c1189644690446ddc0b63ca719eb2f4b15f5cab83779d81b50872c3b57d4b677278cc4c6ca1e54ff8f14ff4b8c09ce842e8e5a3226835177
|
7
|
+
data.tar.gz: 03af55e0505d6e987522e8d799450be43a83b9968c60f7741b7c5bb2d75f0874d7d127b955f31ad028a35b2993b2ecdefb91653edf5e9941c4e7dfc796658696
|
data/lib/solis/config_file.rb
CHANGED
@@ -51,12 +51,17 @@ class ConfigFile
|
|
51
51
|
@config
|
52
52
|
end
|
53
53
|
|
54
|
+
def self.keys
|
55
|
+
init
|
56
|
+
@config.keys
|
57
|
+
end
|
58
|
+
|
54
59
|
private
|
55
60
|
|
56
61
|
def self.init
|
57
62
|
discover_config_file_path
|
58
63
|
if @config.empty?
|
59
|
-
config = YAML::load_file("#{path}/#{name}")
|
64
|
+
config = YAML::load_file("#{path}/#{name}", aliases: true)
|
60
65
|
@config = process(config)
|
61
66
|
end
|
62
67
|
end
|
data/lib/solis/graph.rb
CHANGED
@@ -79,6 +79,9 @@ module Solis
|
|
79
79
|
unless @inflections.nil?
|
80
80
|
raise "Inflection file not found #{File.absolute_path(@inflections)}" unless File.exist?(@inflections)
|
81
81
|
JSON.parse(File.read(@inflections)).each do |s, p|
|
82
|
+
raise "No plural found" if s.nil? && p.nil?
|
83
|
+
raise "No plural found for #{p}" if s.nil?
|
84
|
+
raise "No plural found for #{s}" if p.nil?
|
82
85
|
ActiveSupport::Inflector.inflections.irregular(s, p)
|
83
86
|
end
|
84
87
|
end
|
@@ -89,6 +92,7 @@ module Solis
|
|
89
92
|
LOGGER.warn("Dangling entity found #{_[:target_class].to_s} removing")
|
90
93
|
next
|
91
94
|
end
|
95
|
+
#@shapes[shape_name][:attributes].select { |_, metadata| metadata.key?(:node_kind) && !metadata[:node_kind].nil? }.values.map { |m| m[:datatype].to_s.split('#').last }
|
92
96
|
@shapes[shape_name][:attributes].select { |_, metadata| metadata.key?(:node_kind) && !metadata[:node_kind].nil? }.values.map { |m| m[:datatype].to_s }
|
93
97
|
end
|
94
98
|
shape_keys += @shapes.keys
|
@@ -221,6 +225,10 @@ module Solis
|
|
221
225
|
relations.each_key do |k|
|
222
226
|
next if relations[k][:node_kind].is_a?(RDF::URI) && relations[k][:class].value.gsub(@graph_name, '').gsub('Shape', '').eql?(shape_name)
|
223
227
|
relation_shape = relations[k][:class].value.gsub(@graph_name, '').gsub('Shape', '')
|
228
|
+
if relation_shape =~ /\//
|
229
|
+
relation_shape = relations[k][:class].value.split('/').last.gsub('Shape','')
|
230
|
+
end
|
231
|
+
|
224
232
|
shape_as_resource(relation_shape, stack_level << relation_shape) unless stack_level.include?(relation_shape)
|
225
233
|
end
|
226
234
|
|
data/lib/solis/model.rb
CHANGED
@@ -108,30 +108,49 @@ module Solis
|
|
108
108
|
|
109
109
|
def destroy
|
110
110
|
raise "I need a SPARQL endpoint" if self.class.sparql_endpoint.nil?
|
111
|
-
before_delete_proc&.call(self)
|
112
|
-
|
113
111
|
sparql = SPARQL::Client.new(self.class.sparql_endpoint)
|
114
|
-
graph = as_graph(klass = self, resolve_all = false)
|
115
|
-
Solis::LOGGER.info graph.dump(:ttl) if ConfigFile[:debug]
|
116
112
|
|
117
|
-
|
113
|
+
raise Solis::Error::QueryError, "#{self.id} is still referenced, refusing to delete" if is_referenced?(sparql)
|
114
|
+
#sparql.query('delete{}')
|
115
|
+
before_delete_proc&.call(self)
|
116
|
+
# graph = as_graph(self, false)
|
117
|
+
# Solis::LOGGER.info graph.dump(:ttl) if ConfigFile[:debug]
|
118
|
+
|
119
|
+
query = %(
|
120
|
+
with <#{self.class.graph_name}>
|
121
|
+
delete {?s ?p ?o}
|
122
|
+
where {
|
123
|
+
values ?s {<#{self.graph_id}>}
|
124
|
+
?s ?p ?o }
|
125
|
+
)
|
126
|
+
result = sparql.query(query)
|
127
|
+
|
128
|
+
# result = sparql.delete_data(graph, graph: graph.name)
|
118
129
|
after_delete_proc&.call(result)
|
119
130
|
result
|
120
131
|
end
|
121
132
|
|
122
133
|
def save(validate_dependencies = true)
|
123
134
|
raise "I need a SPARQL endpoint" if self.class.sparql_endpoint.nil?
|
135
|
+
sparql = SPARQL::Client.new(self.class.sparql_endpoint)
|
124
136
|
|
125
137
|
before_create_proc&.call(self)
|
126
|
-
sparql = SPARQL::Client.new(self.class.sparql_endpoint)
|
127
|
-
graph = as_graph(self, validate_dependencies)
|
128
138
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
139
|
+
if exists?(sparql)
|
140
|
+
data = Model.properties_to_hash(self)
|
141
|
+
|
142
|
+
result = update(data)
|
143
|
+
else
|
144
|
+
graph = as_graph(self, validate_dependencies)
|
145
|
+
|
146
|
+
# File.open('/Users/mehmetc/Dropbox/AllSources/LP/graphiti-api/save.ttl', 'wb') do |file|
|
147
|
+
# file.puts graph.dump(:ttl)
|
148
|
+
# end
|
149
|
+
Solis::LOGGER.info SPARQL::Client::Update::InsertData.new(graph, graph: graph.name).to_s if ConfigFile[:debug]
|
150
|
+
|
151
|
+
result = sparql.insert_data(graph, graph: graph.name)
|
152
|
+
end
|
133
153
|
|
134
|
-
result = sparql.insert_data(graph, graph: graph.name)
|
135
154
|
after_create_proc&.call(result)
|
136
155
|
result
|
137
156
|
rescue StandardError => e
|
@@ -144,7 +163,7 @@ module Solis
|
|
144
163
|
raise Solis::Error::GeneralError, "I need a SPARQL endpoint" if self.class.sparql_endpoint.nil?
|
145
164
|
|
146
165
|
attributes = data.include?('attributes') ? data['attributes'] : data
|
147
|
-
raise "id is mandatory
|
166
|
+
raise "id is mandatory when updating" unless attributes.keys.include?('id')
|
148
167
|
|
149
168
|
id = attributes.delete('id')
|
150
169
|
|
@@ -155,14 +174,12 @@ module Solis
|
|
155
174
|
updated_klass = original_klass.deep_dup
|
156
175
|
|
157
176
|
attributes.each_pair do |key, value|
|
158
|
-
updated_klass.
|
177
|
+
updated_klass.instance_variable_set("@#{key}", value)
|
159
178
|
end
|
160
179
|
|
161
180
|
before_update_proc&.call(original_klass, updated_klass)
|
162
181
|
|
163
182
|
delete_graph = as_graph(original_klass, false)
|
164
|
-
# where_graph = RDF::Graph.new
|
165
|
-
# where_graph.name = RDF::URI(self.class.graph_name)
|
166
183
|
|
167
184
|
where_graph = RDF::Graph.new(graph_name: RDF::URI("#{self.class.graph_name}#{self.name.tableize}/#{id}"), data: RDF::Repository.new)
|
168
185
|
|
@@ -176,16 +193,16 @@ module Solis
|
|
176
193
|
|
177
194
|
insert_graph = as_graph(updated_klass, true)
|
178
195
|
|
179
|
-
|
180
|
-
|
181
|
-
|
196
|
+
puts delete_graph.dump(:ttl) #if ConfigFile[:debug]
|
197
|
+
puts insert_graph.dump(:ttl) #if ConfigFile[:debug]
|
198
|
+
puts where_graph.dump(:ttl) #if ConfigFile[:debug]
|
182
199
|
|
183
200
|
#if ConfigFile[:debug]
|
184
201
|
delete_insert_query = SPARQL::Client::Update::DeleteInsert.new(delete_graph, insert_graph, where_graph, graph: insert_graph.name).to_s
|
185
202
|
delete_insert_query.gsub!('_:p', '?p')
|
186
|
-
|
203
|
+
puts delete_insert_query
|
187
204
|
data = sparql.query(delete_insert_query)
|
188
|
-
pp data
|
205
|
+
#pp data
|
189
206
|
#end
|
190
207
|
|
191
208
|
# sparql.delete_insert(delete_graph, insert_graph, where_graph, graph: insert_graph.name)
|
@@ -207,10 +224,23 @@ module Solis
|
|
207
224
|
raise e
|
208
225
|
end
|
209
226
|
|
227
|
+
def graph_id
|
228
|
+
"#{self.class.graph_name}#{self.name.tableize}/#{self.id}"
|
229
|
+
end
|
230
|
+
|
231
|
+
def is_referenced?(sparql)
|
232
|
+
sparql.query("ASK WHERE { ?s ?p <#{self.graph_id}>. filter (!contains(str(?p), '_audit'))}")
|
233
|
+
end
|
234
|
+
|
235
|
+
def exists?(sparql)
|
236
|
+
sparql.query("ASK WHERE { <#{self.graph_id}> ?p ?o }")
|
237
|
+
end
|
238
|
+
|
210
239
|
def self.make_id_for(model)
|
211
240
|
id = model.instance_variable_get("@id")
|
212
241
|
if id.nil? || (id.is_a?(String) && id&.empty?)
|
213
|
-
|
242
|
+
id = SecureRandom.uuid
|
243
|
+
model.instance_variable_set("@id", id)
|
214
244
|
end
|
215
245
|
model
|
216
246
|
end
|
@@ -410,7 +440,7 @@ module Solis
|
|
410
440
|
data = [data] unless data.is_a?(Array)
|
411
441
|
|
412
442
|
data.each do |d|
|
413
|
-
if defined?(d.name) && self.class.graph.shape?(d.name)
|
443
|
+
if defined?(d.name) && self.class.graph.shape?(d.name) && resolve_all
|
414
444
|
if self.class.graph.shape_as_model(d.name.to_s).metadata[:attributes].select { |_, v| v[:node_kind].is_a?(RDF::URI) }.size > 0 &&
|
415
445
|
hierarchy.select { |s| s =~ /^#{d.name.to_s}/ }.size == 0
|
416
446
|
internal_resolve = false
|
@@ -422,6 +452,8 @@ module Solis
|
|
422
452
|
#d = "#{klass.class.graph_name}#{attribute.tableize}/#{d.id}"
|
423
453
|
d = "#{klass.class.graph_name}#{d.name.tableize}/#{d.id}"
|
424
454
|
end
|
455
|
+
elsif defined?(d.name) && self.class.graph.shape?(d.name)
|
456
|
+
d = "#{klass.class.graph_name}#{d.name.tableize}/#{d.id}"
|
425
457
|
end
|
426
458
|
|
427
459
|
if d.is_a?(Array) && d.length == 1
|
@@ -573,5 +605,21 @@ module Solis
|
|
573
605
|
hierarchy.pop
|
574
606
|
id
|
575
607
|
end
|
608
|
+
|
609
|
+
def self.properties_to_hash(model)
|
610
|
+
n = {}
|
611
|
+
model.class.metadata[:attributes].each_key do |m|
|
612
|
+
if model.instance_variable_get("@#{m}").is_a?(Array)
|
613
|
+
n[m] = model.instance_variable_get("@#{m}").map { |iv| iv.class.ancestors.include?(Solis::Model) ? properties_to_hash(iv) : iv }
|
614
|
+
elsif model.instance_variable_get("@#{m}").class.ancestors.include?(Solis::Model)
|
615
|
+
n[m] = properties_to_hash(model.instance_variable_get("@#{m}"))
|
616
|
+
else
|
617
|
+
n[m] = model.instance_variable_get("@#{m}")
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
n.compact!
|
622
|
+
n
|
623
|
+
end
|
576
624
|
end
|
577
625
|
end
|
data/lib/solis/query/filter.rb
CHANGED
@@ -101,8 +101,13 @@ module Solis
|
|
101
101
|
value[:value].each do |v|
|
102
102
|
if metadata[:datatype_rdf].eql?('http://www.w3.org/1999/02/22-rdf-syntax-ns#langString')
|
103
103
|
filter = "?concept <#{metadata[:path]}> ?__search#{i} "
|
104
|
-
|
105
|
-
|
104
|
+
if v.is_a?(Hash)
|
105
|
+
filter += "FILTER(langMatches( lang(?__search#{i}), \"#{v[:"@language"]}\" )). "
|
106
|
+
search_for = v[:"@value"].is_a?(Array) ? v[:"@value"].first : v[:"@value"]
|
107
|
+
else
|
108
|
+
search_for = v
|
109
|
+
end
|
110
|
+
|
106
111
|
search_for = normalize_string(search_for)
|
107
112
|
filter += "FILTER(str(?__search#{i}) #{not_operator}#{value[:operator]} \"#{search_for}\"#{datatype}) .\n"
|
108
113
|
else
|
data/lib/solis/query.rb
CHANGED
@@ -43,8 +43,8 @@ module Solis
|
|
43
43
|
end
|
44
44
|
ids = ids.join(" ")
|
45
45
|
|
46
|
-
|
47
|
-
q = query.gsub(/{ ?{ ?VALUES ?} ?}/, "VALUES ?#{id_name} { #{ids} }")
|
46
|
+
language = Graphiti.context[:object]&.language || Solis::Options.instance.get[:language] || 'en'
|
47
|
+
q = query.gsub(/{ ?{ ?VALUES ?} ?}/, "VALUES ?#{id_name} { #{ids} }").gsub(/{ ?{ ?LANGUAGE ?} ?}/, "bind(\"#{language}\" as ?filter_language).")
|
48
48
|
|
49
49
|
result = Solis::Query.run(entity, q)
|
50
50
|
end
|
@@ -11,33 +11,41 @@ module Solis
|
|
11
11
|
def self.read(key, spreadsheet_id, options = {})
|
12
12
|
class << self
|
13
13
|
def validate(sheets)
|
14
|
-
raise "Please make sure the sheet contains '_PREFIXES', '_METADATA', '_ENTITIES' tabs" unless (%w[
|
15
|
-
_PREFIXES _METADATA _ENTITIES
|
16
|
-
] - sheets.keys).length == 0
|
14
|
+
#raise "Please make sure the sheet contains '_PREFIXES', '_METADATA', '_ENTITIES' tabs" unless (%w[_PREFIXES _METADATA _ENTITIES] - sheets.keys).length == 0
|
17
15
|
|
18
16
|
prefixes = sheets['_PREFIXES']
|
19
17
|
metadata = sheets['_METADATA']
|
20
|
-
entities = sheets['_ENTITIES']
|
21
|
-
|
22
|
-
raise "_PREFIXES tab must have ['base', 'prefix', 'uri'] as a header at row 1" unless (%w[base prefix
|
23
|
-
uri] - prefixes.header).length == 0
|
24
|
-
raise "_METADATA tab must have ['key', 'value'] as a header at row 1" unless (%w[key
|
25
|
-
value] - metadata.header).length == 0
|
26
|
-
raise "_ENTITIES tab must have ['name', 'nameplural', 'description', 'subclassof', 'sameas'] as a header at row 1" unless (%w[
|
27
|
-
name nameplural description subclassof sameas
|
28
|
-
] - entities.header).length == 0
|
29
18
|
|
19
|
+
raise "_PREFIXES tab must have ['base', 'prefix', 'uri'] as a header at row 1" unless (%w[base prefix uri] - prefixes.header).length == 0
|
30
20
|
raise '_PREFIXES.base can only have one base URI' if prefixes.map { |m| m['base'] }.grep(/\*/).count != 1
|
21
|
+
|
22
|
+
raise "_METADATA tab must have ['key', 'value'] as a header at row 1" unless (%w[key value] - metadata.header).length == 0
|
23
|
+
|
24
|
+
if sheets.key?('_ENTITIES')
|
25
|
+
entities = sheets['_ENTITIES']
|
26
|
+
raise "_ENTITIES tab must have ['name', 'nameplural', 'description', 'subclassof', 'sameas'] as a header at row 1" unless (%w[name nameplural description subclassof sameas] - entities.header).length == 0
|
27
|
+
|
28
|
+
entities.each do |entity|
|
29
|
+
raise "Plural not found for #{entity['name']}" if entity['nameplural'].nil? || entity['nameplural'].empty?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
if sheets.key?('_REFERENCES')
|
34
|
+
references = sheets['_REFERENCES']
|
35
|
+
raise "_REFERENCES tab must have ['sheeturl', 'description', 'entityrange'] as a header at row 1" unless (%w[sheeturl description entityrange] - references.header).length == 0
|
36
|
+
end
|
37
|
+
|
31
38
|
end
|
32
39
|
|
33
40
|
def read_sheets(key, spreadsheet_id, options)
|
34
41
|
data = nil
|
35
42
|
|
36
|
-
cache_dir = ConfigFile.include?(:
|
43
|
+
cache_dir = ConfigFile.include?(:cache) ? ConfigFile[:cache] : '/tmp'
|
37
44
|
|
38
45
|
if ::File.exist?("#{cache_dir}/#{spreadsheet_id}.json") && (options.include?(:from_cache) && options[:from_cache])
|
39
46
|
Solis::LOGGER.info("from cache #{cache_dir}/#{spreadsheet_id}.json")
|
40
47
|
data = JSON.parse(::File.read("#{cache_dir}/#{spreadsheet_id}.json"), { symbolize_names: true })
|
48
|
+
return data
|
41
49
|
else
|
42
50
|
Solis::LOGGER.info("from source #{spreadsheet_id}")
|
43
51
|
session = SimpleSheets.new(key, spreadsheet_id)
|
@@ -49,66 +57,69 @@ module Solis
|
|
49
57
|
end
|
50
58
|
|
51
59
|
validate(sheets)
|
60
|
+
end
|
61
|
+
sheets
|
62
|
+
end
|
52
63
|
|
53
|
-
|
54
|
-
|
55
|
-
|
64
|
+
def process_sheet(key, sheet_id, sheets, options = {follow: true})
|
65
|
+
entities = {}
|
66
|
+
prefixes = {}
|
67
|
+
ontology_metadata = {}
|
56
68
|
|
57
|
-
|
58
|
-
|
69
|
+
sheets['_PREFIXES'].each do |e|
|
70
|
+
prefixes.store(e['prefix'].to_sym, { uri: e['uri'], base: e['base'].eql?('*') })
|
71
|
+
end
|
72
|
+
sheets['_METADATA'].each { |e| ontology_metadata.store(e['key'].to_sym, e['value']) }
|
73
|
+
|
74
|
+
base_uri = prefixes.select { |_k, v| v[:base] }.select { |s| !s.empty? }
|
75
|
+
|
76
|
+
graph_prefix = base_uri.keys.first
|
77
|
+
graph_name = base_uri.values.first[:uri]
|
78
|
+
|
79
|
+
sheets['_ENTITIES'].each do |e|
|
80
|
+
|
81
|
+
top_class = e['name'].to_s
|
82
|
+
#if prefixes[graph_prefix][:data].nil? || prefixes[graph_prefix][:data].empty?
|
83
|
+
entity_data = parse_entity_data(e['name'].to_s, graph_prefix, graph_name, sheets[top_class], { key: key, prefixes: prefixes, follow: options[:follow] })
|
84
|
+
# prefixes[graph_prefix][:data] = entity_data
|
85
|
+
#else
|
86
|
+
# entity_data = prefixes[graph_prefix][:data]
|
87
|
+
#end
|
88
|
+
|
89
|
+
if entity_data.empty?
|
90
|
+
entity_data[:id] = {
|
91
|
+
datatype: 'xsd:string',
|
92
|
+
path: "#{graph_prefix}:id",
|
93
|
+
cardinality: { min: '1', max: '1' },
|
94
|
+
same_as: '',
|
95
|
+
description: 'systeem UUID'
|
96
|
+
}
|
59
97
|
end
|
60
|
-
sheets['_METADATA'].each { |e| ontology_metadata.store(e['key'].to_sym, e['value']) }
|
61
|
-
|
62
|
-
base_uri = prefixes.select { |_k, v| v[:base] }.select { |s| !s.empty? }
|
63
|
-
|
64
|
-
graph_prefix = base_uri.keys.first
|
65
|
-
graph_name = base_uri.values.first[:uri]
|
66
|
-
|
67
|
-
sheets['_ENTITIES'].each do |e|
|
68
|
-
|
69
|
-
top_class = e['name'].to_s
|
70
|
-
# subclassof = e['subclassof'].empty? ? nil : e['subclassof'].split(':').last
|
71
|
-
# while subclassof
|
72
|
-
# candidate_sco = sheets['_ENTITIES'].select{|t| t['name'].eql?(subclassof)}.first
|
73
|
-
# subclassof = candidate_sco['subclassof'].empty? ? nil : candidate_sco['subclassof'].split(':').last
|
74
|
-
# top_class = candidate_sco['name'].to_s if candidate_sco['subclassof'].empty?
|
75
|
-
# end
|
76
|
-
|
77
|
-
entity_data = parse_entity_data(e['name'].to_s, graph_prefix, graph_name, sheets[top_class])
|
78
98
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
}
|
87
|
-
end
|
88
|
-
|
89
|
-
entities.store(e['name'].to_sym, { description: e['description'],
|
90
|
-
plural: e['nameplural'],
|
91
|
-
label: e['name'].to_s.strip,
|
92
|
-
sub_class_of: e['subclassof'].nil? || e['subclassof'].empty? ? [] : [e['subclassof']],
|
93
|
-
same_as: e['sameas'],
|
94
|
-
properties: entity_data })
|
95
|
-
end
|
99
|
+
entities.store(e['name'].to_sym, { description: e['description'],
|
100
|
+
plural: e['nameplural'],
|
101
|
+
label: e['name'].to_s.strip,
|
102
|
+
sub_class_of: e['subclassof'].nil? || e['subclassof'].empty? ? [] : [e['subclassof']],
|
103
|
+
same_as: e['sameas'],
|
104
|
+
properties: entity_data })
|
105
|
+
end
|
96
106
|
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
107
|
+
data = {
|
108
|
+
entities: entities,
|
109
|
+
ontologies: {
|
110
|
+
all: prefixes,
|
111
|
+
base: {
|
112
|
+
prefix: graph_prefix,
|
113
|
+
uri: graph_name
|
114
|
+
}
|
115
|
+
},
|
116
|
+
metadata: ontology_metadata
|
117
|
+
}
|
108
118
|
|
109
|
-
|
110
|
-
|
111
|
-
|
119
|
+
cache_dir = ConfigFile.include?(:cache) ? ConfigFile[:cache] : '/tmp'
|
120
|
+
# ::File.open("#{::File.absolute_path(cache_dir)}/#{spreadsheet_id}.json", 'wb') do |f|
|
121
|
+
::File.open("#{::File.absolute_path(cache_dir)}/#{sheet_id}.json", 'wb') do |f|
|
122
|
+
f.puts data.to_json
|
112
123
|
end
|
113
124
|
|
114
125
|
data
|
@@ -116,11 +127,12 @@ module Solis
|
|
116
127
|
raise Solis::Error::GeneralError, e.message
|
117
128
|
end
|
118
129
|
|
119
|
-
def parse_entity_data(
|
130
|
+
def parse_entity_data(entity_name, graph_prefix, _graph_name, e, options = {})
|
120
131
|
properties = {}
|
121
132
|
entity_data = e
|
122
133
|
if entity_data && !entity_data.nil? && (entity_data.count > 0)
|
123
134
|
entity_data.each do |p|
|
135
|
+
property_name = I18n.transliterate(p['name'].strip)
|
124
136
|
min_max = {}
|
125
137
|
|
126
138
|
%w[min max].each do |n|
|
@@ -130,24 +142,54 @@ module Solis
|
|
130
142
|
''
|
131
143
|
end
|
132
144
|
end
|
133
|
-
puts "#{
|
145
|
+
puts "#{entity_name}.#{property_name}"
|
134
146
|
unless p.key?('name')
|
147
|
+
puts "No 'name' property found"
|
135
148
|
pp p
|
136
149
|
end
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
150
|
+
|
151
|
+
if properties.key?(property_name)
|
152
|
+
puts "Found #{entity_name}.#{property_name}"
|
153
|
+
else
|
154
|
+
datatype_prefix, datatype_name = p['datatype'].split(':')
|
155
|
+
properties[property_name] = {
|
156
|
+
datatype: p['datatype'],
|
157
|
+
path: "#{graph_prefix}:#{property_name.to_s.classify}",
|
158
|
+
cardinality: { min: min_max['min'], max: min_max['max'] },
|
159
|
+
same_as: p['sameas'],
|
160
|
+
description: p['description']
|
161
|
+
}
|
162
|
+
|
163
|
+
# unless graph_prefix.eql?(datatype_prefix.to_sym)
|
164
|
+
# prefixes = options[:prefixes]
|
165
|
+
# if prefixes.key?(datatype_prefix.to_sym) && !prefixes[datatype_prefix.to_sym][:sheet_url].empty?
|
166
|
+
# tmp = URI(prefixes[datatype_prefix.to_sym][:sheet_url]).path.split('/')
|
167
|
+
# spreadsheet_id = tmp[tmp.index('d') + 1]
|
168
|
+
#
|
169
|
+
# processed_remote_sheet = {}
|
170
|
+
# if prefixes[datatype_prefix.to_sym].key?(:data) && !prefixes[datatype_prefix.to_sym][:data].empty?
|
171
|
+
# processed_remote_sheet = prefixes[datatype_prefix.to_sym][:data]
|
172
|
+
# else
|
173
|
+
# if options[:follow]
|
174
|
+
# sleep 30
|
175
|
+
# remote_sheet = read_sheets(options[:key], spreadsheet_id, { from_cache: true })
|
176
|
+
# processed_remote_sheet = process_sheet(options[:key], remote_sheet, {follow: false})
|
177
|
+
# prefixes[datatype_prefix.to_sym][:data] = processed_remote_sheet
|
178
|
+
# end
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# processed_remote_sheet
|
182
|
+
# end
|
183
|
+
# end
|
184
|
+
|
185
|
+
end
|
144
186
|
end
|
145
187
|
end
|
146
188
|
|
147
189
|
properties
|
148
190
|
end
|
149
191
|
|
150
|
-
def build_plantuml(
|
192
|
+
def build_plantuml(datas)
|
151
193
|
out = %(@startuml
|
152
194
|
!pragma layout elk
|
153
195
|
skinparam classFontSize 14
|
@@ -157,10 +199,11 @@ skinparam componentStyle uml2
|
|
157
199
|
skinparam wrapMessageWidth 100
|
158
200
|
skinparam ArrowColor #Maroon
|
159
201
|
|
160
|
-
title #{
|
202
|
+
title #{datas.first[:metadata][:title]} - #{datas.first[:metadata][:version]} - #{Time.now}
|
161
203
|
)
|
162
204
|
|
163
|
-
out += "\npackage #{
|
205
|
+
out += "\npackage #{datas.first[:ontologies][:base][:prefix]} {\n"
|
206
|
+
datas.each do |data|
|
164
207
|
data[:entities].each do |entity_name, metadata|
|
165
208
|
out += "\nclass #{entity_name}"
|
166
209
|
|
@@ -186,7 +229,7 @@ title #{data[:metadata][:title]} - #{data[:metadata][:version]} - #{Time.now}
|
|
186
229
|
out += "#{entity_name} --|> #{sub_class.split(':').last}\n" unless sub_class.empty?
|
187
230
|
end
|
188
231
|
end
|
189
|
-
|
232
|
+
end
|
190
233
|
out += %(
|
191
234
|
hide circle
|
192
235
|
hide methods
|
@@ -195,6 +238,8 @@ hide empty members
|
|
195
238
|
)
|
196
239
|
|
197
240
|
out
|
241
|
+
rescue StandardError => e
|
242
|
+
puts e.message
|
198
243
|
end
|
199
244
|
|
200
245
|
def datatype_lookup(datatype, as = :sql)
|
@@ -210,86 +255,14 @@ hide empty members
|
|
210
255
|
datatypes[datatype][as]
|
211
256
|
end
|
212
257
|
|
213
|
-
def
|
214
|
-
|
215
|
-
cardinality_max = { '0' => 'o|', '' => 'o{', '1' => '||' }
|
216
|
-
|
217
|
-
out = %(@startuml
|
218
|
-
skinparam classFontSize 14
|
219
|
-
!define LIGHTORANGE
|
220
|
-
skinparam groupInheritance 1
|
221
|
-
skinparam componentStyle uml2
|
222
|
-
skinparam wrapMessageWidth 100
|
223
|
-
skinparam ArrowColor #Maroon
|
224
|
-
skinparam linetype ortho
|
225
|
-
|
226
|
-
title #{data[:metadata][:title]} - #{data[:metadata][:version]} - #{Time.now}
|
227
|
-
)
|
228
|
-
|
229
|
-
out += "\npackage #{data[:ontologies][:base][:prefix]} {\n"
|
230
|
-
relations = []
|
231
|
-
data[:entities].each do |_entity_name, metadata|
|
232
|
-
table_name = metadata[:plural].to_s.underscore
|
233
|
-
# out += "\nentity \"#{entity_name}\" as #{table_name}"
|
234
|
-
out += "\nentity \"#{table_name}\" as #{table_name}"
|
235
|
-
|
236
|
-
properties = metadata[:properties]
|
237
|
-
# relations = []
|
238
|
-
unless properties.nil? || properties.empty?
|
239
|
-
out += "{\n"
|
240
|
-
properties.each do |property, property_metadata|
|
241
|
-
if property.to_s.eql?('id')
|
242
|
-
out += "\t *#{property} : #{datatype_lookup(property_metadata[:datatype], :sql)} <<generated>>\n"
|
243
|
-
out += "--\n"
|
244
|
-
else
|
245
|
-
mandatory = property_metadata[:cardinality][:min].to_i > 0
|
246
|
-
is_fk = property_metadata[:datatype].split(':').first.eql?(data[:ontologies][:base][:prefix].to_s) ? true : false
|
247
|
-
out += "\t #{mandatory ? '*' : ''}#{property}#{is_fk ? '_id' : ''} : #{datatype_lookup(
|
248
|
-
property_metadata[:datatype], :sql
|
249
|
-
)} #{is_fk ? '<<FK>>' : ''} \n"
|
250
|
-
end
|
251
|
-
|
252
|
-
unless property_metadata[:datatype].split(':').first.eql?(data[:ontologies][:base][:prefix].to_s)
|
253
|
-
next
|
254
|
-
end
|
255
|
-
|
256
|
-
cmin = cardinality_min[(property_metadata[:cardinality][:min]).to_s]
|
257
|
-
cmax = cardinality_max[(property_metadata[:cardinality][:max]).to_s]
|
258
|
-
|
259
|
-
# relations << " #{entity_name.to_s.underscore} #{cmin}--o{ #{property_metadata[:datatype].split(':').last.to_s.underscore} "
|
260
|
-
# ref_table_name = property_metadata[:datatype].split(':').last.to_s.underscore
|
261
|
-
ref_table_name = [property_metadata[:datatype].split(':').last.to_sym,
|
262
|
-
property_metadata[:path].split(':').last.classify.to_sym].map do |m|
|
263
|
-
data[:entities][m].nil? ? nil : data[:entities][m][:plural].underscore
|
264
|
-
end.compact.first
|
265
|
-
|
266
|
-
relations << " #{table_name} #{cmin}--#{cmax} #{ref_table_name} "
|
267
|
-
end
|
268
|
-
out += "}\n"
|
269
|
-
end
|
270
|
-
|
271
|
-
out += "\n"
|
272
|
-
# out += "#{entity_name} }o-- #{metadata[:sub_class_of].split(':').last}\n" unless metadata[:sub_class_of].empty?
|
273
|
-
end
|
274
|
-
out += relations.join("\n")
|
275
|
-
|
276
|
-
out += %(
|
277
|
-
hide circle
|
278
|
-
hide methods
|
279
|
-
hide empty members
|
280
|
-
@enduml
|
281
|
-
)
|
282
|
-
|
283
|
-
out
|
284
|
-
end
|
285
|
-
|
286
|
-
def build_shacl(data)
|
287
|
-
shacl_prefix = data[:ontologies][:all].select { |_, v| v[:uri] =~ /shacl/ }.keys.first
|
258
|
+
def build_shacl(datas)
|
259
|
+
shacl_prefix = datas.first[:ontologies][:all].select { |_, v| v[:uri] =~ /shacl/ }.keys.first
|
288
260
|
shacl_prefix = 'sh' if shacl_prefix.nil?
|
289
261
|
|
290
|
-
out = header(
|
262
|
+
out = header(datas.first)
|
291
263
|
|
292
|
-
|
264
|
+
datas.each do |data|
|
265
|
+
data[:entities].each do |entity_name, metadata|
|
293
266
|
graph_prefix = data[:ontologies][:base][:prefix]
|
294
267
|
graph_name = data[:ontologies][:base][:uri]
|
295
268
|
|
@@ -301,7 +274,7 @@ hide empty members
|
|
301
274
|
if node && !node.empty?
|
302
275
|
node = node.first if node.is_a?(Array)
|
303
276
|
node = node.strip
|
304
|
-
node += 'Shape' if node != /Shape$/ && node =~ /^#{graph_prefix}:/
|
277
|
+
node += 'Shape' if node != /Shape$/ # && node =~ /^#{graph_prefix}:/
|
305
278
|
else
|
306
279
|
node = target_class
|
307
280
|
end
|
@@ -345,74 +318,78 @@ hide empty members
|
|
345
318
|
end
|
346
319
|
out += ".\n"
|
347
320
|
end
|
348
|
-
|
321
|
+
end
|
349
322
|
out
|
323
|
+
rescue StandardError => e
|
324
|
+
puts e.message
|
350
325
|
end
|
351
326
|
|
352
|
-
def build_schema(
|
327
|
+
def build_schema(datas)
|
353
328
|
classes = {}
|
354
329
|
datatype_properties = {}
|
355
330
|
object_properties = {}
|
356
331
|
|
357
332
|
format = :ttl
|
358
|
-
graph_prefix =
|
359
|
-
graph_name =
|
333
|
+
graph_prefix = datas.first[:ontologies][:base][:prefix]
|
334
|
+
graph_name = datas.first[:ontologies][:base][:uri]
|
360
335
|
|
361
336
|
all_prefixes = {}
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
metadata[:properties].each do |property, property_metadata|
|
373
|
-
attribute = property.to_s.strip
|
374
|
-
description = property_metadata[:description]
|
375
|
-
path = "#{graph_name}#{attribute}"
|
376
|
-
datatype = property_metadata[:datatype]
|
377
|
-
|
378
|
-
schema_data = datatype_properties[attribute] || {}
|
379
|
-
domain = schema_data[:domain] || []
|
380
|
-
domain << "#{graph_name}#{entity_name}"
|
381
|
-
datatype_properties[attribute] = {
|
382
|
-
domain: domain,
|
383
|
-
comment: description,
|
384
|
-
label: attribute.to_s,
|
385
|
-
range: datatype,
|
386
|
-
type: 'rdf:Property'
|
337
|
+
datas.first[:ontologies][:all].each { |k, v| all_prefixes[k] = v[:uri] }
|
338
|
+
|
339
|
+
datas.each do |data|
|
340
|
+
data[:entities].each do |entity_name, metadata|
|
341
|
+
classes[entity_name] = {
|
342
|
+
comment: metadata[:description],
|
343
|
+
label: entity_name.to_s,
|
344
|
+
type: 'owl:Class',
|
345
|
+
subClassOf: metadata[:sub_class_of]
|
387
346
|
}
|
388
|
-
unless property_metadata[:same_as].nil? || property_metadata[:same_as].empty?
|
389
|
-
datatype_properties[attribute]['owl:sameAs'] =
|
390
|
-
property_metadata[:same_as]
|
391
|
-
end
|
392
347
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
348
|
+
metadata[:properties].each do |property, property_metadata|
|
349
|
+
attribute = property.to_s.strip
|
350
|
+
description = property_metadata[:description]
|
351
|
+
path = "#{graph_name}#{attribute}"
|
352
|
+
datatype = property_metadata[:datatype]
|
353
|
+
|
354
|
+
schema_data = datatype_properties[attribute] || {}
|
355
|
+
domain = schema_data[:domain] || []
|
356
|
+
domain << "#{graph_name}#{entity_name}"
|
357
|
+
datatype_properties[attribute] = {
|
358
|
+
domain: domain,
|
359
|
+
comment: description,
|
360
|
+
label: attribute.to_s,
|
361
|
+
range: datatype,
|
362
|
+
type: 'rdf:Property'
|
363
|
+
}
|
364
|
+
unless property_metadata[:same_as].nil? || property_metadata[:same_as].empty?
|
365
|
+
datatype_properties[attribute]['owl:sameAs'] =
|
366
|
+
property_metadata[:same_as]
|
367
|
+
end
|
368
|
+
|
369
|
+
subclass_data = data[:entities][entity_name][:sub_class_of] || []
|
370
|
+
unless property_metadata[:cardinality][:min].empty?
|
371
|
+
subclass_data << RDF::Vocabulary.term(type: 'owl:Restriction',
|
372
|
+
onProperty: path,
|
373
|
+
minCardinality: property_metadata[:cardinality][:min])
|
374
|
+
end
|
375
|
+
unless property_metadata[:cardinality][:max].empty?
|
376
|
+
subclass_data << RDF::Vocabulary.term(type: 'owl:Restriction',
|
377
|
+
onProperty: path,
|
378
|
+
maxCardinality: property_metadata[:cardinality][:max])
|
379
|
+
end
|
380
|
+
data[:entities][entity_name][:sub_class_of] = subclass_data
|
403
381
|
end
|
404
|
-
data[:entities][entity_name][:sub_class_of] = subclass_data
|
405
382
|
end
|
406
383
|
end
|
407
384
|
|
408
385
|
lp = RDF::StrictVocabulary(graph_name)
|
409
386
|
o = ::Class.new(lp) do
|
410
387
|
ontology(graph_name.to_sym, {
|
411
|
-
"dc11:title":
|
412
|
-
"dc11:description":
|
388
|
+
"dc11:title": datas.first[:metadata][:title].freeze,
|
389
|
+
"dc11:description": datas.first[:metadata][:description].freeze,
|
413
390
|
"dc11:date": Time.now.to_s.freeze,
|
414
|
-
"dc11:creator":
|
415
|
-
"owl:versionInfo":
|
391
|
+
"dc11:creator": datas.first[:metadata][:author].freeze,
|
392
|
+
"owl:versionInfo": datas.first[:metadata][:version].freeze,
|
416
393
|
type: 'owl:Ontology'.freeze
|
417
394
|
})
|
418
395
|
|
@@ -433,6 +410,7 @@ hide empty members
|
|
433
410
|
graph = RDF::Graph.new
|
434
411
|
graph.graph_name = RDF::URI(graph_name)
|
435
412
|
|
413
|
+
datas.each do |data|
|
436
414
|
data[:entities].select { |_k, v| !v[:same_as].empty? }.each do |k, v|
|
437
415
|
prefix, verb = v[:same_as].split(':')
|
438
416
|
rdf_vocabulary = RDF::Vocabulary.from_sym(prefix.upcase)
|
@@ -442,178 +420,27 @@ hide empty members
|
|
442
420
|
rescue StandardError => e
|
443
421
|
puts e.message
|
444
422
|
end
|
423
|
+
end
|
445
424
|
|
446
425
|
graph << o.to_enum
|
447
426
|
|
448
427
|
graph.dump(format, prefixes: all_prefixes)
|
428
|
+
rescue StandardError => e
|
429
|
+
puts e.message
|
449
430
|
end
|
450
431
|
|
451
|
-
def build_inflections(
|
432
|
+
def build_inflections(datas)
|
452
433
|
inflections = {}
|
434
|
+
datas.each do |data|
|
453
435
|
data[:entities].each do |entity, metadata|
|
454
436
|
inflections[entity] = metadata[:plural]
|
455
437
|
inflections[entity.to_s.underscore.to_sym] = metadata[:plural].underscore
|
456
438
|
end
|
457
|
-
|
458
|
-
inflections.to_json
|
459
|
-
end
|
460
|
-
|
461
|
-
def build_sql(data)
|
462
|
-
graph_prefix = data[:ontologies][:base][:prefix]
|
463
|
-
out = "--\n-- #{data[:metadata][:title]} - #{data[:metadata][:version]} - #{Time.now}\n"
|
464
|
-
out += "-- description: #{data[:metadata][:description]}\n"
|
465
|
-
out += "-- author: #{data[:metadata][:author]}\n--\n\n"
|
466
|
-
|
467
|
-
out += %(CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
468
|
-
DROP SCHEMA IF EXISTS #{graph_prefix} CASCADE;
|
469
|
-
CREATE SCHEMA #{graph_prefix};
|
470
|
-
|
471
|
-
)
|
472
|
-
data[:entities].each do |entity_name, metadata|
|
473
|
-
table_name = metadata[:plural].to_s.underscore
|
474
|
-
out += "CREATE TABLE #{graph_prefix}.#{table_name}(\n"
|
475
|
-
|
476
|
-
properties = metadata[:properties]
|
477
|
-
properties.each_with_index do |(property, property_metadata), i|
|
478
|
-
mandatory = property_metadata[:cardinality][:min].to_i > 0
|
479
|
-
is_fk = property_metadata[:datatype].split(':').first.eql?(data[:ontologies][:base][:prefix].to_s) ? true : false
|
480
|
-
if data[:entities][property_metadata[:datatype].split(':').last.to_sym].nil? && is_fk
|
481
|
-
raise Solis::Error::NotFoundError,
|
482
|
-
"#{entity_name}.#{property} Not found in _ENTITIES tab"
|
483
|
-
end
|
484
|
-
|
485
|
-
if is_fk
|
486
|
-
references = data[:entities][property_metadata[:datatype].split(':').last.to_sym][:plural].to_s.underscore
|
487
|
-
end
|
488
|
-
|
489
|
-
out += ", \n" if i > 0
|
490
|
-
if property.to_s.eql?('id')
|
491
|
-
# out += "\t#{property} #{datatype_lookup(property_metadata[:datatype], :sql)}#{mandatory ? ' NOT NULL' : ''} PRIMARY KEY"
|
492
|
-
out += "\t#{property} SERIAL#{mandatory ? ' NOT NULL' : ''} PRIMARY KEY"
|
493
|
-
else
|
494
|
-
out += "\t#{property}#{is_fk ? '_id' : ''} #{datatype_lookup(property_metadata[:datatype],
|
495
|
-
:sql)}#{mandatory ? ' NOT NULL' : ''}#{is_fk ? " REFERENCES #{graph_prefix}.#{references}(id)" : ''}"
|
496
|
-
end
|
497
|
-
end
|
498
|
-
|
499
|
-
out += ");\n\n"
|
500
|
-
end
|
501
|
-
|
502
|
-
out
|
503
|
-
end
|
504
|
-
|
505
|
-
def build_erd(data, type = :uml)
|
506
|
-
out = erd_header(data, type)
|
507
|
-
all_tables = {}
|
508
|
-
tables = {}
|
509
|
-
relations = []
|
510
|
-
references = {}
|
511
|
-
every_entity(data).each do |table|
|
512
|
-
case type
|
513
|
-
when :uml
|
514
|
-
d = table[:table].call(type)
|
515
|
-
out += d[:out]
|
516
|
-
relations << d[:relations] unless d[:relations].empty?
|
517
|
-
out += "\n\n"
|
518
|
-
#references << d[:references]
|
519
|
-
when :sql
|
520
|
-
all_tables[table[:name]] = table
|
521
|
-
d = table[:table].call(type)
|
522
|
-
tables[table[:name]] = d[:out]
|
523
|
-
|
524
|
-
d[:references].each do |k, v|
|
525
|
-
references[k] = (references.include?(k) ? references[k] : 0) + v
|
526
|
-
end
|
527
|
-
end
|
528
|
-
end
|
529
|
-
|
530
|
-
references = references.sort_by { |k, v| -v }.to_h #each{|m| r[m[0]] = m[1]}
|
531
|
-
|
532
|
-
r = references.sort_by { |k, v|
|
533
|
-
k = k[0]
|
534
|
-
relation = all_tables.key?(k) ? all_tables[k][:properties].map { |s| s[:references] }.compact.first : nil
|
535
|
-
|
536
|
-
a = references.keys.index(k)
|
537
|
-
b = references.keys.index(relation)
|
538
|
-
b = 0 if b.nil?
|
539
|
-
a = 0 if a.nil?
|
540
|
-
|
541
|
-
b = a + b if b < a
|
542
|
-
|
543
|
-
b
|
544
|
-
}
|
545
|
-
|
546
|
-
references = r.to_h
|
547
|
-
|
548
|
-
if type.eql?(:sql)
|
549
|
-
all_keys = references.keys
|
550
|
-
t = tables.sort_by { |k, v| all_keys.include?(k) ? all_keys.index(k) : 0 }
|
551
|
-
out += t.map { |m| m[1] }.join("\n")
|
552
439
|
end
|
553
440
|
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
out += erd_footer(data, type)
|
558
|
-
|
559
|
-
out
|
560
|
-
end
|
561
|
-
|
562
|
-
def erd_header(data, type)
|
563
|
-
header = ''
|
564
|
-
|
565
|
-
case type
|
566
|
-
when :uml
|
567
|
-
header = %(@startuml
|
568
|
-
skinparam classFontSize 14
|
569
|
-
!define LIGHTORANGE
|
570
|
-
skinparam groupInheritance 1
|
571
|
-
skinparam componentStyle uml2
|
572
|
-
skinparam wrapMessageWidth 100
|
573
|
-
skinparam ArrowColor #Maroon
|
574
|
-
skinparam linetype ortho
|
575
|
-
|
576
|
-
title #{data[:metadata][:title]} - #{data[:metadata][:version]} - #{Time.now}
|
577
|
-
|
578
|
-
package #{data[:ontologies][:base][:prefix]} {
|
579
|
-
)
|
580
|
-
when :sql
|
581
|
-
graph_prefix = data[:ontologies][:base][:prefix]
|
582
|
-
header = %(--
|
583
|
-
-- #{data[:metadata][:title]} - #{data[:metadata][:version]} - #{Time.now}
|
584
|
-
-- description: #{data[:metadata][:description]}
|
585
|
-
-- author: #{data[:metadata][:author]}
|
586
|
-
--
|
587
|
-
|
588
|
-
|
589
|
-
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
590
|
-
DROP SCHEMA IF EXISTS #{graph_prefix} CASCADE;
|
591
|
-
CREATE SCHEMA #{graph_prefix};
|
592
|
-
|
593
|
-
|
594
|
-
)
|
595
|
-
end
|
596
|
-
|
597
|
-
header
|
598
|
-
end
|
599
|
-
|
600
|
-
def erd_footer(_data, type = :uml)
|
601
|
-
footer = ''
|
602
|
-
|
603
|
-
case type
|
604
|
-
when :uml
|
605
|
-
footer = %(
|
606
|
-
|
607
|
-
hide circle
|
608
|
-
hide methods
|
609
|
-
hide empty members
|
610
|
-
@enduml
|
611
|
-
)
|
612
|
-
when :sql
|
613
|
-
footer = ''
|
614
|
-
end
|
615
|
-
|
616
|
-
footer
|
441
|
+
inflections.to_json
|
442
|
+
rescue StandardError => e
|
443
|
+
puts e.message
|
617
444
|
end
|
618
445
|
|
619
446
|
def every_entity(data)
|
@@ -756,20 +583,53 @@ hide empty members
|
|
756
583
|
|
757
584
|
"#{out}\n"
|
758
585
|
end
|
586
|
+
|
587
|
+
def spreadsheet_id_from_url(sheet_url)
|
588
|
+
tmp = URI(sheet_url).path.split('/')
|
589
|
+
spreadsheet_id = tmp[tmp.index('d') + 1]
|
590
|
+
end
|
591
|
+
end
|
592
|
+
|
593
|
+
sheet_data = read_sheets(key, spreadsheet_id, options)
|
594
|
+
|
595
|
+
if sheet_data.is_a?(Hash)
|
596
|
+
raise "No _REFERENCES sheet found" unless sheet_data.key?("_REFERENCES")
|
597
|
+
#read other ontologies
|
598
|
+
Solis::LOGGER.info('Reading referenced ontologies')
|
599
|
+
references = sheet_data['_REFERENCES'].map do |reference|
|
600
|
+
{sheet_url: reference['sheeturl'], description: reference['description']}
|
601
|
+
end
|
602
|
+
|
603
|
+
cache_dir = ConfigFile.include?(:cache) ? ConfigFile[:cache] : '/tmp'
|
604
|
+
::File.open("#{::File.absolute_path(cache_dir)}/#{spreadsheet_id}.json", 'wb') do |f|
|
605
|
+
f.puts references.to_json
|
606
|
+
end
|
607
|
+
else
|
608
|
+
references = sheet_data
|
609
|
+
end
|
610
|
+
|
611
|
+
datas = []
|
612
|
+
references.each do |v|
|
613
|
+
sheet_id = spreadsheet_id_from_url(v[:sheet_url])
|
614
|
+
|
615
|
+
sheet_data = read_sheets(key, sheet_id, options)
|
616
|
+
if sheet_data.key?("_PREFIXES")
|
617
|
+
datas << process_sheet(key, sheet_id, sheet_data)
|
618
|
+
sleep 30
|
619
|
+
else
|
620
|
+
datas << sheet_data
|
621
|
+
end
|
759
622
|
end
|
760
623
|
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
plantuml = build_plantuml(
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
inflections = build_inflections(
|
769
|
-
|
770
|
-
#erd = build_erd(data, :uml)
|
771
|
-
{ inflections: inflections, shacl: shacl, schema: schema, plantuml: plantuml,
|
772
|
-
plantuml_erd: plantuml_erd, sql: sql }
|
624
|
+
Solis::LOGGER.info('Generating SHACL')
|
625
|
+
shacl = build_shacl(datas)
|
626
|
+
Solis::LOGGER.info('Generating PLANTUML')
|
627
|
+
plantuml = build_plantuml(datas)
|
628
|
+
Solis::LOGGER.info('Generating SCHEMA')
|
629
|
+
schema = build_schema(datas)
|
630
|
+
Solis::LOGGER.info('Generating INFLECTIONS')
|
631
|
+
inflections = build_inflections(datas)
|
632
|
+
{ inflections: inflections, shacl: shacl, schema: schema, plantuml: plantuml}
|
773
633
|
end
|
774
634
|
end
|
775
635
|
end
|
data/lib/solis/shape.rb
CHANGED
@@ -69,6 +69,9 @@ module Solis
|
|
69
69
|
end
|
70
70
|
elsif datatype.nil? && node.is_a?(RDF::URI)
|
71
71
|
node.value.split('/').last.gsub(/Shape$/, '').to_sym
|
72
|
+
# normalize ex."https://data.q.odis.be/person#Name" to Name
|
73
|
+
#node.value.split('/').last.gsub(/Shape$/, '').split('#').last.to_sym
|
74
|
+
#node.value.split('/').last.gsub(/Shape$/, '').gsub('#','').camelize.to_sym
|
72
75
|
elsif datatype =~ /^http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns/
|
73
76
|
case datatype
|
74
77
|
when /http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#langString/
|
data/lib/solis/version.rb
CHANGED
data/solis.gemspec
CHANGED
@@ -27,22 +27,23 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ['lib']
|
29
29
|
|
30
|
-
spec.add_runtime_dependency 'activesupport', '~>
|
30
|
+
spec.add_runtime_dependency 'activesupport', '~> 7.0'
|
31
31
|
spec.add_runtime_dependency 'http', '~> 5.1'
|
32
32
|
spec.add_runtime_dependency 'graphiti', '~> 1.3'
|
33
|
-
spec.add_runtime_dependency 'moneta', '~> 1.
|
34
|
-
spec.add_runtime_dependency 'linkeddata', '~> 3.
|
33
|
+
spec.add_runtime_dependency 'moneta', '~> 1.6'
|
34
|
+
spec.add_runtime_dependency 'linkeddata', '~> 3.3'
|
35
35
|
spec.add_runtime_dependency 'google_drive', '~> 3.0'
|
36
|
-
spec.add_runtime_dependency 'json', '~> 2.
|
36
|
+
spec.add_runtime_dependency 'json', '~> 2.6'
|
37
37
|
spec.add_runtime_dependency 'hashdiff', '~> 1.0'
|
38
38
|
spec.add_runtime_dependency 'iso8601', '~> 0.13.0'
|
39
|
-
spec.add_runtime_dependency 'connection_pool', '~> 2.
|
39
|
+
spec.add_runtime_dependency 'connection_pool', '~> 2.4'
|
40
40
|
spec.add_runtime_dependency 'uuidtools', '~> 2.2.0'
|
41
|
-
spec.add_runtime_dependency 'dry-struct', '~> 1.
|
42
|
-
spec.add_runtime_dependency 'psych', '
|
41
|
+
spec.add_runtime_dependency 'dry-struct', '~> 1.6'
|
42
|
+
spec.add_runtime_dependency 'psych', '~> 5.1'
|
43
|
+
#spec.add_runtime_dependency 'hashdiff', '~> 1.1'
|
43
44
|
|
44
45
|
spec.add_development_dependency 'rake', '~> 13.0'
|
45
|
-
spec.add_development_dependency 'minitest', '~> 5.
|
46
|
+
spec.add_development_dependency 'minitest', '~> 5.19'
|
46
47
|
|
47
48
|
# spec.add_development_dependency 'rubocop'
|
48
49
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.72.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mehmet Celik
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '7.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '7.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: http
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,28 +58,28 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
61
|
+
version: '1.6'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
68
|
+
version: '1.6'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: linkeddata
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
75
|
+
version: '3.3'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
82
|
+
version: '3.3'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: google_drive
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,14 +100,14 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '2.
|
103
|
+
version: '2.6'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: '2.
|
110
|
+
version: '2.6'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: hashdiff
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 2.
|
145
|
+
version: '2.4'
|
146
146
|
type: :runtime
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version: 2.
|
152
|
+
version: '2.4'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: uuidtools
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -170,28 +170,28 @@ dependencies:
|
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: '1.
|
173
|
+
version: '1.6'
|
174
174
|
type: :runtime
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: '1.
|
180
|
+
version: '1.6'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: psych
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- - "
|
185
|
+
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: '
|
187
|
+
version: '5.1'
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- - "
|
192
|
+
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: '
|
194
|
+
version: '5.1'
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: rake
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -212,14 +212,14 @@ dependencies:
|
|
212
212
|
requirements:
|
213
213
|
- - "~>"
|
214
214
|
- !ruby/object:Gem::Version
|
215
|
-
version: 5.
|
215
|
+
version: '5.19'
|
216
216
|
type: :development
|
217
217
|
prerelease: false
|
218
218
|
version_requirements: !ruby/object:Gem::Requirement
|
219
219
|
requirements:
|
220
220
|
- - "~>"
|
221
221
|
- !ruby/object:Gem::Version
|
222
|
-
version: 5.
|
222
|
+
version: '5.19'
|
223
223
|
description: The SUN in latin or is it SILOS spelled backwards. Turn any SHACL file
|
224
224
|
or Google sheet into an API, ORM, documentation on top of a data store
|
225
225
|
email:
|
@@ -295,7 +295,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
295
295
|
- !ruby/object:Gem::Version
|
296
296
|
version: '0'
|
297
297
|
requirements: []
|
298
|
-
rubygems_version: 3.
|
298
|
+
rubygems_version: 3.5.6
|
299
299
|
signing_key:
|
300
300
|
specification_version: 4
|
301
301
|
summary: Turn any SHACL file into an API, ORM, documentation, ...
|