uri_service 0.2.12 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -0
- data/lib/uri_service.rb +3 -1
- data/lib/uri_service/client.rb +196 -130
- data/lib/uri_service/term_type.rb +7 -0
- data/lib/uri_service/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5012df111508e186ecb439067488e70ec5e511e5
|
4
|
+
data.tar.gz: af2dbf25aec0882474d1a8909cc26fd81007b1b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a9c898ce08c8f34a2ca4d23f088b24c9d735cd3ac2ecf1f565bb47584ca2e46a333d89b956da404f56b4f5d517c8ee3625b16a45b555e60ee0fc5edeea4f704
|
7
|
+
data.tar.gz: f6b423ecf9d89676b3661fd027ca5ba14bca37affffe3bb9e16415559d0de451b637554e7fc774b46339a4d108cb4d9b1f63f94690eeb93d7f080cf9fb2289ee
|
data/README.md
CHANGED
@@ -15,6 +15,7 @@ gem install uri_service
|
|
15
15
|
```ruby
|
16
16
|
UriService::init({
|
17
17
|
'local_uri_base' => 'http://id.example.com/term/',
|
18
|
+
'temporary_uri_base' => 'com:example:id:temporary:',
|
18
19
|
'solr' => {
|
19
20
|
'url' => 'http://localhost:8983/solr/uri_service_test',
|
20
21
|
'pool_size' => 5,
|
@@ -36,6 +37,7 @@ UriService.client.do_stuff(...)
|
|
36
37
|
```ruby
|
37
38
|
client = UriService::Client.new({
|
38
39
|
'local_uri_base' => 'http://id.example.com/term/',
|
40
|
+
'temporary_uri_base' => 'com:example:id:temporary:',
|
39
41
|
'solr' => {
|
40
42
|
'url' => 'http://localhost:8983/solr/uri_service_test',
|
41
43
|
'pool_size' => 5,
|
@@ -65,6 +67,7 @@ Note that the database that you specify here does not have to be the same databa
|
|
65
67
|
```yaml
|
66
68
|
development:
|
67
69
|
local_uri_base: 'http://id.example.com/term/'
|
70
|
+
temporary_uri_base: 'com:example:id:temporary:'
|
68
71
|
solr:
|
69
72
|
url: 'http://localhost:8983/solr/uri_service_development'
|
70
73
|
pool_size: 5
|
@@ -77,6 +80,7 @@ development:
|
|
77
80
|
|
78
81
|
test:
|
79
82
|
local_uri_base: 'http://id.example.com/term/'
|
83
|
+
temporary_uri_base: 'com:example:id:temporary:'
|
80
84
|
solr:
|
81
85
|
url: 'http://localhost:8983/solr/uri_service_test'
|
82
86
|
pool_size: 5
|
@@ -89,6 +93,7 @@ test:
|
|
89
93
|
|
90
94
|
production:
|
91
95
|
local_uri_base: 'http://id.example.com/term/'
|
96
|
+
temporary_uri_base: 'com:example:id:temporary:'
|
92
97
|
solr:
|
93
98
|
url: 'http://localhost:9983/solr/uri_service_production'
|
94
99
|
pool_size: 5
|
data/lib/uri_service.rb
CHANGED
@@ -12,9 +12,10 @@ module UriService
|
|
12
12
|
VOCABULARIES = :vocabularies
|
13
13
|
TERM = :term
|
14
14
|
TERMS = :terms
|
15
|
+
VALID_URI_REGEX = /\A#{URI::regexp}\z/
|
15
16
|
|
16
17
|
# Initialize the main instance of UriService::Client
|
17
|
-
# opts format: { 'local_uri_base' => 'http://id.example.com/term/', 'solr' => {...solr config...}, 'database' => {...database config...} }
|
18
|
+
# opts format: { 'local_uri_base' => 'http://id.example.com/term/', temporary_uri_base: 'temporary:', 'solr' => {...solr config...}, 'database' => {...database config...} }
|
18
19
|
def self.init(opts)
|
19
20
|
if @client && @client.connected?
|
20
21
|
@client.disconnect!
|
@@ -47,6 +48,7 @@ module UriService
|
|
47
48
|
end
|
48
49
|
|
49
50
|
require "uri_service/version"
|
51
|
+
require "uri_service/term_type"
|
50
52
|
require "uri_service/client"
|
51
53
|
|
52
54
|
require 'uri_service/railtie' if defined?(Rails)
|
data/lib/uri_service/client.rb
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
class UriService::Client
|
2
2
|
|
3
|
-
attr_reader :db, :rsolr_pool, :local_uri_base
|
3
|
+
attr_reader :db, :rsolr_pool, :local_uri_base, :temporary_uri_base
|
4
4
|
|
5
5
|
ALPHANUMERIC_UNDERSCORE_KEY_REGEX = /\A[a-z]+[a-z0-9_]*\z/
|
6
|
-
|
7
|
-
|
6
|
+
CORE_FIELD_NAMES = ['uri', 'vocabulary_string_key', 'value', 'type']
|
7
|
+
VALID_TYPES = [UriService::TermType::EXTERNAL, UriService::TermType::LOCAL, UriService::TermType::TEMPORARY]
|
8
8
|
|
9
9
|
def initialize(opts)
|
10
10
|
raise UriService::InvalidOptsError, "Must supply opts['local_uri_base'] to initialize method." if opts['local_uri_base'].nil?
|
11
|
+
raise UriService::InvalidOptsError, "Must supply opts['temporary_uri_base'] to initialize method." if opts['temporary_uri_base'].nil?
|
11
12
|
raise UriService::InvalidOptsError, "Must supply opts['database'] to initialize method." if opts['database'].nil?
|
12
13
|
raise UriService::InvalidOptsError, "Must supply opts['solr'] to initialize method." if opts['solr'].nil?
|
13
14
|
|
14
|
-
# Set local_uri_base
|
15
|
+
# Set local_uri_base and temporary_uri_base
|
15
16
|
@local_uri_base = opts['local_uri_base']
|
17
|
+
@temporary_uri_base = opts['temporary_uri_base']
|
16
18
|
|
17
19
|
# Create DB connection pool
|
18
20
|
@db = Sequel.connect(opts['database'])
|
@@ -45,7 +47,7 @@ class UriService::Client
|
|
45
47
|
term_db_row[:value],
|
46
48
|
term_db_row[:uri],
|
47
49
|
JSON.parse(term_db_row[:additional_fields]),
|
48
|
-
term_db_row[:
|
50
|
+
term_db_row[:type],
|
49
51
|
false)
|
50
52
|
|
51
53
|
if print_progress_to_console
|
@@ -122,7 +124,7 @@ class UriService::Client
|
|
122
124
|
String :uri_hash, fixed: true, size: 64, unique: true
|
123
125
|
String :value, text: true
|
124
126
|
String :value_hash, fixed: true, size: 64
|
125
|
-
|
127
|
+
String :type, null: false
|
126
128
|
String :additional_fields, text: true
|
127
129
|
end
|
128
130
|
puts 'Created table: ' + UriService::TERMS.to_s
|
@@ -157,79 +159,60 @@ class UriService::Client
|
|
157
159
|
end
|
158
160
|
end
|
159
161
|
|
160
|
-
# Creates a new term
|
161
|
-
def create_term(
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
# Creates a new local term, auto-generating a URI
|
166
|
-
# By default, if raise_error_if_local_term_value_exists_in_vocabulary param is true, rejects the creation of a local value if that exact value already exists in the specified vocabulary
|
167
|
-
def create_local_term(vocabulary_string_key, value, additional_fields={}, raise_error_if_local_term_value_exists_in_vocabulary=true)
|
168
|
-
|
169
|
-
# Create a new URI for this local term, using the @local_uri_base
|
170
|
-
term_uri = URI(@local_uri_base)
|
171
|
-
term_uri.path += SecureRandom.uuid # Generate random UUID for local URI
|
172
|
-
term_uri = term_uri.to_s
|
162
|
+
# Creates a new term
|
163
|
+
def create_term(type, opts)
|
164
|
+
raise UriService::InvalidTermTypeError, 'Invalid type: ' + type unless VALID_TYPES.include?(type)
|
173
165
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
rescue UriService::ExistingUriError
|
179
|
-
raise UriService::ExistingUriError, "UriService generated a duplicate random UUID (via SecureRandom.uuid) and will now attempt to create another. This type of problem is EXTREMELY rare."
|
180
|
-
end
|
181
|
-
}
|
182
|
-
|
183
|
-
return nil
|
184
|
-
end
|
185
|
-
|
186
|
-
def create_term_impl(vocabulary_string_key, value, term_uri, additional_fields, is_local, raise_error_if_local_term_value_exists_in_vocabulary)
|
187
|
-
self.handle_database_disconnect do
|
166
|
+
vocabulary_string_key = opts.delete(:vocabulary_string_key)
|
167
|
+
value = opts.delete(:value)
|
168
|
+
uri = opts.delete(:uri)
|
169
|
+
additional_fields = opts.delete(:additional_fields) || {}
|
188
170
|
|
189
|
-
|
171
|
+
if type == UriService::TermType::EXTERNAL
|
172
|
+
# URI is required
|
173
|
+
raise UriService::InvalidOptsError, "A uri must be supplied for terms of type #{type}." if uri.nil?
|
190
174
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
unless term_uri =~ VALID_URI_REGEX
|
196
|
-
raise UriService::InvalidUriError, "Invalid URI supplied: #{term_uri}, with result #{(VALID_URI_REGEX.match(term_uri)).to_s}"
|
197
|
-
end
|
198
|
-
validate_additional_fields(additional_fields) # This method call raises an error if an invalid additional_field key is supplied
|
175
|
+
return create_term_impl(type, vocabulary_string_key, value, uri, additional_fields)
|
176
|
+
else
|
177
|
+
# URI should not be present
|
178
|
+
raise UriService::InvalidOptsError, "A uri cannot supplied for term type: #{type}." unless uri.nil?
|
199
179
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
uri
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
end
|
180
|
+
if type == UriService::TermType::TEMPORARY
|
181
|
+
# No two TEMPORARY terms within the same vocabulary can have the same value, so we generate a unique URI from a hash of the (vocabulary_string_key + value) to ensure uniqueness.
|
182
|
+
uri = self.generate_uri_for_temporary_term(vocabulary_string_key, value)
|
183
|
+
return create_term_impl(type, vocabulary_string_key, value, uri, additional_fields)
|
184
|
+
elsif type == UriService::TermType::LOCAL
|
185
|
+
5.times {
|
186
|
+
# We generate a unique URI for a local term from a UUID generator.
|
187
|
+
# Getting a duplicate UUID from a call to SecureRandom.uuid is EXTREMELY unlikely,
|
188
|
+
# but we'll account for it just in case by being ready to make multiple attempts.
|
189
|
+
begin
|
190
|
+
# Generate new URI for LOCAL and TEMPORARY terms
|
191
|
+
uri = URI(@local_uri_base)
|
192
|
+
uri.path += SecureRandom.uuid # Generate random UUID for local URI
|
193
|
+
uri = uri.to_s
|
194
|
+
return create_term_impl(type, vocabulary_string_key, value, uri, additional_fields)
|
195
|
+
rescue UriService::ExistingUriError
|
196
|
+
next
|
197
|
+
end
|
198
|
+
}
|
199
|
+
# Probabilistically, the error below should never be raised.
|
200
|
+
raise UriService::CouldNotGenerateUriError, "UriService generated a duplicate random UUID (via SecureRandom.uuid) too many times in a row. Probabilistically, this should never happen."
|
222
201
|
end
|
223
202
|
|
224
|
-
return generate_frozen_term_hash(vocabulary_string_key, value, term_uri, additional_fields, is_local)
|
225
203
|
end
|
226
204
|
end
|
227
205
|
|
228
|
-
def
|
206
|
+
def generate_uri_for_temporary_term(vocabulary_string_key, term_value)
|
207
|
+
uri = URI(@temporary_uri_base + Digest::SHA256.hexdigest(vocabulary_string_key + term_value))
|
208
|
+
return uri.to_s
|
209
|
+
end
|
210
|
+
|
211
|
+
def generate_frozen_term_hash(vocabulary_string_key, value, uri, additional_fields, type)
|
229
212
|
hash_to_return = {}
|
230
213
|
hash_to_return['uri'] = uri
|
231
214
|
hash_to_return['value'] = value
|
232
|
-
hash_to_return['
|
215
|
+
hash_to_return['type'] = type
|
233
216
|
hash_to_return['vocabulary_string_key'] = vocabulary_string_key
|
234
217
|
|
235
218
|
additional_fields.each do |key, val|
|
@@ -241,45 +224,43 @@ class UriService::Client
|
|
241
224
|
return hash_to_return
|
242
225
|
end
|
243
226
|
|
244
|
-
def create_term_solr_doc(vocabulary_string_key, value, uri, additional_fields,
|
227
|
+
def create_term_solr_doc(vocabulary_string_key, value, uri, additional_fields, type)
|
245
228
|
doc = {}
|
246
229
|
doc['uri'] = uri
|
247
230
|
doc['value'] = value
|
248
|
-
doc['
|
231
|
+
doc['type'] = type
|
249
232
|
doc['vocabulary_string_key'] = vocabulary_string_key
|
250
233
|
|
251
|
-
additional_fields
|
252
|
-
doc[key + self.class.get_solr_suffix_for_object(val)] = val
|
253
|
-
end
|
234
|
+
doc['additional_fields'] = JSON.generate(additional_fields)
|
254
235
|
|
255
236
|
return doc
|
256
237
|
end
|
257
238
|
|
258
|
-
def self.get_solr_suffix_for_object(obj)
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
end
|
239
|
+
#def self.get_solr_suffix_for_object(obj)
|
240
|
+
# if obj.is_a?(Array)
|
241
|
+
# # Note boolean arrays aren't supported because they don't seem useful in this context
|
242
|
+
# if obj[0].is_a?(Fixnum)
|
243
|
+
# return '_isim'
|
244
|
+
# else
|
245
|
+
# # Treat like a string array
|
246
|
+
# return '_ssim'
|
247
|
+
# end
|
248
|
+
# else
|
249
|
+
# if obj.is_a?(String)
|
250
|
+
# return '_ssi'
|
251
|
+
# elsif obj.is_a?(TrueClass) || obj.is_a?(FalseClass)
|
252
|
+
# return '_bsi'
|
253
|
+
# elsif obj.is_a?(Fixnum)
|
254
|
+
# return '_isi'
|
255
|
+
# else
|
256
|
+
# raise UriService::UnsupportedObjectTypeError, "Unable to determine solr suffix for unsupported object type: #{obj.class.name}"
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
#end
|
279
260
|
|
280
261
|
# Index the DB row term data into solr
|
281
|
-
def send_term_to_solr(vocabulary_string_key, value,
|
282
|
-
doc = create_term_solr_doc(vocabulary_string_key, value,
|
262
|
+
def send_term_to_solr(vocabulary_string_key, value, uri, additional_fields, type, commit=true)
|
263
|
+
doc = create_term_solr_doc(vocabulary_string_key, value, uri, additional_fields, type)
|
283
264
|
@rsolr_pool.with do |rsolr|
|
284
265
|
rsolr.add(doc)
|
285
266
|
rsolr.commit if commit
|
@@ -287,7 +268,7 @@ class UriService::Client
|
|
287
268
|
end
|
288
269
|
|
289
270
|
# Validates additional_fields and verifies that no reserved words are supplied
|
290
|
-
def
|
271
|
+
def validate_additional_field_keys(additional_fields)
|
291
272
|
additional_fields.each do |key, value|
|
292
273
|
if CORE_FIELD_NAMES.include?(key.to_s)
|
293
274
|
raise UriService::InvalidAdditionalFieldKeyError, "Cannot supply the key \"#{key.to_s}\" as an additional field because it is a reserved key."
|
@@ -308,8 +289,14 @@ class UriService::Client
|
|
308
289
|
end
|
309
290
|
end
|
310
291
|
|
311
|
-
# Finds the
|
312
|
-
def
|
292
|
+
# Finds the term with the given uri
|
293
|
+
def find_term_by_uri(uri)
|
294
|
+
results = self.find_terms_where({uri: uri}, 1)
|
295
|
+
return results.length == 1 ? results.first : nil
|
296
|
+
end
|
297
|
+
|
298
|
+
# Finds terms that match the specified conditions
|
299
|
+
def find_terms_where(opts, limit=10)
|
313
300
|
fqs = []
|
314
301
|
|
315
302
|
# Only search on allowed fields
|
@@ -324,14 +311,20 @@ class UriService::Client
|
|
324
311
|
response = rsolr.get('select', params: {
|
325
312
|
:q => '*:*',
|
326
313
|
:fq => fqs,
|
327
|
-
:rows =>
|
328
|
-
:sort => '
|
314
|
+
:rows => limit,
|
315
|
+
:sort => 'value_ssort asc, uri asc' # For consistent sorting
|
316
|
+
# Note: We don't sort by solr score because solr fq searches don't factor into the score
|
329
317
|
})
|
330
|
-
if response['response']['
|
331
|
-
|
318
|
+
if response['response']['docs'].length > 0
|
319
|
+
arr_to_return = []
|
320
|
+
response['response']['docs'].each do |doc|
|
321
|
+
arr_to_return << term_solr_doc_to_frozen_term_hash(doc)
|
322
|
+
end
|
323
|
+
return arr_to_return
|
324
|
+
else
|
325
|
+
return []
|
332
326
|
end
|
333
327
|
end
|
334
|
-
return nil
|
335
328
|
end
|
336
329
|
|
337
330
|
def term_solr_doc_to_frozen_term_hash(term_solr_doc)
|
@@ -339,19 +332,10 @@ class UriService::Client
|
|
339
332
|
uri = term_solr_doc.delete('uri')
|
340
333
|
vocabulary_string_key = term_solr_doc.delete('vocabulary_string_key')
|
341
334
|
value = term_solr_doc.delete('value')
|
342
|
-
|
343
|
-
additional_fields =
|
344
|
-
|
345
|
-
# Iterate through remaining keys and put them in additional_fields after removing suffixes
|
346
|
-
term_solr_doc.each do |key, val|
|
347
|
-
# Skip certain automatically added fields that aren't part of the term_hash
|
348
|
-
next if ['_version_', 'timestamp', 'score'].include?(key)
|
349
|
-
|
350
|
-
# Remove trailing '_si', '_bi', etc. if present for solr-suffixed fields
|
351
|
-
additional_fields[key.gsub(/_[^_]+$/, '')] = val
|
352
|
-
end
|
335
|
+
type = term_solr_doc.delete('type')
|
336
|
+
additional_fields = JSON.parse(term_solr_doc.delete('additional_fields'))
|
353
337
|
|
354
|
-
return generate_frozen_term_hash(vocabulary_string_key, value, uri, additional_fields,
|
338
|
+
return generate_frozen_term_hash(vocabulary_string_key, value, uri, additional_fields, type)
|
355
339
|
end
|
356
340
|
|
357
341
|
def find_terms_by_query(vocabulary_string_key, value_query, limit=10, start=0)
|
@@ -433,12 +417,12 @@ class UriService::Client
|
|
433
417
|
end
|
434
418
|
end
|
435
419
|
|
436
|
-
def delete_term(
|
420
|
+
def delete_term(uri, commit=true)
|
437
421
|
self.handle_database_disconnect do
|
438
422
|
@db.transaction do
|
439
|
-
@db[UriService::TERMS].where(uri:
|
423
|
+
@db[UriService::TERMS].where(uri: uri).delete
|
440
424
|
@rsolr_pool.with do |rsolr|
|
441
|
-
rsolr.delete_by_query('uri:' + UriService.solr_escape(
|
425
|
+
rsolr.delete_by_query('uri:' + UriService.solr_escape(uri))
|
442
426
|
rsolr.commit if commit
|
443
427
|
end
|
444
428
|
end
|
@@ -461,12 +445,15 @@ class UriService::Client
|
|
461
445
|
end
|
462
446
|
|
463
447
|
# opts format: {:value => 'new value', :additional_fields => {'key' => 'value'}}
|
464
|
-
def update_term(
|
448
|
+
def update_term(uri, opts, merge_additional_fields=true)
|
465
449
|
self.handle_database_disconnect do
|
466
|
-
|
467
|
-
raise UriService::NonExistentUriError, "No term found with uri: " +
|
468
|
-
|
469
|
-
term_db_row
|
450
|
+
term_db_row = @db[UriService::TERMS].first(uri: uri)
|
451
|
+
raise UriService::NonExistentUriError, "No term found with uri: " + uri if term_db_row.nil?
|
452
|
+
|
453
|
+
if term_db_row[:type] == UriService::TermType::TEMPORARY
|
454
|
+
# TEMPORARY terms cannot have their values, additional_fields or anything else changed
|
455
|
+
raise UriService::CannotChangeTemporaryTerm, "Temporary terms cannot be changed. Delete unusued temporary terms or create new ones."
|
456
|
+
end
|
470
457
|
|
471
458
|
new_value = opts[:value] || term_db_row[:value]
|
472
459
|
new_additional_fields = term_db_row[:additional_fields].nil? ? {} : JSON.parse(term_db_row[:additional_fields])
|
@@ -479,14 +466,14 @@ class UriService::Client
|
|
479
466
|
new_additional_fields = opts[:additional_fields]
|
480
467
|
end
|
481
468
|
end
|
482
|
-
|
469
|
+
validate_additional_field_keys(new_additional_fields)
|
483
470
|
|
484
471
|
@db.transaction do
|
485
|
-
|
486
|
-
self.send_term_to_solr(term_db_row[:vocabulary_string_key], new_value,
|
472
|
+
@db[UriService::TERMS].where(uri: uri).update(value: new_value, value_hash: Digest::SHA256.hexdigest(new_value), additional_fields: JSON.generate(new_additional_fields))
|
473
|
+
self.send_term_to_solr(term_db_row[:vocabulary_string_key], new_value, uri, new_additional_fields, term_db_row[:type])
|
487
474
|
end
|
488
475
|
|
489
|
-
return generate_frozen_term_hash(term_db_row[:vocabulary_string_key], new_value,
|
476
|
+
return generate_frozen_term_hash(term_db_row[:vocabulary_string_key], new_value, uri, new_additional_fields, term_db_row[:type])
|
490
477
|
end
|
491
478
|
end
|
492
479
|
|
@@ -513,16 +500,95 @@ class UriService::Client
|
|
513
500
|
end
|
514
501
|
end
|
515
502
|
|
503
|
+
#########################
|
504
|
+
# BEGIN PRIVATE METHODS #
|
505
|
+
#########################
|
506
|
+
|
507
|
+
private
|
508
|
+
|
509
|
+
# Backing implementation for actual term creation in db/solr.
|
510
|
+
# - Performs some data validations.
|
511
|
+
# - Ensures uniqueness of URIs in database.
|
512
|
+
# - Returns an existing TEMPORARY term if a user attempts to
|
513
|
+
# create a new TEMPORARY term with an existing value/vocabulary combo.
|
514
|
+
def create_term_impl(type, vocabulary_string_key, value, uri, additional_fields)
|
515
|
+
self.handle_database_disconnect do
|
516
|
+
|
517
|
+
if type == UriService::TermType::TEMPORARY
|
518
|
+
# If this is a TEMPORARY term, we need to ensure that the temporary
|
519
|
+
# passed in URI is a hash of the vocabulary + value, just in case this
|
520
|
+
# method is ever called directly instead of through the create_term
|
521
|
+
# wrapper method. This is to ensure that our expectations about the
|
522
|
+
# uniqueness of TEMPORARY term values is never violated.
|
523
|
+
unless uri == self.generate_uri_for_temporary_term(vocabulary_string_key, value)
|
524
|
+
raise UriService::InvalidTemporaryTermUriError, "The supplied URI was not derived from the supplied (vocabulary_string_key+value) pair."
|
525
|
+
end
|
526
|
+
|
527
|
+
# TEMPORARY terms are not meant to hold data in additional_fields.
|
528
|
+
if additional_fields.size > 0
|
529
|
+
raise UriService::InvalidOptsError, "Terms of type #{type} cannot have additional_fields."
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
unless uri =~ UriService::VALID_URI_REGEX
|
534
|
+
raise UriService::InvalidUriError, "Invalid URI supplied during term creation: #{uri}"
|
535
|
+
end
|
536
|
+
|
537
|
+
#Ensure that vocabulary with vocabulary_string_key exists
|
538
|
+
if self.find_vocabulary(vocabulary_string_key).nil?
|
539
|
+
raise UriService::NonExistentVocabularyError, "There is no vocabulary with string key: " + vocabulary_string_key
|
540
|
+
end
|
541
|
+
|
542
|
+
# Stringify and validate keys for additional_fields
|
543
|
+
additional_fields.stringify_keys!
|
544
|
+
validate_additional_field_keys(additional_fields) # This method call raises an error if an invalid additional_field key is supplied
|
545
|
+
|
546
|
+
@db.transaction do
|
547
|
+
value_hash = Digest::SHA256.hexdigest(value)
|
548
|
+
|
549
|
+
begin
|
550
|
+
@db[UriService::TERMS].insert(
|
551
|
+
type: type,
|
552
|
+
uri: uri,
|
553
|
+
uri_hash: Digest::SHA256.hexdigest(uri),
|
554
|
+
value: value,
|
555
|
+
value_hash: value_hash,
|
556
|
+
vocabulary_string_key: vocabulary_string_key,
|
557
|
+
additional_fields: JSON.generate(additional_fields)
|
558
|
+
)
|
559
|
+
send_term_to_solr(vocabulary_string_key, value, uri, additional_fields, type)
|
560
|
+
rescue Sequel::UniqueConstraintViolation
|
561
|
+
|
562
|
+
# If this is a new TEMPORARY term and we ran into a Sequel::UniqueConstraintViolation,
|
563
|
+
# that mean that the term already exists. We should return that existing term.
|
564
|
+
# don't create a new one. Instead, return the existing one.
|
565
|
+
if type == UriService::TermType::TEMPORARY
|
566
|
+
return self.find_term_by_uri(uri)
|
567
|
+
end
|
568
|
+
|
569
|
+
raise UriService::ExistingUriError, "A term already exists with uri: " + uri + " (conflict found via uri_hash check)"
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
return generate_frozen_term_hash(vocabulary_string_key, value, uri, additional_fields, type)
|
574
|
+
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
516
579
|
end
|
517
580
|
|
581
|
+
class UriService::CannotChangeTemporaryTerm < StandardError;end
|
582
|
+
class UriService::CouldNotGenerateUriError < StandardError;end
|
518
583
|
class UriService::InvalidAdditionalFieldKeyError < StandardError;end
|
519
|
-
class UriService::InvalidVocabularyStringKeyError < StandardError;end
|
520
584
|
class UriService::InvalidOptsError < StandardError;end
|
585
|
+
class UriService::InvalidTemporaryTermUriError < StandardError;end
|
586
|
+
class UriService::InvalidTermTypeError < StandardError;end
|
521
587
|
class UriService::InvalidUriError < StandardError;end
|
588
|
+
class UriService::InvalidVocabularyStringKeyError < StandardError;end
|
522
589
|
class UriService::ExistingUriError < StandardError;end
|
523
590
|
class UriService::ExistingVocabularyStringKeyError < StandardError;end
|
524
591
|
class UriService::NonExistentUriError < StandardError;end
|
525
592
|
class UriService::NonExistentVocabularyError < StandardError;end
|
526
593
|
class UriService::UnsupportedObjectTypeError < StandardError;end
|
527
|
-
class UriService::UnsupportedSearchFieldError < StandardError;end
|
528
|
-
class UriService::DisallowedDuplicateLocalTermValueError < StandardError;end
|
594
|
+
class UriService::UnsupportedSearchFieldError < StandardError;end
|
data/lib/uri_service/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uri_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric O'Hanlon
|
@@ -179,6 +179,7 @@ files:
|
|
179
179
|
- lib/uri_service.rb
|
180
180
|
- lib/uri_service/client.rb
|
181
181
|
- lib/uri_service/railtie.rb
|
182
|
+
- lib/uri_service/term_type.rb
|
182
183
|
- lib/uri_service/version.rb
|
183
184
|
homepage: https://github.com/cul/uri_service
|
184
185
|
licenses:
|
@@ -206,4 +207,3 @@ specification_version: 4
|
|
206
207
|
summary: A service for registering local URIs and performing both local and remote
|
207
208
|
URI lookups.
|
208
209
|
test_files: []
|
209
|
-
has_rdoc:
|