rom-dynamo 0.1.4 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/.rspec +1 -0
- data/Gemfile +3 -2
- data/Rakefile +5 -0
- data/lib/rom/dynamo/commands.rb +29 -7
- data/lib/rom/dynamo/relation.rb +113 -71
- data/lib/rom/dynamo/repository.rb +22 -10
- data/lib/rom/dynamo/version.rb +1 -1
- data/lib/rom/dynamo.rb +6 -1
- data/lib/rom-dynamo.rb +1 -0
- data/rom-dynamo.gemspec +6 -4
- metadata +65 -25
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZTBlOWU4ZGY1NGZiYjM1MmI3MDg1NjMxYmE0NWE5NjViODUxY2JlNw==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bb3d1008f7f0331e2ea2d49690cf9b95388c96143ca86718204e0fc53f3e8c4e
|
4
|
+
data.tar.gz: f45c64b787dab54ea6c821e196c3d3ab4a1aa181065a5338e5892156e606885c
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
ODg1ZDlkYWEwNGEzODg2Mzk2YjFjMjI0MjUyYTAyODRiNTg3YjQyYjIxNWQ0
|
11
|
-
ZGQ1ZjNmNTVhZDkxOWE4ZTk1NGNkMjFmNTE1MmFkYmUzMDliYTM=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
ZGY0ZGRmOThiZDBhYzRiMzA2NjdjMDhhZWM4MzRiMGNhYWEwMzhmYzRiMjhk
|
14
|
-
NDdlZWNhMzE2NjMyOTFkMTY4NWUyMDk4ZmU3YmUxM2I5MWI3NDdjNGU4Mzdk
|
15
|
-
MTIxNjllNjc1ZTU3NjEyODBhZDc5YjljOGFkNzI1NjNlYTk5YzU=
|
6
|
+
metadata.gz: e595872d1620052b010b0b42905ae517d6a2461e1cc9b2a30e78ec661d6f89afa8e3bb4e9f2681b11a44b0372c8e9e6489c02864e768f3091fb539a41f5c0719
|
7
|
+
data.tar.gz: 81ec89f72f4e0b0b5a0be77b828c5db7bb730e6e4b118fca5a52d657d809396bcb63d494d592ebfaabf7d9d0b5ce618e8f323817059f6b537e4826ad1a0382c8
|
data/.rspec
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/lib/rom/dynamo/commands.rb
CHANGED
@@ -5,21 +5,43 @@ module Rom
|
|
5
5
|
module Commands
|
6
6
|
# DynamoDB create command
|
7
7
|
class Create < ROM::Commands::Create
|
8
|
-
def execute(
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def execute(tuples)
|
9
|
+
Array([tuples]).flatten.map do |tuple|
|
10
|
+
attributes = input[tuple]
|
11
|
+
dataset.insert(attributes.to_h)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def dataset
|
16
|
+
relation.dataset
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# DynamoDB update command
|
21
|
+
class Update < ROM::Commands::Update
|
22
|
+
def execute(params)
|
23
|
+
attributes = input[params]
|
24
|
+
relation.map do |tuple|
|
25
|
+
dataset.update(tuple, attributes.to_h)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def dataset
|
30
|
+
relation.dataset
|
13
31
|
end
|
14
32
|
end
|
15
33
|
|
16
34
|
# DynamoDB delete command
|
17
35
|
class Delete < ROM::Commands::Delete
|
18
36
|
def execute
|
19
|
-
|
20
|
-
tuples.each { |t|
|
37
|
+
relation.to_a.tap do |tuples|
|
38
|
+
tuples.each { |t| dataset.delete(t) }
|
21
39
|
end
|
22
40
|
end
|
41
|
+
|
42
|
+
def dataset
|
43
|
+
relation.dataset
|
44
|
+
end
|
23
45
|
end
|
24
46
|
end
|
25
47
|
end
|
data/lib/rom/dynamo/relation.rb
CHANGED
@@ -2,84 +2,108 @@ module Rom
|
|
2
2
|
module Dynamo
|
3
3
|
class Relation < ROM::Relation
|
4
4
|
include Enumerable
|
5
|
-
forward :restrict, :index_restrict
|
6
|
-
|
7
|
-
|
8
|
-
dataset.insert(*args)
|
9
|
-
self
|
10
|
-
end
|
11
|
-
|
12
|
-
def delete(*args)
|
13
|
-
dataset.delete(*args)
|
14
|
-
self
|
15
|
-
end
|
5
|
+
forward :restrict, :batch_restrict, :index_restrict
|
6
|
+
forward :limit, :reversed
|
7
|
+
adapter :dynamo
|
16
8
|
end
|
17
9
|
|
18
10
|
class Dataset
|
19
|
-
include
|
20
|
-
|
11
|
+
include Enumerable
|
12
|
+
include Dry::Equalizer(:name, :connection)
|
13
|
+
extend Dry::Initializer[undefined: false]
|
14
|
+
EmptyQuery = { key_conditions: {}.freeze }.freeze
|
15
|
+
|
16
|
+
option :connection
|
17
|
+
option :name, proc(&:to_s)
|
18
|
+
option :table_keys, optional: true, reader: false
|
19
|
+
option :query, default: proc { EmptyQuery }, reader: false
|
21
20
|
alias_method :ddb, :connection
|
22
21
|
|
23
|
-
def initialize(name, ddb, conditions = nil)
|
24
|
-
@name, @connection = name, ddb
|
25
|
-
@conditions = conditions || {}
|
26
|
-
end
|
27
|
-
|
28
22
|
############# READ #############
|
23
|
+
|
29
24
|
def each(&block)
|
30
|
-
|
31
|
-
consistent_read: true
|
32
|
-
|
33
|
-
|
25
|
+
block.nil? ? to_enum : begin
|
26
|
+
result = start_query(consistent_read: true)
|
27
|
+
result.each_page { |p| p[:items].each(&block) }
|
28
|
+
end
|
34
29
|
end
|
35
30
|
|
36
31
|
def restrict(query = nil)
|
37
32
|
return self if query.nil?
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
dup_with_query(Dataset, query)
|
34
|
+
end
|
35
|
+
|
36
|
+
def batch_restrict(keys)
|
37
|
+
dup_as(BatchGetDataset, keys: keys.map do |k|
|
38
|
+
Hash[table_keys.zip(k.is_a?(Array) ? k : [k])]
|
39
|
+
end)
|
41
40
|
end
|
42
41
|
|
43
42
|
def index_restrict(index, query)
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
dup_with_query(GlobalIndexDataset, query, index_name: index.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
############# PAGINATION #############
|
47
|
+
|
48
|
+
def limit(limit)
|
49
|
+
dup_with_query(self.class, nil, limit: limit.to_i)
|
50
|
+
end
|
51
|
+
|
52
|
+
def reversed
|
53
|
+
dup_with_query(self.class, nil, scan_index_forward: false)
|
47
54
|
end
|
48
55
|
|
49
56
|
############# WRITE #############
|
50
57
|
def insert(hash)
|
51
|
-
|
52
|
-
|
53
|
-
item: hash
|
54
|
-
})
|
58
|
+
opts = { table_name: name, item: stringify_keys(hash) }
|
59
|
+
connection.put_item(opts).attributes
|
55
60
|
end
|
56
61
|
|
57
62
|
def delete(hash)
|
63
|
+
hash = stringify_keys(hash)
|
58
64
|
connection.delete_item({
|
59
65
|
table_name: name,
|
60
66
|
key: hash_to_key(hash),
|
61
67
|
expected: to_expected(hash),
|
62
|
-
})
|
68
|
+
}).attributes
|
69
|
+
end
|
70
|
+
|
71
|
+
def update(keys, hash)
|
72
|
+
connection.update_item({
|
73
|
+
table_name: name, key: hash_to_key(stringify_keys(keys)),
|
74
|
+
attribute_updates: hash.each_with_object({}) do |(k, v), out|
|
75
|
+
out[k] = { value: dump_value(v), action: 'PUT' } if !keys[k]
|
76
|
+
end
|
77
|
+
}).attributes
|
63
78
|
end
|
64
79
|
|
65
80
|
############# HELPERS #############
|
66
81
|
private
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
82
|
+
def batch_get_each_item(keys, &block)
|
83
|
+
!keys.empty? && ddb.batch_get_item({
|
84
|
+
request_items: { name => { keys: keys } },
|
85
|
+
}).each_page do |page|
|
86
|
+
out = page[:responses][name]
|
87
|
+
out.each(&block)
|
73
88
|
end
|
74
89
|
end
|
75
90
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
91
|
+
def dup_with_query(klass, key_hash, opts = {})
|
92
|
+
opts = @query.merge(opts)
|
93
|
+
|
94
|
+
if key_hash && !key_hash.empty?
|
95
|
+
conditions = @query[:key_conditions]
|
96
|
+
opts[:key_conditions] = conditions.merge(Hash[
|
97
|
+
key_hash.map do |key, value|
|
98
|
+
[key, {
|
99
|
+
attribute_value_list: [value],
|
100
|
+
comparison_operator: "EQ"
|
101
|
+
}]
|
102
|
+
end
|
103
|
+
]).freeze
|
104
|
+
end
|
105
|
+
|
106
|
+
dup_as(klass, query: opts.freeze)
|
83
107
|
end
|
84
108
|
|
85
109
|
def to_expected(hash)
|
@@ -96,45 +120,63 @@ module Rom
|
|
96
120
|
|
97
121
|
def table_keys
|
98
122
|
@table_keys ||= begin
|
99
|
-
|
100
|
-
|
101
|
-
keys.map(&:attribute_name)
|
123
|
+
r = ddb.describe_table(table_name: name)
|
124
|
+
r[:table][:key_schema].map(&:attribute_name)
|
102
125
|
end
|
103
126
|
end
|
104
127
|
|
128
|
+
def start_query(opts = {}, &block)
|
129
|
+
opts = @query.merge(table_name: name).merge!(opts)
|
130
|
+
puts "Querying DDB: #{opts.inspect}"
|
131
|
+
ddb.query(opts)
|
132
|
+
end
|
133
|
+
|
105
134
|
def dup_as(klass, opts = {})
|
106
135
|
table_keys # To populate keys once at top-level Dataset
|
107
|
-
|
108
|
-
klass.
|
109
|
-
|
110
|
-
|
111
|
-
|
136
|
+
attrs = Dataset.dry_initializer.attributes(self)
|
137
|
+
klass.new(attrs.merge(opts))
|
138
|
+
end
|
139
|
+
|
140
|
+
# String modifiers
|
141
|
+
def stringify_keys(hash)
|
142
|
+
hash.each_with_object({}) { |(k, v), out| out[k.to_s] = v }
|
143
|
+
end
|
144
|
+
|
145
|
+
def dump_value(v)
|
146
|
+
return v.new_offset(0).iso8601(6) if v.is_a?(DateTime)
|
147
|
+
v.is_a?(Time) ? v.utc.iso8601(6) : v
|
112
148
|
end
|
113
149
|
end
|
114
150
|
|
115
|
-
#
|
116
|
-
|
117
|
-
|
151
|
+
# Batch get using an array of key queries
|
152
|
+
# [{ key => val }, { key => val }, ...]
|
153
|
+
class BatchGetDataset < Dataset
|
154
|
+
option :keys
|
118
155
|
|
156
|
+
# Query for records
|
119
157
|
def each(&block)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
index_name: @index
|
124
|
-
}) { |hash| keys << hash_to_key(hash) }
|
125
|
-
|
126
|
-
# Bail if we have nothing
|
127
|
-
return if keys.empty?
|
158
|
+
batch_get_each_item(@keys, &block)
|
159
|
+
end
|
160
|
+
end
|
128
161
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
162
|
+
# Dataset queried via a Global Secondary Index
|
163
|
+
# Paginate through keys from Global Index and
|
164
|
+
# call BatchGetItem for keys from each page
|
165
|
+
class GlobalIndexDataset < Dataset
|
166
|
+
def each(&block)
|
167
|
+
if @query[:limit]
|
168
|
+
each_item(start_query, &block)
|
169
|
+
else
|
170
|
+
result = start_query(limit: 100)
|
171
|
+
result.each_page { |p| each_item(p, &block) }
|
135
172
|
end
|
136
173
|
end
|
137
174
|
|
175
|
+
private def each_item(result, &block)
|
176
|
+
keys = result[:items].map { |h| hash_to_key(h) }
|
177
|
+
batch_get_each_item(keys, &block)
|
178
|
+
end
|
138
179
|
end
|
180
|
+
|
139
181
|
end
|
140
182
|
end
|
@@ -1,12 +1,19 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'rom/
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'rom/gateway'
|
3
3
|
|
4
4
|
module Rom
|
5
5
|
module Dynamo
|
6
|
-
class
|
6
|
+
class Gateway < ROM::Gateway
|
7
|
+
attr_reader :ddb, :options
|
8
|
+
|
7
9
|
def initialize(uri)
|
8
|
-
uri = URI.parse(uri)
|
9
|
-
|
10
|
+
uri = Addressable::URI.parse(uri)
|
11
|
+
opts = { region: uri.host }
|
12
|
+
opts.merge!(uri.query_values) if uri.query
|
13
|
+
opts.keys.each { |k| opts[k.to_sym] = opts.delete(k) }
|
14
|
+
|
15
|
+
@options = opts
|
16
|
+
@ddb = Aws::DynamoDB::Client.new(@options)
|
10
17
|
@prefix = uri.path.gsub('/', '')
|
11
18
|
@datasets = {}
|
12
19
|
end
|
@@ -17,17 +24,22 @@ module Rom
|
|
17
24
|
|
18
25
|
def dataset(name)
|
19
26
|
name = "#{@prefix}#{name}"
|
20
|
-
@datasets[name] ||= Dataset.new(
|
27
|
+
@datasets[name] ||= _has?(name) && Dataset.new(connection: @ddb, name: name)
|
21
28
|
end
|
22
29
|
|
23
30
|
def dataset?(name)
|
24
|
-
name
|
25
|
-
list = connection.list_tables
|
26
|
-
list[:table_names].include?(name)
|
31
|
+
!!self[name]
|
27
32
|
end
|
28
33
|
|
29
34
|
def [](name)
|
30
|
-
@datasets[name]
|
35
|
+
@datasets["#{@prefix}#{name}"]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def _has?(name)
|
40
|
+
@ddb.describe_table(table_name: name)
|
41
|
+
rescue Aws::DynamoDB::Errors::ResourceNotFoundException
|
42
|
+
return false
|
31
43
|
end
|
32
44
|
end
|
33
45
|
end
|
data/lib/rom/dynamo/version.rb
CHANGED
data/lib/rom/dynamo.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'rom'
|
2
|
-
require '
|
2
|
+
require 'date'
|
3
|
+
require 'aws-sdk-dynamodb'
|
3
4
|
require "rom/dynamo/version"
|
4
5
|
require 'rom/dynamo/relation'
|
5
6
|
require 'rom/dynamo/commands'
|
6
7
|
require 'rom/dynamo/repository'
|
7
8
|
|
9
|
+
# jRuby HACK: https://github.com/jruby/jruby/issues/3645#issuecomment-181660161
|
10
|
+
module Aws; const_set(:DynamoDB, Aws::DynamoDB) end
|
11
|
+
|
12
|
+
# Register adapter with ROM-rb
|
8
13
|
ROM.register_adapter(:dynamo, Rom::Dynamo)
|
data/lib/rom-dynamo.rb
CHANGED
data/rom-dynamo.gemspec
CHANGED
@@ -24,10 +24,12 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
26
|
# Runtime
|
27
|
-
spec.add_runtime_dependency "
|
28
|
-
spec.add_runtime_dependency "
|
27
|
+
spec.add_runtime_dependency "addressable", "~> 2.3"
|
28
|
+
spec.add_runtime_dependency "rom", ">= 1.0", "< 6.0"
|
29
|
+
spec.add_runtime_dependency "aws-sdk-dynamodb", "~> 1.0"
|
29
30
|
|
30
31
|
# Development
|
31
|
-
spec.add_development_dependency "
|
32
|
-
spec.add_development_dependency "
|
32
|
+
spec.add_development_dependency "activesupport", ">= 4.0", "< 7.0"
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
34
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
33
35
|
end
|
metadata
CHANGED
@@ -1,71 +1,111 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rom-dynamo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Rykov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: addressable
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.3'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rom
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
16
30
|
requirements:
|
17
|
-
- -
|
31
|
+
- - ">="
|
18
32
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0
|
33
|
+
version: '1.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '6.0'
|
20
37
|
type: :runtime
|
21
38
|
prerelease: false
|
22
39
|
version_requirements: !ruby/object:Gem::Requirement
|
23
40
|
requirements:
|
24
|
-
- -
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.0'
|
44
|
+
- - "<"
|
25
45
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
46
|
+
version: '6.0'
|
27
47
|
- !ruby/object:Gem::Dependency
|
28
|
-
name: aws-sdk-
|
48
|
+
name: aws-sdk-dynamodb
|
29
49
|
requirement: !ruby/object:Gem::Requirement
|
30
50
|
requirements:
|
31
|
-
- -
|
51
|
+
- - "~>"
|
32
52
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
53
|
+
version: '1.0'
|
34
54
|
type: :runtime
|
35
55
|
prerelease: false
|
36
56
|
version_requirements: !ruby/object:Gem::Requirement
|
37
57
|
requirements:
|
38
|
-
- -
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.0'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: activesupport
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '4.0'
|
68
|
+
- - "<"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '7.0'
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '4.0'
|
78
|
+
- - "<"
|
39
79
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
80
|
+
version: '7.0'
|
41
81
|
- !ruby/object:Gem::Dependency
|
42
82
|
name: bundler
|
43
83
|
requirement: !ruby/object:Gem::Requirement
|
44
84
|
requirements:
|
45
|
-
- - ~>
|
85
|
+
- - "~>"
|
46
86
|
- !ruby/object:Gem::Version
|
47
|
-
version: '1.
|
87
|
+
version: '1.7'
|
48
88
|
type: :development
|
49
89
|
prerelease: false
|
50
90
|
version_requirements: !ruby/object:Gem::Requirement
|
51
91
|
requirements:
|
52
|
-
- - ~>
|
92
|
+
- - "~>"
|
53
93
|
- !ruby/object:Gem::Version
|
54
|
-
version: '1.
|
94
|
+
version: '1.7'
|
55
95
|
- !ruby/object:Gem::Dependency
|
56
96
|
name: rake
|
57
97
|
requirement: !ruby/object:Gem::Requirement
|
58
98
|
requirements:
|
59
|
-
- - ~>
|
99
|
+
- - "~>"
|
60
100
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
101
|
+
version: '13.0'
|
62
102
|
type: :development
|
63
103
|
prerelease: false
|
64
104
|
version_requirements: !ruby/object:Gem::Requirement
|
65
105
|
requirements:
|
66
|
-
- - ~>
|
106
|
+
- - "~>"
|
67
107
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
108
|
+
version: '13.0'
|
69
109
|
description: DynamoDB adapter for Ruby Object Mapper
|
70
110
|
email:
|
71
111
|
- mrykov@gmail.com
|
@@ -73,9 +113,9 @@ executables: []
|
|
73
113
|
extensions: []
|
74
114
|
extra_rdoc_files: []
|
75
115
|
files:
|
76
|
-
- .gitignore
|
77
|
-
- .rspec
|
78
|
-
- .travis.yml
|
116
|
+
- ".gitignore"
|
117
|
+
- ".rspec"
|
118
|
+
- ".travis.yml"
|
79
119
|
- Gemfile
|
80
120
|
- LICENSE.txt
|
81
121
|
- README.md
|
@@ -99,17 +139,17 @@ require_paths:
|
|
99
139
|
- lib
|
100
140
|
required_ruby_version: !ruby/object:Gem::Requirement
|
101
141
|
requirements:
|
102
|
-
- -
|
142
|
+
- - ">="
|
103
143
|
- !ruby/object:Gem::Version
|
104
144
|
version: '0'
|
105
145
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
146
|
requirements:
|
107
|
-
- -
|
147
|
+
- - ">="
|
108
148
|
- !ruby/object:Gem::Version
|
109
149
|
version: '0'
|
110
150
|
requirements: []
|
111
151
|
rubyforge_project:
|
112
|
-
rubygems_version: 2.
|
152
|
+
rubygems_version: 2.7.8
|
113
153
|
signing_key:
|
114
154
|
specification_version: 4
|
115
155
|
summary: DynamoDB adapter for Ruby Object Mapper
|