uri_service 0.5.5 → 0.6.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 +5 -5
- data/README.md +7 -5
- data/lib/tasks/uri_service/ci.rake +31 -58
- data/lib/tasks/uri_service/docker.rake +127 -0
- data/lib/uri_service/client.rb +105 -103
- data/lib/uri_service/version.rb +5 -5
- data/lib/uri_service.rb +10 -8
- metadata +46 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2a5e8309e33cf98f187e5f1dc39e5b0c52ea9098146cec6d417c7b4304b7cadc
|
4
|
+
data.tar.gz: d05d94ac0bbb449c1492a93fe4ad121dc8399a07843179899794ebdd8293b000
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 419b95b61f9acd1f729543b49ba530f8f1112a3b5d22aebb1a9ea1308e2fd64057dfbd5a674ab65b2d617d04fc7158ab4367c8dac7e626b66264ad09969f86b6
|
7
|
+
data.tar.gz: 6de069fd580769f921b9ca9780a201bc2410f3e7b0f908740b93b37c1935b4b205db662b29c11e8e3d8faf381bfa6d44821f0d6299f21996d06a3a95d54f195c
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
A database-backed and Solr-cached lookup/creation service for URIs. Works with or without Rails.
|
4
4
|
|
5
|
+
Note: Version 0.6.x and later are meant for use with Solr 8.
|
6
|
+
|
5
7
|
### Major Concepts:
|
6
8
|
|
7
9
|
**External Term (UriService::TermType::EXTERNAL)**
|
@@ -31,7 +33,7 @@ UriService::init({
|
|
31
33
|
'local_uri_base' => 'http://id.example.com/term/',
|
32
34
|
'temporary_uri_base' => 'com:example:id:temporary:',
|
33
35
|
'solr' => {
|
34
|
-
'url' => 'http://localhost:8983/solr/
|
36
|
+
'url' => 'http://localhost:8983/solr/uri_service',
|
35
37
|
'pool_size' => 5,
|
36
38
|
'pool_timeout' => 5000
|
37
39
|
}
|
@@ -53,7 +55,7 @@ client = UriService::Client.new({
|
|
53
55
|
'local_uri_base' => 'http://id.example.com/term/',
|
54
56
|
'temporary_uri_base' => 'com:example:id:temporary:',
|
55
57
|
'solr' => {
|
56
|
-
'url' => 'http://localhost:8983/solr/
|
58
|
+
'url' => 'http://localhost:8983/solr/uri_service',
|
57
59
|
'pool_size' => 5,
|
58
60
|
'pool_timeout' => 5000
|
59
61
|
}
|
@@ -83,7 +85,7 @@ development:
|
|
83
85
|
local_uri_base: 'http://id.example.com/term/'
|
84
86
|
temporary_uri_base: 'com:example:id:temporary:'
|
85
87
|
solr:
|
86
|
-
url: 'http://localhost:8983/solr/
|
88
|
+
url: 'http://localhost:8983/solr/uri_service'
|
87
89
|
pool_size: 5
|
88
90
|
pool_timeout: 5000
|
89
91
|
database:
|
@@ -96,7 +98,7 @@ test:
|
|
96
98
|
local_uri_base: 'http://id.example.com/term/'
|
97
99
|
temporary_uri_base: 'com:example:id:temporary:'
|
98
100
|
solr:
|
99
|
-
url: 'http://localhost:
|
101
|
+
url: 'http://localhost:9983/solr/uri_service'
|
100
102
|
pool_size: 5
|
101
103
|
pool_timeout: 5000
|
102
104
|
database:
|
@@ -109,7 +111,7 @@ production:
|
|
109
111
|
local_uri_base: 'http://id.example.com/term/'
|
110
112
|
temporary_uri_base: 'com:example:id:temporary:'
|
111
113
|
solr:
|
112
|
-
url: 'http://localhost:
|
114
|
+
url: 'http://localhost:8983/solr/uri_service_prod'
|
113
115
|
pool_size: 5
|
114
116
|
pool_timeout: 5000
|
115
117
|
database:
|
@@ -19,13 +19,15 @@ namespace :uri_service do
|
|
19
19
|
puts "[Warning] Exception creating rspec rake tasks. This message can be ignored in environments that intentionally do not pull in the RSpec gem (i.e. production)."
|
20
20
|
puts e
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
desc "CI build"
|
24
24
|
task :ci do
|
25
|
-
|
26
|
-
|
25
|
+
ENV['APP_ENV'] = 'test'
|
26
|
+
Rake::Task["uri_service:ci_prepare"].invoke
|
27
|
+
Rake::Task["uri_service:docker:setup_config_files"].invoke
|
28
|
+
Rake::Task["uri_service:ci_impl"].invoke
|
27
29
|
end
|
28
|
-
|
30
|
+
|
29
31
|
desc "Preparation steps for the CI run"
|
30
32
|
task :ci_prepare do
|
31
33
|
# Delete existing test database
|
@@ -36,65 +38,36 @@ namespace :uri_service do
|
|
36
38
|
client.create_required_tables
|
37
39
|
FileUtils.mkdir_p('tmp')
|
38
40
|
end
|
39
|
-
|
40
|
-
desc
|
41
|
-
task
|
42
|
-
|
43
|
-
|
44
|
-
FileUtils.rm_rf(instance_dir)
|
45
|
-
|
46
|
-
puts "Unpacking and starting solr...\n"
|
47
|
-
SolrWrapper.wrap({
|
48
|
-
port: 9983,
|
49
|
-
version: solr_version,
|
50
|
-
verbose: false,
|
51
|
-
mirror_url: 'http://lib-solr-mirror.princeton.edu/dist/',
|
52
|
-
managed: true,
|
53
|
-
download_path: File.join('tmp', "solr-#{solr_version}.zip"),
|
54
|
-
instance_dir: instance_dir,
|
55
|
-
}) do |solr_wrapper_instance|
|
56
|
-
|
57
|
-
# Create collection
|
58
|
-
solr_wrapper_instance.with_collection(name: 'uri_service_test', dir: File.join('spec/fixtures', 'uri_service_test_cores/uri_service_test-solr6-conf')) do |collection_name|
|
41
|
+
|
42
|
+
desc 'CI build just running specs'
|
43
|
+
task :ci_impl do
|
44
|
+
docker_wrapper do
|
45
|
+
duration = Benchmark.realtime do
|
59
46
|
Rake::Task["uri_service:rspec"].invoke
|
60
47
|
end
|
61
|
-
|
62
|
-
puts 'Stopping solr...'
|
48
|
+
puts "\nCI run finished in #{duration} seconds."
|
63
49
|
end
|
64
50
|
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
Jettywrapper.url = "https://github.com/cul/hydra-jetty/archive/solr-only.zip"
|
70
|
-
Jettywrapper.jetty_dir = File.join('tmp', 'jetty-test')
|
71
|
-
|
72
|
-
unless File.exists?(Jettywrapper.jetty_dir)
|
73
|
-
puts "\n" + 'No test jetty found. Will download / unzip a copy now.' + "\n"
|
51
|
+
|
52
|
+
def docker_wrapper(&block)
|
53
|
+
unless ENV['APP_ENV'] == 'test'
|
54
|
+
raise 'This task should only be run in the test environment (because it clears docker volumes)'
|
74
55
|
end
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
jetty_port: 9983,
|
90
|
-
java_version: '>= 1.8',
|
91
|
-
java_opts: ["-XX:MaxPermSize=128m", "-Xmx256m"]
|
92
|
-
})
|
93
|
-
error = Jettywrapper.wrap(jetty_params) do
|
94
|
-
Rake::Task["uri_service:rspec"].invoke
|
56
|
+
|
57
|
+
# Stop docker if it's currently running (so we can delete any old volumes)
|
58
|
+
Rake::Task['uri_service:docker:stop'].invoke
|
59
|
+
# Rake tasks must be re-enabled if you want to call them again later during the same run
|
60
|
+
Rake::Task['uri_service:docker:stop'].reenable
|
61
|
+
|
62
|
+
ENV['app_env_confirmation'] = ENV['APP_ENV'] # setting this to skip prompt in volume deletion task
|
63
|
+
Rake::Task['uri_service:docker:delete_volumes'].invoke
|
64
|
+
|
65
|
+
Rake::Task['uri_service:docker:start'].invoke
|
66
|
+
begin
|
67
|
+
block.call
|
68
|
+
ensure
|
69
|
+
Rake::Task['uri_service:docker:stop'].invoke
|
95
70
|
end
|
96
|
-
raise "test failures: #{error}" if error
|
97
|
-
|
98
71
|
end
|
99
72
|
|
100
|
-
end
|
73
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'open3'
|
3
|
+
require 'net/http'
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
namespace :uri_service do
|
7
|
+
namespace :docker do
|
8
|
+
def docker_compose_file_path
|
9
|
+
UriService.root.join("docker/docker-compose.#{ENV['APP_ENV']}.yml")
|
10
|
+
end
|
11
|
+
|
12
|
+
def docker_compose_config
|
13
|
+
YAML.load_file(docker_compose_file_path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def wait_for_solr_cores_to_load
|
17
|
+
expected_port = docker_compose_config['services']['solr']['ports'][0].split(':')[0]
|
18
|
+
url_to_check = "http://localhost:#{expected_port}/solr/uri_service/admin/system"
|
19
|
+
puts "Waiting for Solr to become available (at #{url_to_check})..."
|
20
|
+
Timeout.timeout(20, Timeout::Error, 'Timed out during Solr startup check.') do
|
21
|
+
loop do
|
22
|
+
begin
|
23
|
+
sleep 0.25
|
24
|
+
status_code = Net::HTTP.get_response(URI(url_to_check)).code
|
25
|
+
if status_code == '200' # Solr is ready to receive requests
|
26
|
+
puts 'Solr is available.'
|
27
|
+
break
|
28
|
+
end
|
29
|
+
rescue EOFError, Errno::ECONNRESET => e
|
30
|
+
# Try again in response to the above error types
|
31
|
+
next
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def running?
|
38
|
+
status = `docker compose -f #{UriService.root.join(docker_compose_file_path)} ps`
|
39
|
+
status.split("n").count > 1
|
40
|
+
end
|
41
|
+
|
42
|
+
task :setup_config_files do
|
43
|
+
docker_compose_template_dir = UriService.root.join('docker/templates')
|
44
|
+
docker_compose_dest_dir = UriService.root.join('docker')
|
45
|
+
Dir.foreach(docker_compose_template_dir) do |entry|
|
46
|
+
next unless entry.end_with?('.yml')
|
47
|
+
src_path = File.join(docker_compose_template_dir, entry)
|
48
|
+
dst_path = File.join(docker_compose_dest_dir, entry.gsub('.template', ''))
|
49
|
+
if File.exist?(dst_path)
|
50
|
+
puts Rainbow("File already exists (skipping): #{dst_path}").blue.bright + "\n"
|
51
|
+
else
|
52
|
+
FileUtils.cp(src_path, dst_path)
|
53
|
+
puts Rainbow("Created file at: #{dst_path}").green
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
task :start do
|
59
|
+
puts "Starting...\n"
|
60
|
+
if running?
|
61
|
+
puts "\nAlready running."
|
62
|
+
else
|
63
|
+
# NOTE: This command rebuilds the container images before each run, to ensure they're
|
64
|
+
# always up to date. In most cases, the overhead is minimal if the Dockerfile for an image
|
65
|
+
# hasn't changed since the last build.
|
66
|
+
`docker compose -f #{docker_compose_file_path} up --build --detach --wait`
|
67
|
+
wait_for_solr_cores_to_load
|
68
|
+
puts "\nStarted."
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
task :stop do
|
73
|
+
puts "Stopping...\n"
|
74
|
+
if running?
|
75
|
+
puts "\n"
|
76
|
+
`docker compose -f #{UriService.root.join(docker_compose_file_path)} down`
|
77
|
+
puts "\nStopped"
|
78
|
+
else
|
79
|
+
puts "Already stopped."
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
task :restart do
|
84
|
+
Rake::Task['uri_service:docker:stop'].invoke
|
85
|
+
Rake::Task['uri_service:docker:start'].invoke
|
86
|
+
end
|
87
|
+
|
88
|
+
task :status do
|
89
|
+
puts running? ? 'Running.' : 'Not running.'
|
90
|
+
end
|
91
|
+
|
92
|
+
task :delete_volumes do
|
93
|
+
if running?
|
94
|
+
puts 'Error: The volumes are currently in use. Please stop the docker services before deleting the volumes.'
|
95
|
+
next
|
96
|
+
end
|
97
|
+
|
98
|
+
puts Rainbow("This will delete ALL Solr data for the selected app "\
|
99
|
+
"environment (#{ENV['APP_ENV']}) and cannot be undone. Please confirm that you want to continue "\
|
100
|
+
"by typing the name of the selected Rails environment (#{ENV['APP_ENV']}):").red.bright
|
101
|
+
print '> '
|
102
|
+
response = ENV['app_env_confirmation'] || $stdin.gets.chomp
|
103
|
+
|
104
|
+
puts ""
|
105
|
+
|
106
|
+
if response != ENV['APP_ENV']
|
107
|
+
puts "Aborting because \"#{ENV['APP_ENV']}\" was not entered."
|
108
|
+
next
|
109
|
+
end
|
110
|
+
|
111
|
+
config = docker_compose_config
|
112
|
+
volume_prefix = config['name']
|
113
|
+
full_volume_names = config['volumes'].keys.map { |short_name| "#{volume_prefix}_#{short_name}" }
|
114
|
+
|
115
|
+
full_volume_names.map do |full_volume_name|
|
116
|
+
if JSON.parse(Open3.capture3("docker volume inspect '#{full_volume_name}'")[0]).length.positive?
|
117
|
+
`docker volume rm '#{full_volume_name}'`
|
118
|
+
puts Rainbow("Deleted: #{full_volume_name}").green
|
119
|
+
else
|
120
|
+
puts Rainbow("Skipped: #{full_volume_name} (already deleted)").blue.bright
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
puts 'Done.'
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/uri_service/client.rb
CHANGED
@@ -1,31 +1,33 @@
|
|
1
1
|
class UriService::Client
|
2
|
-
|
2
|
+
|
3
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
6
|
CORE_FIELD_NAMES = ['uri', 'vocabulary_string_key', 'value', 'authority', 'type', 'internal_id']
|
7
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
11
|
raise UriService::InvalidOptsError, "Must supply opts['temporary_uri_base'] to initialize method." if opts['temporary_uri_base'].nil?
|
12
12
|
raise UriService::InvalidOptsError, "Must supply opts['database'] to initialize method." if opts['database'].nil?
|
13
13
|
raise UriService::InvalidOptsError, "Must supply opts['solr'] to initialize method." if opts['solr'].nil?
|
14
|
-
|
14
|
+
|
15
15
|
# Set local_uri_base and temporary_uri_base
|
16
16
|
@local_uri_base = opts['local_uri_base']
|
17
17
|
@temporary_uri_base = opts['temporary_uri_base']
|
18
|
-
|
18
|
+
|
19
19
|
# Create DB connection pool
|
20
20
|
@db = Sequel.connect(opts['database'])
|
21
|
-
|
21
|
+
|
22
22
|
# Create Solr connection pool
|
23
23
|
@rsolr_pool = ConnectionPool.new( size: opts['solr']['pool_size'], timeout: (opts['solr']['pool_timeout'].to_f/1000.to_f) ) { RSolr.connect(:url => opts['solr']['url']) }
|
24
|
+
|
25
|
+
@auto_commit_after_term_creation = opts['solr'].fetch('auto_commit_after_term_creation', true).to_s == 'true'
|
24
26
|
end
|
25
|
-
|
27
|
+
|
26
28
|
def reindex_all_terms(clear=false, print_progress_to_console=false)
|
27
29
|
self.handle_database_disconnect do
|
28
|
-
|
30
|
+
|
29
31
|
if print_progress_to_console
|
30
32
|
puts "Getting database term count..."
|
31
33
|
total = @db[UriService::TERMS].count
|
@@ -33,13 +35,13 @@ class UriService::Client
|
|
33
35
|
puts "Number of terms to index: #{total.to_s}"
|
34
36
|
puts ""
|
35
37
|
end
|
36
|
-
|
38
|
+
|
37
39
|
if clear
|
38
40
|
@rsolr_pool.with do |rsolr|
|
39
41
|
rsolr.delete_by_query('*:*');
|
40
42
|
end
|
41
43
|
end
|
42
|
-
|
44
|
+
|
43
45
|
# Need to use unambiguous order when using paged_each, so we choose to order by DB :id
|
44
46
|
@db[UriService::TERMS].order(:id).paged_each(:rows_per_fetch=>100) do |term_db_row|
|
45
47
|
self.send_term_to_solr(
|
@@ -51,26 +53,26 @@ class UriService::Client
|
|
51
53
|
term_db_row[:type],
|
52
54
|
term_db_row[:id],
|
53
55
|
false)
|
54
|
-
|
56
|
+
|
55
57
|
if print_progress_to_console
|
56
58
|
reindex_counter += 1
|
57
59
|
print "\rIndexed #{reindex_counter.to_s} of #{total.to_s}"
|
58
60
|
end
|
59
61
|
end
|
60
|
-
|
62
|
+
|
61
63
|
puts "\n" + "Committing solr updates..." if print_progress_to_console
|
62
64
|
self.do_solr_commit
|
63
65
|
puts "Done." if print_progress_to_console
|
64
66
|
end
|
65
67
|
end
|
66
|
-
|
68
|
+
|
67
69
|
def disconnect!
|
68
70
|
unless @db.nil?
|
69
71
|
db_reference = @db
|
70
72
|
@db = nil
|
71
73
|
db_reference.disconnect
|
72
74
|
end
|
73
|
-
|
75
|
+
|
74
76
|
unless @rsolr_pool.nil?
|
75
77
|
rsolr_pool_reference = @rsolr_pool
|
76
78
|
@rsolr_pool = nil
|
@@ -79,10 +81,10 @@ class UriService::Client
|
|
79
81
|
# but this doesn't hurt.
|
80
82
|
end
|
81
83
|
end
|
82
|
-
|
84
|
+
|
83
85
|
def connected?
|
84
86
|
return false if @db.nil? || @rsolr_pool.nil?
|
85
|
-
|
87
|
+
|
86
88
|
begin
|
87
89
|
self.test_connection
|
88
90
|
return true
|
@@ -90,23 +92,23 @@ class UriService::Client
|
|
90
92
|
return false
|
91
93
|
end
|
92
94
|
end
|
93
|
-
|
95
|
+
|
94
96
|
def test_connection
|
95
97
|
@db.test_connection # Raises Sequel::DatabaseConnectionError if connection didn't work
|
96
98
|
@rsolr_pool.with do |rsolr|
|
97
|
-
rsolr.get('admin/
|
99
|
+
rsolr.get('admin/system') # Raises Errno::ECONNREFUSED if connection didn't work
|
98
100
|
end
|
99
101
|
end
|
100
|
-
|
102
|
+
|
101
103
|
def required_tables_exist?
|
102
104
|
return (UriService.required_tables - @db.tables).length == 0
|
103
105
|
end
|
104
|
-
|
106
|
+
|
105
107
|
def create_required_tables
|
106
108
|
self.handle_database_disconnect do
|
107
|
-
|
109
|
+
|
108
110
|
current_tables = @db.tables
|
109
|
-
|
111
|
+
|
110
112
|
unless current_tables.include?(UriService::VOCABULARIES)
|
111
113
|
@db.create_table UriService::VOCABULARIES do |t|
|
112
114
|
primary_key :id
|
@@ -117,7 +119,7 @@ class UriService::Client
|
|
117
119
|
else
|
118
120
|
puts 'Skipped creation of table ' + UriService::VOCABULARIES.to_s + ' because it already exists.'
|
119
121
|
end
|
120
|
-
|
122
|
+
|
121
123
|
unless current_tables.include?(UriService::TERMS)
|
122
124
|
@db.create_table UriService::TERMS do |t|
|
123
125
|
primary_key :id
|
@@ -134,14 +136,14 @@ class UriService::Client
|
|
134
136
|
else
|
135
137
|
puts 'Skipped creation of table ' + UriService::TERMS.to_s + ' because it already exists.'
|
136
138
|
end
|
137
|
-
|
139
|
+
|
138
140
|
end
|
139
141
|
end
|
140
|
-
|
142
|
+
|
141
143
|
##################
|
142
144
|
# Create methods #
|
143
145
|
##################
|
144
|
-
|
146
|
+
|
145
147
|
def create_vocabulary(string_key, display_label)
|
146
148
|
self.handle_database_disconnect do
|
147
149
|
if string_key.to_s == 'all'
|
@@ -151,7 +153,7 @@ class UriService::Client
|
|
151
153
|
unless string_key =~ ALPHANUMERIC_UNDERSCORE_KEY_REGEX
|
152
154
|
raise UriService::InvalidVocabularyStringKeyError, "Invalid key (can only include lower case letters, numbers or underscores, but cannot start with an underscore): " + string_key
|
153
155
|
end
|
154
|
-
|
156
|
+
|
155
157
|
@db.transaction do
|
156
158
|
begin
|
157
159
|
@db[UriService::VOCABULARIES].insert(string_key: string_key, display_label: display_label)
|
@@ -161,27 +163,27 @@ class UriService::Client
|
|
161
163
|
end
|
162
164
|
end
|
163
165
|
end
|
164
|
-
|
166
|
+
|
165
167
|
# Creates a new term
|
166
168
|
def create_term(type, opts)
|
167
169
|
raise UriService::InvalidTermTypeError, 'Invalid type: ' + type unless VALID_TYPES.include?(type)
|
168
|
-
|
170
|
+
|
169
171
|
vocabulary_string_key = opts.delete(:vocabulary_string_key)
|
170
172
|
value = opts.delete(:value)
|
171
173
|
uri = opts.delete(:uri)
|
172
174
|
authority = opts.has_key?(:authority) ? opts.delete(:authority) : ''
|
173
175
|
authority = '' if authority.nil?
|
174
176
|
additional_fields = opts.delete(:additional_fields) || {}
|
175
|
-
|
177
|
+
|
176
178
|
if type == UriService::TermType::EXTERNAL
|
177
179
|
# URI is required
|
178
180
|
raise UriService::InvalidOptsError, "A uri must be supplied for terms of type #{type}." if uri.nil?
|
179
|
-
|
181
|
+
|
180
182
|
return create_term_impl(type, vocabulary_string_key, value, uri, authority, additional_fields)
|
181
183
|
else
|
182
184
|
# URI should not be present
|
183
185
|
raise UriService::InvalidOptsError, "A uri cannot supplied for term type: #{type}" unless uri.nil?
|
184
|
-
|
186
|
+
|
185
187
|
if type == UriService::TermType::TEMPORARY
|
186
188
|
# 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.
|
187
189
|
uri = self.generate_uri_for_temporary_term(vocabulary_string_key, value)
|
@@ -204,15 +206,15 @@ class UriService::Client
|
|
204
206
|
# Probabilistically, the error below should never be raised.
|
205
207
|
raise UriService::CouldNotGenerateUriError, "UriService generated a duplicate random UUID (via SecureRandom.uuid) too many times in a row. Probabilistically, this should never happen."
|
206
208
|
end
|
207
|
-
|
209
|
+
|
208
210
|
end
|
209
211
|
end
|
210
|
-
|
212
|
+
|
211
213
|
def generate_uri_for_temporary_term(vocabulary_string_key, term_value)
|
212
214
|
uri = URI(@temporary_uri_base + Digest::SHA256.hexdigest(vocabulary_string_key + term_value))
|
213
215
|
return uri.to_s
|
214
216
|
end
|
215
|
-
|
217
|
+
|
216
218
|
def generate_frozen_term_hash(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id)
|
217
219
|
hash_to_return = {}
|
218
220
|
hash_to_return['uri'] = uri
|
@@ -221,20 +223,20 @@ class UriService::Client
|
|
221
223
|
hash_to_return['authority'] = authority unless authority == ''
|
222
224
|
hash_to_return['vocabulary_string_key'] = vocabulary_string_key
|
223
225
|
hash_to_return['internal_id'] = internal_id
|
224
|
-
|
226
|
+
|
225
227
|
additional_fields.each do |key, val|
|
226
228
|
hash_to_return[key] = val
|
227
229
|
end
|
228
|
-
|
230
|
+
|
229
231
|
# Delete nil values
|
230
232
|
hash_to_return.delete_if { |k, v| v.nil? }
|
231
|
-
|
233
|
+
|
232
234
|
# Freeze hash
|
233
235
|
hash_to_return.freeze # To make this a read-only hash
|
234
|
-
|
236
|
+
|
235
237
|
return hash_to_return
|
236
238
|
end
|
237
|
-
|
239
|
+
|
238
240
|
def create_term_solr_doc(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id)
|
239
241
|
doc = {}
|
240
242
|
doc['uri'] = uri
|
@@ -243,21 +245,21 @@ class UriService::Client
|
|
243
245
|
doc['vocabulary_string_key'] = vocabulary_string_key
|
244
246
|
doc['authority'] = authority
|
245
247
|
doc['internal_id'] = internal_id
|
246
|
-
|
248
|
+
|
247
249
|
doc['additional_fields'] = JSON.generate(additional_fields)
|
248
|
-
|
250
|
+
|
249
251
|
return doc
|
250
252
|
end
|
251
|
-
|
253
|
+
|
252
254
|
# Index the DB row term data into solr
|
253
|
-
def send_term_to_solr(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id, commit=
|
255
|
+
def send_term_to_solr(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id, commit = @auto_commit_after_term_creation)
|
254
256
|
doc = create_term_solr_doc(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id)
|
255
257
|
@rsolr_pool.with do |rsolr|
|
256
258
|
rsolr.add(doc)
|
257
259
|
rsolr.commit if commit
|
258
260
|
end
|
259
261
|
end
|
260
|
-
|
262
|
+
|
261
263
|
# Validates additional_fields and verifies that no reserved words are supplied
|
262
264
|
def validate_additional_field_keys(additional_fields)
|
263
265
|
additional_fields.each do |key, value|
|
@@ -269,41 +271,41 @@ class UriService::Client
|
|
269
271
|
end
|
270
272
|
end
|
271
273
|
end
|
272
|
-
|
274
|
+
|
273
275
|
################
|
274
276
|
# Find methods #
|
275
277
|
################
|
276
|
-
|
278
|
+
|
277
279
|
def find_vocabulary(vocabulary_string_key)
|
278
280
|
self.handle_database_disconnect do
|
279
281
|
@db[UriService::VOCABULARIES].where(string_key: vocabulary_string_key).first
|
280
282
|
end
|
281
283
|
end
|
282
|
-
|
284
|
+
|
283
285
|
# Finds the term with the given uri
|
284
286
|
def find_term_by_uri(uri)
|
285
287
|
results = self.find_terms_where({uri: uri}, 1)
|
286
288
|
return results.length == 1 ? results.first : nil
|
287
289
|
end
|
288
|
-
|
290
|
+
|
289
291
|
# Finds the term with the given uri
|
290
292
|
def find_term_by_internal_id(id)
|
291
293
|
results = self.find_terms_where({internal_id: id}, 1)
|
292
294
|
return results.length == 1 ? results.first : nil
|
293
295
|
end
|
294
|
-
|
296
|
+
|
295
297
|
# Finds terms that match the specified conditions
|
296
298
|
def find_terms_where(opts, limit=10)
|
297
299
|
fqs = []
|
298
|
-
|
300
|
+
|
299
301
|
# Only search on allowed fields
|
300
302
|
unsupported_search_fields = opts.map{|key, val| key.to_s} - CORE_FIELD_NAMES
|
301
303
|
raise UriService::UnsupportedSearchFieldError, "Unsupported search fields: #{unsupported_search_fields.join(', ')}" if unsupported_search_fields.present?
|
302
|
-
|
304
|
+
|
303
305
|
opts.each do |field_name, val|
|
304
306
|
fqs << (field_name.to_s + ':"' + UriService.solr_escape(val.to_s) + '"')
|
305
307
|
end
|
306
|
-
|
308
|
+
|
307
309
|
@rsolr_pool.with do |rsolr|
|
308
310
|
response = rsolr.get('select', params: {
|
309
311
|
:q => '*:*',
|
@@ -323,9 +325,9 @@ class UriService::Client
|
|
323
325
|
end
|
324
326
|
end
|
325
327
|
end
|
326
|
-
|
328
|
+
|
327
329
|
def term_solr_doc_to_frozen_term_hash(term_solr_doc)
|
328
|
-
|
330
|
+
|
329
331
|
uri = term_solr_doc.delete('uri')
|
330
332
|
vocabulary_string_key = term_solr_doc.delete('vocabulary_string_key')
|
331
333
|
value = term_solr_doc.delete('value')
|
@@ -333,19 +335,19 @@ class UriService::Client
|
|
333
335
|
type = term_solr_doc.delete('type')
|
334
336
|
additional_fields = JSON.parse(term_solr_doc.delete('additional_fields'))
|
335
337
|
internal_id = term_solr_doc.delete('internal_id')
|
336
|
-
|
338
|
+
|
337
339
|
return generate_frozen_term_hash(vocabulary_string_key, value, uri, authority, additional_fields, type, internal_id)
|
338
340
|
end
|
339
|
-
|
341
|
+
|
340
342
|
def find_terms_by_query(vocabulary_string_key, value_query, limit=10, start=0)
|
341
|
-
|
343
|
+
|
342
344
|
if value_query.blank?
|
343
345
|
return self.list_terms(vocabulary_string_key, limit, start)
|
344
346
|
end
|
345
|
-
|
347
|
+
|
346
348
|
terms_to_return = []
|
347
349
|
@rsolr_pool.with do |rsolr|
|
348
|
-
|
350
|
+
|
349
351
|
solr_params = {
|
350
352
|
:q => UriService.solr_escape(value_query),
|
351
353
|
:fq => 'vocabulary_string_key:' + UriService.solr_escape(vocabulary_string_key),
|
@@ -353,15 +355,15 @@ class UriService::Client
|
|
353
355
|
:start => start,
|
354
356
|
:sort => 'score desc, value_ssort asc, uri asc' # For consistent sorting
|
355
357
|
}
|
356
|
-
|
358
|
+
|
357
359
|
if value_query.length < 3
|
358
360
|
# For efficiency, we only do whole term matches for queries < 3 characters
|
359
361
|
solr_params[:qf] = 'value_suggest'
|
360
362
|
solr_params[:pf] = 'value_suggest'
|
361
363
|
end
|
362
|
-
|
364
|
+
|
363
365
|
response = rsolr.get('suggest', params: solr_params)
|
364
|
-
|
366
|
+
|
365
367
|
if response['response']['numFound'] > 0
|
366
368
|
response['response']['docs'].each do |doc|
|
367
369
|
terms_to_return << term_solr_doc_to_frozen_term_hash(doc)
|
@@ -370,11 +372,11 @@ class UriService::Client
|
|
370
372
|
end
|
371
373
|
return terms_to_return
|
372
374
|
end
|
373
|
-
|
375
|
+
|
374
376
|
################
|
375
377
|
# List methods #
|
376
378
|
################
|
377
|
-
|
379
|
+
|
378
380
|
# Lists vocabularies alphabetically (by string key) and supports paging through results.
|
379
381
|
def list_vocabularies(limit=10, start=0)
|
380
382
|
self.handle_database_disconnect do
|
@@ -382,13 +384,13 @@ class UriService::Client
|
|
382
384
|
return db_rows.map{|row| row.except(:id).stringify_keys!}
|
383
385
|
end
|
384
386
|
end
|
385
|
-
|
387
|
+
|
386
388
|
# Lists terms alphabetically and supports paging through results.
|
387
389
|
# Useful for browsing through a term list without a query.
|
388
390
|
def list_terms(vocabulary_string_key, limit=10, start=0)
|
389
391
|
terms_to_return = []
|
390
392
|
@rsolr_pool.with do |rsolr|
|
391
|
-
|
393
|
+
|
392
394
|
solr_params = {
|
393
395
|
:fq => 'vocabulary_string_key:' + UriService.solr_escape(vocabulary_string_key),
|
394
396
|
:q => '*:*',
|
@@ -396,7 +398,7 @@ class UriService::Client
|
|
396
398
|
:start => start,
|
397
399
|
:sort => 'value_ssort asc, uri asc' # Include 'uri asc' as part of sort to ensure consistent sorting
|
398
400
|
}
|
399
|
-
|
401
|
+
|
400
402
|
response = rsolr.get('select', params: solr_params)
|
401
403
|
if response['response']['numFound'] > 0
|
402
404
|
response['response']['docs'].each do |doc|
|
@@ -406,17 +408,17 @@ class UriService::Client
|
|
406
408
|
end
|
407
409
|
return terms_to_return
|
408
410
|
end
|
409
|
-
|
411
|
+
|
410
412
|
##################
|
411
413
|
# Delete methods #
|
412
414
|
##################
|
413
|
-
|
415
|
+
|
414
416
|
def delete_vocabulary(vocabulary_string_key)
|
415
417
|
self.handle_database_disconnect do
|
416
418
|
@db[UriService::VOCABULARIES].where(string_key: vocabulary_string_key).delete
|
417
419
|
end
|
418
420
|
end
|
419
|
-
|
421
|
+
|
420
422
|
def delete_term(uri, commit=true)
|
421
423
|
self.handle_database_disconnect do
|
422
424
|
@db.transaction do
|
@@ -428,37 +430,37 @@ class UriService::Client
|
|
428
430
|
end
|
429
431
|
end
|
430
432
|
end
|
431
|
-
|
433
|
+
|
432
434
|
##################
|
433
435
|
# Update methods #
|
434
436
|
##################
|
435
|
-
|
437
|
+
|
436
438
|
def update_vocabulary(string_key, new_display_label)
|
437
439
|
self.handle_database_disconnect do
|
438
440
|
dataset = @db[UriService::VOCABULARIES].where(string_key: string_key)
|
439
441
|
raise UriService::NonExistentVocabularyError, "No vocabulary found with string_key: " + string_key if dataset.count == 0
|
440
|
-
|
442
|
+
|
441
443
|
@db.transaction do
|
442
444
|
dataset.update(display_label: new_display_label)
|
443
445
|
end
|
444
446
|
end
|
445
447
|
end
|
446
|
-
|
448
|
+
|
447
449
|
# opts format: {:value => 'new value', :authority => 'newauthority', :additional_fields => {'key' => 'value'}}
|
448
450
|
def update_term(uri, opts, merge_additional_fields=true)
|
449
451
|
self.handle_database_disconnect do
|
450
452
|
term_db_row = @db[UriService::TERMS].first(uri: uri)
|
451
453
|
raise UriService::NonExistentUriError, "No term found with uri: " + uri if term_db_row.nil?
|
452
|
-
|
454
|
+
|
453
455
|
new_value = opts[:value] || term_db_row[:value]
|
454
456
|
new_authority = opts[:authority] || term_db_row[:authority]
|
455
457
|
new_additional_fields = term_db_row[:additional_fields].nil? ? {} : JSON.parse(term_db_row[:additional_fields])
|
456
|
-
|
458
|
+
|
457
459
|
if term_db_row[:type] == UriService::TermType::TEMPORARY && new_value != term_db_row[:value]
|
458
460
|
# TEMPORARY terms cannot have their values changed, but it is possible to update other fields
|
459
461
|
raise UriService::CannotChangeTemporaryTermValue, "The value of a temporary term cannot be changed. Delete unusued temporary terms or create a new one with a different value."
|
460
462
|
end
|
461
|
-
|
463
|
+
|
462
464
|
unless opts[:additional_fields].nil?
|
463
465
|
if merge_additional_fields
|
464
466
|
new_additional_fields.merge!(opts[:additional_fields])
|
@@ -468,16 +470,16 @@ class UriService::Client
|
|
468
470
|
end
|
469
471
|
end
|
470
472
|
validate_additional_field_keys(new_additional_fields)
|
471
|
-
|
473
|
+
|
472
474
|
@db.transaction do
|
473
475
|
@db[UriService::TERMS].where(uri: uri).update(value: new_value, value_hash: Digest::SHA256.hexdigest(new_value), authority: new_authority, additional_fields: JSON.generate(new_additional_fields))
|
474
476
|
self.send_term_to_solr(term_db_row[:vocabulary_string_key], new_value, uri, new_authority, new_additional_fields, term_db_row[:type], term_db_row[:id])
|
475
477
|
end
|
476
|
-
|
478
|
+
|
477
479
|
return generate_frozen_term_hash(term_db_row[:vocabulary_string_key], new_value, uri, new_authority, new_additional_fields, term_db_row[:type], term_db_row[:id])
|
478
480
|
end
|
479
481
|
end
|
480
|
-
|
482
|
+
|
481
483
|
def handle_database_disconnect
|
482
484
|
tries ||= 3
|
483
485
|
begin
|
@@ -487,26 +489,26 @@ class UriService::Client
|
|
487
489
|
retry unless tries == 0
|
488
490
|
end
|
489
491
|
end
|
490
|
-
|
492
|
+
|
491
493
|
def do_solr_commit
|
492
494
|
@rsolr_pool.with do |rsolr|
|
493
495
|
rsolr.commit
|
494
496
|
end
|
495
497
|
end
|
496
|
-
|
498
|
+
|
497
499
|
def clear_solr_index
|
498
500
|
@rsolr_pool.with do |rsolr|
|
499
501
|
rsolr.delete_by_query('*:*');
|
500
502
|
rsolr.commit
|
501
503
|
end
|
502
504
|
end
|
503
|
-
|
505
|
+
|
504
506
|
#########################
|
505
507
|
# BEGIN PRIVATE METHODS #
|
506
508
|
#########################
|
507
|
-
|
509
|
+
|
508
510
|
private
|
509
|
-
|
511
|
+
|
510
512
|
# Backing implementation for actual term creation in db/solr.
|
511
513
|
# - Performs some data validations.
|
512
514
|
# - Ensures uniqueness of URIs in database.
|
@@ -514,11 +516,11 @@ class UriService::Client
|
|
514
516
|
# create a new TEMPORARY term with an existing value/vocabulary combo,
|
515
517
|
# also adding non-existent supplied additional_fields to the existing temporary term.
|
516
518
|
def create_term_impl(type, vocabulary_string_key, value, uri, authority, additional_fields)
|
517
|
-
|
519
|
+
|
518
520
|
raise UriService::InvalidTermTypeError, 'Invalid type: ' + type unless VALID_TYPES.include?(type)
|
519
|
-
|
521
|
+
|
520
522
|
self.handle_database_disconnect do
|
521
|
-
|
523
|
+
|
522
524
|
if type == UriService::TermType::TEMPORARY
|
523
525
|
# If this is a TEMPORARY term, we need to ensure that the temporary
|
524
526
|
# passed in URI is a hash of the vocabulary + value, just in case this
|
@@ -529,20 +531,20 @@ class UriService::Client
|
|
529
531
|
raise UriService::InvalidTemporaryTermUriError, "The supplied URI was not derived from the supplied (vocabulary_string_key+value) pair."
|
530
532
|
end
|
531
533
|
end
|
532
|
-
|
534
|
+
|
533
535
|
unless uri =~ UriService::VALID_URI_REGEX
|
534
536
|
raise UriService::InvalidUriError, "Invalid URI supplied during term creation: #{uri}"
|
535
537
|
end
|
536
|
-
|
538
|
+
|
537
539
|
#Ensure that vocabulary with vocabulary_string_key exists
|
538
540
|
if self.find_vocabulary(vocabulary_string_key).nil?
|
539
541
|
raise UriService::NonExistentVocabularyError, "There is no vocabulary with string key: " + vocabulary_string_key.to_s
|
540
542
|
end
|
541
|
-
|
543
|
+
|
542
544
|
# Stringify and validate keys for additional_fields
|
543
545
|
additional_fields.stringify_keys!
|
544
546
|
validate_additional_field_keys(additional_fields) # This method call raises an error if an invalid additional_field key is supplied
|
545
|
-
|
547
|
+
|
546
548
|
@db.transaction do
|
547
549
|
value_hash = Digest::SHA256.hexdigest(value)
|
548
550
|
|
@@ -559,41 +561,41 @@ class UriService::Client
|
|
559
561
|
)
|
560
562
|
send_term_to_solr(vocabulary_string_key, value, uri, authority, additional_fields, type, db_id)
|
561
563
|
rescue Sequel::UniqueConstraintViolation
|
562
|
-
|
564
|
+
|
563
565
|
# If the user is trying to create a new TEMPORARY term and we ran into a Sequel::UniqueConstraintViolation,
|
564
566
|
# that means that the term already exists. We will return that existing term, but also update the term with
|
565
567
|
# any non-existent additional_fields supplied by the user and during this create operation, and a supplied
|
566
568
|
# authority if the term did not already have an authority.
|
567
569
|
if type == UriService::TermType::TEMPORARY
|
568
570
|
temporary_term = self.find_term_by_uri(uri)
|
569
|
-
|
571
|
+
|
570
572
|
opts = {}
|
571
573
|
non_existent_additional_fields = additional_fields.keys - temporary_term.keys
|
572
|
-
|
574
|
+
|
573
575
|
if non_existent_additional_fields.length > 0
|
574
576
|
additional_fields_to_merge_in = additional_fields.select{|k, v| non_existent_additional_fields.include?(k)}
|
575
577
|
opts[:additional_fields] = additional_fields_to_merge_in
|
576
578
|
end
|
577
|
-
|
579
|
+
|
578
580
|
if temporary_term['authority'].nil? && authority.length > 0 && authority != temporary_term['authority']
|
579
581
|
opts[:authority] = authority
|
580
582
|
end
|
581
|
-
|
583
|
+
|
582
584
|
if opts.size > 0
|
583
585
|
temporary_term = UriService.client.update_term(temporary_term['uri'], opts, true)
|
584
586
|
end
|
585
|
-
|
587
|
+
|
586
588
|
return temporary_term
|
587
589
|
end
|
588
|
-
|
590
|
+
|
589
591
|
raise UriService::ExistingUriError, "A term already exists with uri: " + uri + " (conflict found via uri_hash check)"
|
590
592
|
end
|
591
|
-
|
593
|
+
|
592
594
|
return generate_frozen_term_hash(vocabulary_string_key, value, uri, authority, additional_fields, type, db_id)
|
593
595
|
end
|
594
596
|
end
|
595
597
|
end
|
596
|
-
|
598
|
+
|
597
599
|
end
|
598
600
|
|
599
601
|
class UriService::Error < StandardError;end
|
@@ -610,4 +612,4 @@ class UriService::ExistingVocabularyStringKeyError < UriService::Error;end
|
|
610
612
|
class UriService::NonExistentUriError < UriService::Error;end
|
611
613
|
class UriService::NonExistentVocabularyError < UriService::Error;end
|
612
614
|
class UriService::UnsupportedObjectTypeError < UriService::Error;end
|
613
|
-
class UriService::UnsupportedSearchFieldError < UriService::Error;end
|
615
|
+
class UriService::UnsupportedSearchFieldError < UriService::Error;end
|
data/lib/uri_service/version.rb
CHANGED
data/lib/uri_service.rb
CHANGED
@@ -6,36 +6,35 @@ require 'uri'
|
|
6
6
|
require 'yaml'
|
7
7
|
|
8
8
|
module UriService
|
9
|
-
|
10
9
|
# Constants
|
11
10
|
VOCABULARY = :vocabulary
|
12
11
|
VOCABULARIES = :vocabularies
|
13
12
|
TERM = :term
|
14
13
|
TERMS = :terms
|
15
14
|
VALID_URI_REGEX = /\A#{URI::regexp}\z/
|
16
|
-
|
15
|
+
|
17
16
|
# Initialize the main instance of UriService::Client
|
18
17
|
# opts format: { 'local_uri_base' => 'http://id.example.com/term/', temporary_uri_base: 'temporary:', 'solr' => {...solr config...}, 'database' => {...database config...} }
|
19
18
|
def self.init(opts)
|
20
19
|
if @client && @client.connected?
|
21
20
|
@client.disconnect!
|
22
21
|
end
|
23
|
-
|
22
|
+
|
24
23
|
@client = UriService::Client.new(opts)
|
25
24
|
end
|
26
25
|
|
27
26
|
def self.client
|
28
27
|
return @client
|
29
28
|
end
|
30
|
-
|
29
|
+
|
31
30
|
def self.version
|
32
31
|
return UriService::VERSION
|
33
32
|
end
|
34
|
-
|
33
|
+
|
35
34
|
def self.required_tables
|
36
35
|
return [UriService::VOCABULARIES, UriService::TERMS]
|
37
36
|
end
|
38
|
-
|
37
|
+
|
39
38
|
# Wrapper around escape method for different versions of RSolr
|
40
39
|
def self.solr_escape(str)
|
41
40
|
if RSolr.respond_to?(:solr_escape)
|
@@ -44,11 +43,14 @@ module UriService
|
|
44
43
|
return RSolr.escape(str) # Fall back to older method
|
45
44
|
end
|
46
45
|
end
|
47
|
-
|
46
|
+
|
47
|
+
def self.root
|
48
|
+
Pathname.new(File.dirname(__dir__))
|
49
|
+
end
|
48
50
|
end
|
49
51
|
|
50
52
|
require "uri_service/version"
|
51
53
|
require "uri_service/term_type"
|
52
54
|
require "uri_service/client"
|
53
55
|
|
54
|
-
require 'uri_service/railtie' if defined?(Rails)
|
56
|
+
require 'uri_service/railtie' if defined?(Rails)
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: uri_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric O'Hanlon
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,21 +25,21 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: connection_pool
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rdf
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rsolr
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,89 +67,89 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: sequel
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
75
|
+
version: 4.26.0
|
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:
|
82
|
+
version: 4.26.0
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: jettywrapper
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '0'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
98
|
+
name: rainbow
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '3.
|
103
|
+
version: '3.0'
|
104
104
|
type: :development
|
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: '3.
|
110
|
+
version: '3.0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name:
|
112
|
+
name: mysql2
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
117
|
+
version: 0.3.18
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
124
|
+
version: 0.3.18
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: rake
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '
|
131
|
+
version: '10.1'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '
|
138
|
+
version: '10.1'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: rspec
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: '3.1'
|
146
146
|
type: :development
|
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:
|
152
|
+
version: '3.1'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: solr_wrapper
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - ">="
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: sqlite3
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - "<"
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '1.6'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "<"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '1.6'
|
167
181
|
description: A service for registering local URIs and performing both local and remote
|
168
182
|
URI lookups.
|
169
183
|
email: elo2112@columbia.edu
|
@@ -175,6 +189,7 @@ files:
|
|
175
189
|
- lib/tasks/uri_service.rake
|
176
190
|
- lib/tasks/uri_service/ci.rake
|
177
191
|
- lib/tasks/uri_service/db.rake
|
192
|
+
- lib/tasks/uri_service/docker.rake
|
178
193
|
- lib/tasks/uri_service/solr.rake
|
179
194
|
- lib/uri_service.rb
|
180
195
|
- lib/uri_service/client.rb
|
@@ -185,7 +200,7 @@ homepage: https://github.com/cul/uri_service
|
|
185
200
|
licenses:
|
186
201
|
- MIT
|
187
202
|
metadata: {}
|
188
|
-
post_install_message:
|
203
|
+
post_install_message:
|
189
204
|
rdoc_options: []
|
190
205
|
require_paths:
|
191
206
|
- lib
|
@@ -200,9 +215,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
200
215
|
- !ruby/object:Gem::Version
|
201
216
|
version: '0'
|
202
217
|
requirements: []
|
203
|
-
|
204
|
-
|
205
|
-
signing_key:
|
218
|
+
rubygems_version: 3.0.3.1
|
219
|
+
signing_key:
|
206
220
|
specification_version: 4
|
207
221
|
summary: A service for registering local URIs and performing both local and remote
|
208
222
|
URI lookups.
|