tiny_dyno 0.1.7 → 0.1.9
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/CHANGES.md +12 -0
- data/lib/tiny_dyno/changeable.rb +1 -1
- data/lib/tiny_dyno/document.rb +4 -4
- data/lib/tiny_dyno/document_composition.rb +6 -4
- data/lib/tiny_dyno/errors/hash_key_errors.rb +28 -2
- data/lib/tiny_dyno/expected.rb +18 -0
- data/lib/tiny_dyno/fields/standard.rb +17 -17
- data/lib/tiny_dyno/hash_key.rb +109 -0
- data/lib/tiny_dyno/persistable.rb +10 -10
- data/lib/tiny_dyno/range_key.rb +0 -0
- data/lib/tiny_dyno/version.rb +1 -1
- data/lib/tiny_dyno.rb +0 -5
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a57635fe6ebcd452a54d007997380f6616bb0f3
|
4
|
+
data.tar.gz: 3e7518b99d5034175ea1781ac4f39812a722c7fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd0dc92db501ed54364de063d527acb8ccb3a115ed27585a1c6c4c5f3e0f73ed65a9441d569150fb6c095f52b58eb0c59bcf313e21949a100cd92a6e3dada745
|
7
|
+
data.tar.gz: e6d2aee6af7d226e667e0e7f522d227daf5662b1f725c961b95ce097e4b5f4a8a88696d95cef8c4da2adc6afb4aa352affef3732e463a47973d2693e9efd345d
|
data/CHANGES.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
0.1.9 (2015-07-01)
|
2
|
+
-----------------
|
3
|
+
|
4
|
+
* Fixes - clean up of a few stale require 'pry'
|
5
|
+
|
6
|
+
0.1.8 (2015-07-01)
|
7
|
+
------------------
|
8
|
+
|
9
|
+
* Fixes - Raise Error, if multiple hash keys are being defined
|
10
|
+
* Fixes - On Create use 'expected' clause to achieve intended behavior on create,
|
11
|
+
to not overwrite an existing record, but only create a new record
|
12
|
+
|
data/lib/tiny_dyno/changeable.rb
CHANGED
@@ -63,7 +63,7 @@ module TinyDyno
|
|
63
63
|
# @since 2.1.0
|
64
64
|
def attribute_change(attr)
|
65
65
|
attr = database_field_name(attr)
|
66
|
-
[changed_attributes[attr], attributes[attr]] if attribute_changed?(attr)
|
66
|
+
[changed_attributes[attr], attributes[attr]] if (attribute_changed?(attr) && !attr.nil?)
|
67
67
|
end
|
68
68
|
|
69
69
|
end
|
data/lib/tiny_dyno/document.rb
CHANGED
@@ -70,10 +70,10 @@ module TinyDyno
|
|
70
70
|
# check that each option key relates to a hash_key present on the model
|
71
71
|
# do not permit scan queries
|
72
72
|
def valid_option_keys(options)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
73
|
+
raise TinyDyno::Errors::HashKeyOnly.new(klass: self.class, name: 'primary_key') if primary_key.nil?
|
74
|
+
# options.keys.each do |name|
|
75
|
+
# named = name.to_s
|
76
|
+
# end
|
77
77
|
end
|
78
78
|
|
79
79
|
# minimimum implementation for now
|
@@ -3,27 +3,29 @@ require 'tiny_dyno/changeable'
|
|
3
3
|
require 'tiny_dyno/fields'
|
4
4
|
require 'tiny_dyno/stateful'
|
5
5
|
require 'tiny_dyno/tables'
|
6
|
-
require 'tiny_dyno/
|
6
|
+
require 'tiny_dyno/hash_key'
|
7
7
|
require 'tiny_dyno/persistable'
|
8
|
+
require 'tiny_dyno/expected'
|
8
9
|
|
9
10
|
module TinyDyno
|
10
11
|
module DocumentComposition
|
11
12
|
extend ActiveSupport::Concern
|
12
13
|
|
13
14
|
include Attributes
|
15
|
+
include Expected
|
14
16
|
include Changeable
|
15
17
|
include Fields
|
16
|
-
include
|
18
|
+
include HashKey
|
17
19
|
include Persistable
|
18
20
|
include Stateful
|
19
21
|
include Tables
|
20
22
|
|
21
|
-
|
22
23
|
MODULES = [
|
23
24
|
Attributes,
|
25
|
+
Expected,
|
24
26
|
Changeable,
|
25
27
|
Fields,
|
26
|
-
|
28
|
+
HashKey,
|
27
29
|
Persistable,
|
28
30
|
Stateful,
|
29
31
|
Tables,
|
@@ -50,14 +50,13 @@ module TinyDyno
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
|
54
53
|
# encoding: utf-8
|
55
54
|
module TinyDyno
|
56
55
|
module Errors
|
57
56
|
|
58
57
|
# This error is raised, when a query is performed with fields specified
|
59
58
|
# that are not HashKeys, which would result in a table scan
|
60
|
-
class
|
59
|
+
class HashKeyOnly < TinyDynoError
|
61
60
|
|
62
61
|
# Create the new error.
|
63
62
|
#
|
@@ -76,3 +75,30 @@ module TinyDyno
|
|
76
75
|
end
|
77
76
|
end
|
78
77
|
end
|
78
|
+
|
79
|
+
# encoding: utf-8
|
80
|
+
module TinyDyno
|
81
|
+
module Errors
|
82
|
+
|
83
|
+
# This error is raised, when a query is performed with fields specified
|
84
|
+
# that are not HashKeys, which would result in a table scan
|
85
|
+
class OnlyOneHashKeyPermitted < TinyDynoError
|
86
|
+
|
87
|
+
# Create the new error.
|
88
|
+
#
|
89
|
+
# @example Instantiate the error.
|
90
|
+
# OnlyOneHashKeyPermitted.new(Person, "gender")
|
91
|
+
#
|
92
|
+
# @param [ Class ] klass The model class.
|
93
|
+
# @param [ String, Symbol ] name The name of the attribute.
|
94
|
+
#
|
95
|
+
# @since 3.0.0
|
96
|
+
def initialize(klass:, name:)
|
97
|
+
super(
|
98
|
+
compose_message("you can only define one hash_key", { klass: klass.name, name: name })
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TinyDyno
|
2
|
+
module Expected
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# insert Expected clause, which will ensure
|
6
|
+
# that INSERTs will only take place
|
7
|
+
# if there is no record with that hash key yet
|
8
|
+
def request_as_new_record(request)
|
9
|
+
request.merge({
|
10
|
+
expected: {
|
11
|
+
"#{ primary_key[:attr] }": {
|
12
|
+
comparison_operator: 'NULL'
|
13
|
+
}
|
14
|
+
}})
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -41,24 +41,24 @@ module TinyDyno
|
|
41
41
|
|
42
42
|
private
|
43
43
|
|
44
|
-
# Is the field included in the fields that were returned from the
|
45
|
-
# database? We can apply the default if:
|
46
|
-
# 1. The field is included in an only limitation (field: 1)
|
47
|
-
# 2. The field is not excluded in a without limitation (field: 0)
|
48
|
-
#
|
49
|
-
# @example Is the field included?
|
50
|
-
# field.included?(fields)
|
51
|
-
#
|
52
|
-
# @param [ Hash ] fields The field limitations.
|
53
|
-
#
|
54
|
-
# @return [ true, false ] If the field was included.
|
44
|
+
# # Is the field included in the fields that were returned from the
|
45
|
+
# # database? We can apply the default if:
|
46
|
+
# # 1. The field is included in an only limitation (field: 1)
|
47
|
+
# # 2. The field is not excluded in a without limitation (field: 0)
|
48
|
+
# #
|
49
|
+
# # @example Is the field included?
|
50
|
+
# # field.included?(fields)
|
51
|
+
# #
|
52
|
+
# # @param [ Hash ] fields The field limitations.
|
53
|
+
# #
|
54
|
+
# # @return [ true, false ] If the field was included.
|
55
|
+
# #
|
56
|
+
# # @since 2.4.4
|
57
|
+
# def included?(fields)
|
58
|
+
# (fields.values.first == 1 && fields[name.to_s] == 1) ||
|
59
|
+
# (fields.values.first == 0 && !fields.has_key?(name.to_s))
|
60
|
+
# end
|
55
61
|
#
|
56
|
-
# @since 2.4.4
|
57
|
-
def included?(fields)
|
58
|
-
(fields.values.first == 1 && fields[name.to_s] == 1) ||
|
59
|
-
(fields.values.first == 0 && !fields.has_key?(name.to_s))
|
60
|
-
end
|
61
|
-
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module TinyDyno
|
2
|
+
module HashKey
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :attribute_definitions, :key_schema, :primary_key
|
7
|
+
|
8
|
+
# TODO :local_secondary_indexes, :global_secondary_indexes
|
9
|
+
self.attribute_definitions ||= []
|
10
|
+
self.key_schema ||= []
|
11
|
+
self.primary_key ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
# return all defined hash keys on an instantiated object
|
15
|
+
# for further use in DynamoDB queries, i.e. to look up an object
|
16
|
+
#
|
17
|
+
def hash_key_as_selector
|
18
|
+
{ "#{ self.class.primary_key[:attr] }": attributes[self.class.primary_key[:attr]] }
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
|
23
|
+
# Defines the primary key for the Document
|
24
|
+
# Only one primary key = hash_key is allowed in DynamoDB
|
25
|
+
#
|
26
|
+
# @example Define a field.
|
27
|
+
# hash_key :score, :type => Integer
|
28
|
+
#
|
29
|
+
# @param [ Symbol ] name The name of the hash_key.
|
30
|
+
# @param [ Hash ] options The options to pass to the hash_key.
|
31
|
+
#
|
32
|
+
# @option options [ Class ] :type The type of the field.
|
33
|
+
# @option options [ String ] :label The label for the field.
|
34
|
+
#
|
35
|
+
# @return [ Field ] The generated field
|
36
|
+
def hash_key(name, options = {})
|
37
|
+
raise TinyDyno::Errors::OnlyOneHashKeyPermitted.new(klass: self.class, name: name) unless primary_key.empty?
|
38
|
+
named = name.to_s
|
39
|
+
attribute_definition = build_attribute_definition(named,options[:type])
|
40
|
+
key_schema = build_key_schema(named)
|
41
|
+
unless attribute_definition_meets_spec?(attribute_definition)
|
42
|
+
raise TinyDyno::Errors::InvalidHashKey.new(klass: self.class, name: name)
|
43
|
+
end
|
44
|
+
# we need the accessors as well
|
45
|
+
add_field(named, options)
|
46
|
+
self.attribute_definitions << attribute_definition
|
47
|
+
self.key_schema << key_schema
|
48
|
+
self.primary_key = {
|
49
|
+
attr: attribute_definition[:attribute_name],
|
50
|
+
attr_type: attribute_definition[:attribute_type],
|
51
|
+
key_type: key_schema[:key_type],
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
# convert a hash key into a format as expected by
|
56
|
+
# put_item and update_item request
|
57
|
+
def as_item_entry(hash_key)
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Return true or false, depending on whether the attribute_definitions on the model
|
64
|
+
# meet the specification of the Aws Sdk
|
65
|
+
# This is a syntax, not a logic check
|
66
|
+
def attribute_definitions_meet_spec?
|
67
|
+
attribute_definitions.each do |definition|
|
68
|
+
return false unless attribute_definition_meets_spec?(definition)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def attribute_definition_meets_spec?(definition)
|
73
|
+
return (definition.has_key?(:attribute_name) && \
|
74
|
+
definition.has_key?(:attribute_type) && \
|
75
|
+
definition[:attribute_name].class == String && \
|
76
|
+
definition[:attribute_type].class == String && \
|
77
|
+
['S','N', 'B'].include?(definition[:attribute_type]))
|
78
|
+
end
|
79
|
+
|
80
|
+
def build_attribute_definition(name, key_type)
|
81
|
+
{
|
82
|
+
attribute_name: name,
|
83
|
+
attribute_type: hash_key_type(key_type)
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def hash_key_type(key_type = nil)
|
88
|
+
return 'S' if key_type == String
|
89
|
+
return 'N' if key_type == Fixnum or key_type == Integer
|
90
|
+
return nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def build_key_schema(name)
|
94
|
+
{
|
95
|
+
attribute_name: name,
|
96
|
+
key_type: 'HASH'
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
# convert values in queries to DynamoDB
|
101
|
+
# into types as expected by DynamoDB
|
102
|
+
def dyno_typed_key(key:, val:)
|
103
|
+
typed_class = self.fields[key].options[:type]
|
104
|
+
return (document_typed(klass: typed_class, value: val))
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -4,7 +4,13 @@ module TinyDyno
|
|
4
4
|
|
5
5
|
def save(options = {})
|
6
6
|
if new_record?
|
7
|
-
request_put_item(options)
|
7
|
+
if request_put_item(options)
|
8
|
+
changes_applied
|
9
|
+
@new_record = nil
|
10
|
+
return true
|
11
|
+
else
|
12
|
+
return false
|
13
|
+
end
|
8
14
|
else
|
9
15
|
request_update_item(options)
|
10
16
|
end
|
@@ -13,14 +19,8 @@ module TinyDyno
|
|
13
19
|
private
|
14
20
|
|
15
21
|
def request_put_item(options)
|
16
|
-
request =
|
17
|
-
|
18
|
-
changes_applied
|
19
|
-
@new_record = nil
|
20
|
-
return true
|
21
|
-
else
|
22
|
-
return false
|
23
|
-
end
|
22
|
+
request = request_as_new_record(build_item_request(options))
|
23
|
+
return(TinyDyno::Adapter.put_item(put_item_request: request))
|
24
24
|
end
|
25
25
|
|
26
26
|
# The target structure as per
|
@@ -51,7 +51,7 @@ module TinyDyno
|
|
51
51
|
# "ExpressionAttributeValueVariable" => "value", # value <Hash,Array,String,Numeric,Boolean,IO,Set,nil>
|
52
52
|
# },
|
53
53
|
# })
|
54
|
-
def
|
54
|
+
def build_item_request(options)
|
55
55
|
{
|
56
56
|
table_name: self.class.table_name,
|
57
57
|
item: build_item_request_entries
|
File without changes
|
data/lib/tiny_dyno/version.rb
CHANGED
data/lib/tiny_dyno.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tiny_dyno
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Gerschner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -162,6 +162,7 @@ files:
|
|
162
162
|
- ".ruby-version"
|
163
163
|
- ".simplecov"
|
164
164
|
- ".travis.yml"
|
165
|
+
- CHANGES.md
|
165
166
|
- Gemfile
|
166
167
|
- Guardfile
|
167
168
|
- LICENSE
|
@@ -185,14 +186,17 @@ files:
|
|
185
186
|
- lib/tiny_dyno/errors/attribute_errors.rb
|
186
187
|
- lib/tiny_dyno/errors/hash_key_errors.rb
|
187
188
|
- lib/tiny_dyno/errors/tiny_dyno_error.rb
|
189
|
+
- lib/tiny_dyno/expected.rb
|
188
190
|
- lib/tiny_dyno/extensions.rb
|
189
191
|
- lib/tiny_dyno/extensions/module.rb
|
190
192
|
- lib/tiny_dyno/fields.rb
|
191
193
|
- lib/tiny_dyno/fields/standard.rb
|
194
|
+
- lib/tiny_dyno/hash_key.rb
|
192
195
|
- lib/tiny_dyno/hash_keys.rb
|
193
196
|
- lib/tiny_dyno/loggable.rb
|
194
197
|
- lib/tiny_dyno/persistable.rb
|
195
198
|
- lib/tiny_dyno/range_attributes.rb
|
199
|
+
- lib/tiny_dyno/range_key.rb
|
196
200
|
- lib/tiny_dyno/stateful.rb
|
197
201
|
- lib/tiny_dyno/tables.rb
|
198
202
|
- lib/tiny_dyno/version.rb
|