dynameek 0.0.1a
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.
- data/lib/dynameek/dynamo_db.rb +58 -0
- data/lib/dynameek/model.rb +92 -0
- data/lib/dynameek/model_structure.rb +106 -0
- data/lib/dynameek/query.rb +77 -0
- data/lib/dynameek.rb +7 -0
- metadata +58 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
module Dynameek
|
2
|
+
module DynamoDb
|
3
|
+
def convert_from_dynamodb(type, value)
|
4
|
+
case type
|
5
|
+
when :integer
|
6
|
+
value.to_i
|
7
|
+
when :float
|
8
|
+
value.to_f
|
9
|
+
when :string
|
10
|
+
value.to_s
|
11
|
+
when :datetime
|
12
|
+
Time.at(value).to_datetime
|
13
|
+
else
|
14
|
+
value
|
15
|
+
end
|
16
|
+
end
|
17
|
+
def convert_to_dynamodb(type, value)
|
18
|
+
case type
|
19
|
+
when :datetime
|
20
|
+
value.to_time.to_f
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def exists?
|
27
|
+
table.exists?
|
28
|
+
end
|
29
|
+
|
30
|
+
def build!
|
31
|
+
return if dynamo_db.tables[table_name].exists?
|
32
|
+
new_table = dynamo_db.tables.create(table_name, @@read_write[0], @@read_write[1],
|
33
|
+
:hash_key => { @@hash_key.field => @@hash_key.type },
|
34
|
+
:range_key => { @@range.field => @@range.type == :datetime ? :number : @@range.type }
|
35
|
+
)
|
36
|
+
puts "Creating table, this may take a few minutes"
|
37
|
+
while new_table.status == :creating
|
38
|
+
sleep 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
@@table = nil
|
43
|
+
@@dynamo_db = nil
|
44
|
+
|
45
|
+
def dynamo_db
|
46
|
+
@@dynamo_db = AWS::DynamoDB.new if @@dynamo_db.nil?
|
47
|
+
@@dynamo_db
|
48
|
+
end
|
49
|
+
|
50
|
+
def table
|
51
|
+
build!
|
52
|
+
@@table = dynamo_db.tables[table_name] if @@table.nil?
|
53
|
+
@@table.load_schema if !@@table.schema_loaded?
|
54
|
+
@@table
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Dynameek::Model
|
2
|
+
extend Dynameek::DynamoDb
|
3
|
+
extend Dynameek::ModelStructure
|
4
|
+
extend Dynameek::Query
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
attr_accessor :attributes
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
def self.find(hash_key, range_val=nil)
|
14
|
+
raise Exception("This has a composite hash with a range, the range val is required") if(range_val.nil? && !@@range.field.nil?)
|
15
|
+
#multicolumn
|
16
|
+
hash_key = hash_key.join(multi_column_join) if(hash_key.is_a?(Array))
|
17
|
+
|
18
|
+
items = if !range_val.nil?
|
19
|
+
range_val = convert_to_dynamodb(range_field.type, range_val)
|
20
|
+
table.batch_get(:all, [[hash_key, range_val]])
|
21
|
+
else
|
22
|
+
table.batch_get(:all, [hash_key])
|
23
|
+
end
|
24
|
+
# p items.methods - Object.new.methods
|
25
|
+
return nil if(items.entries.size == 0)
|
26
|
+
item_to_instance(items.first)
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
def self.item_to_instance(item)
|
33
|
+
item = item.attributes if item.is_a?(AWS::DynamoDB::Item)
|
34
|
+
instance = self.new
|
35
|
+
fields.each do |field, type|
|
36
|
+
next if multi_column_hash_key? && field == hash_key_field.field
|
37
|
+
instance.send "#{field.to_s}=", convert_from_dynamodb(type, item[field.to_s])
|
38
|
+
end
|
39
|
+
instance
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
def self.create(attrib)
|
45
|
+
instance = self.new
|
46
|
+
attrib.each do |key, val|
|
47
|
+
instance.send "#{key.to_s}=", val
|
48
|
+
end
|
49
|
+
instance.save
|
50
|
+
end
|
51
|
+
|
52
|
+
@@before_save_callbacks = Set.new
|
53
|
+
def self.before_save method
|
54
|
+
@@before_save_callbacks.add(method.to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
def save
|
58
|
+
attribs = self.class.fields.reduce({}) do |memo, (field, type)|
|
59
|
+
#Always call the read method in case it has been overwritten
|
60
|
+
#Note that this is required for the multicolumn key
|
61
|
+
val = self.send field
|
62
|
+
val = self.class.convert_to_dynamodb(type, val)
|
63
|
+
memo[field] = val
|
64
|
+
memo
|
65
|
+
end
|
66
|
+
@@before_save_callbacks.each{|method| self.send method}
|
67
|
+
self.class.table.batch_write(
|
68
|
+
:put => [
|
69
|
+
attribs
|
70
|
+
]
|
71
|
+
)
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def self.table_name
|
77
|
+
self.to_s
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def read_attribute(fieldname)
|
83
|
+
@attributes[fieldname]
|
84
|
+
end
|
85
|
+
|
86
|
+
def write_attribute(fieldname, value)
|
87
|
+
@attributes = {} if(!@attributes)
|
88
|
+
@attributes[fieldname] = value
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Dynameek
|
2
|
+
module ModelStructure
|
3
|
+
|
4
|
+
@@fields = {}
|
5
|
+
@@hash_key = OpenStruct.new
|
6
|
+
@@hash_key.field = nil
|
7
|
+
@@hash_key.type = nil
|
8
|
+
|
9
|
+
@@range = OpenStruct.new
|
10
|
+
@@range.field = nil
|
11
|
+
@@range.type = nil
|
12
|
+
|
13
|
+
@@read_write = [10, 5]
|
14
|
+
|
15
|
+
@@multi_column_hash_key_fields = []
|
16
|
+
@@multi_column_join = "|"
|
17
|
+
|
18
|
+
|
19
|
+
def field fieldname, type
|
20
|
+
fieldname = fieldname.to_sym
|
21
|
+
type = type.to_sym
|
22
|
+
@@fields[fieldname] = type
|
23
|
+
define_method(fieldname.to_s) { read_attribute(fieldname) }
|
24
|
+
define_method("#{fieldname.to_s}?") { !read_attribute(fieldname).nil? }
|
25
|
+
define_method("#{fieldname.to_s}=") {|value| write_attribute(fieldname, value) }
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
def hash_key fieldname
|
31
|
+
fieldname = fieldname.to_sym
|
32
|
+
check_field(fieldname)
|
33
|
+
@@hash_key.field = fieldname
|
34
|
+
@@hash_key.type = @@fields[fieldname]
|
35
|
+
define_method(:hash_key) { read_attribute(fieldname) }
|
36
|
+
end
|
37
|
+
|
38
|
+
def multi_column_join
|
39
|
+
@@multi_column_join
|
40
|
+
end
|
41
|
+
def multi_column_join=(join)
|
42
|
+
@@multi_column_join = join
|
43
|
+
end
|
44
|
+
def multi_column_hash_key?
|
45
|
+
!@@multi_column_hash_key_fields.empty?
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
def multi_column_hash_key fieldnames
|
51
|
+
fields = fieldnames.map(&:to_sym)
|
52
|
+
fields.each{|f| check_field(f)}
|
53
|
+
@@multi_column_hash_key_fields = fields
|
54
|
+
fieldname = fieldnames.map(&:to_s).join("_").to_s
|
55
|
+
@@fields[fieldname] = :string
|
56
|
+
define_method(:hash_key) do
|
57
|
+
@@multi_column_hash_key_fields.reduce([]) do |memo, field|
|
58
|
+
memo << attributes[field]
|
59
|
+
memo
|
60
|
+
end.join(@@multi_column_join)
|
61
|
+
end
|
62
|
+
alias_method fieldname, :hash_key
|
63
|
+
@@hash_key.field = fieldname
|
64
|
+
@@hash_key.type = :string
|
65
|
+
end
|
66
|
+
|
67
|
+
def hash_key_field
|
68
|
+
@@hash_key
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def range fieldname
|
73
|
+
fieldname = fieldname.to_sym
|
74
|
+
check_field(fieldname)
|
75
|
+
@@range.field = fieldname
|
76
|
+
@@range.type = @@fields[fieldname]
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def read_write read, write
|
81
|
+
@@read_write = [read, write]
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_units
|
85
|
+
@@read_write[0]
|
86
|
+
end
|
87
|
+
def write_units
|
88
|
+
@@read_write[1]
|
89
|
+
end
|
90
|
+
|
91
|
+
def fields
|
92
|
+
@@fields
|
93
|
+
end
|
94
|
+
|
95
|
+
def range_field
|
96
|
+
@@range.field.nil? ? nil : @@range
|
97
|
+
end
|
98
|
+
|
99
|
+
def check_field(fieldname)
|
100
|
+
raise Exception("#{fieldname} is not a recognised field") if @@fields[fieldname].nil?
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Dynameek
|
2
|
+
module Query
|
3
|
+
#Similar to dynamoids approach but lighter (hopefully)
|
4
|
+
|
5
|
+
class QueryChain
|
6
|
+
|
7
|
+
def initialize(model)
|
8
|
+
@model = model
|
9
|
+
@hash_key = nil
|
10
|
+
@range = {eq: nil, within: nil, gte: nil, gt: nil, lte: nil, lt: nil, begins_with: nil}
|
11
|
+
end
|
12
|
+
|
13
|
+
def query(hash_key)
|
14
|
+
@hash_key = hash_key
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def where(value, op=:eq)
|
19
|
+
raise Exception("Op #{op.to_s} not recognised") if(!@range.keys.include?(op))
|
20
|
+
@range[op] = value
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def all
|
25
|
+
run
|
26
|
+
end
|
27
|
+
|
28
|
+
def each
|
29
|
+
all.each
|
30
|
+
end
|
31
|
+
|
32
|
+
def each_with_index
|
33
|
+
all.each_with_index
|
34
|
+
end
|
35
|
+
|
36
|
+
RANGE_QUERY_MAP =
|
37
|
+
{
|
38
|
+
eq: :range_value,
|
39
|
+
within: :range_value,
|
40
|
+
gte: :range_gte,
|
41
|
+
gt: :range_greater_than,
|
42
|
+
lte: :range_lte,
|
43
|
+
lt: :range_less_than,
|
44
|
+
begins_with: :range_begins_with
|
45
|
+
}
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def run
|
50
|
+
hash_key = @hash_key
|
51
|
+
hash_key = hash_key.join(@model.multi_column_join) if(hash_key.is_a?(Array))
|
52
|
+
|
53
|
+
query_hash = {:hash_value => hash_key}
|
54
|
+
|
55
|
+
query_hash = @range.reduce(query_hash) do |hsh, (key, val)|
|
56
|
+
if(!val.nil?)
|
57
|
+
hsh[RANGE_QUERY_MAP[key]] = @model.convert_to_dynamodb(@model.range_field.type, val)
|
58
|
+
end
|
59
|
+
hsh
|
60
|
+
end
|
61
|
+
@model.table.items.query(query_hash).map{|item| @model.item_to_instance(item)}
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
[:query, :where, :all, :each, :each_with_index].each do |method|
|
69
|
+
define_method(method) do |*args|
|
70
|
+
qc = QueryChain.new(self)
|
71
|
+
args = [] if !args
|
72
|
+
qc.send method, *args
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
data/lib/dynameek.rb
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
module Dynameek
|
2
|
+
end
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), *%w[dynameek dynamo_db])
|
5
|
+
require File.join(File.dirname(__FILE__), *%w[dynameek query])
|
6
|
+
require File.join(File.dirname(__FILE__), *%w[dynameek model_structure])
|
7
|
+
require File.join(File.dirname(__FILE__), *%w[dynameek model])
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dynameek
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: 5
|
5
|
+
version: 0.0.1a
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Max Dupenois
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2013-03-20 00:00:00 Z
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A very lightweight model for DynamoDB tables in, certainly not in a finished state
|
17
|
+
email: max.dupenois@forward.co.uk
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/dynameek/dynamo_db.rb
|
26
|
+
- lib/dynameek/model.rb
|
27
|
+
- lib/dynameek/model_structure.rb
|
28
|
+
- lib/dynameek/query.rb
|
29
|
+
- lib/dynameek.rb
|
30
|
+
homepage: http://github.com/maxdupenois/dynameek
|
31
|
+
licenses: []
|
32
|
+
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ">"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.3.1
|
50
|
+
requirements: []
|
51
|
+
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 1.8.24
|
54
|
+
signing_key:
|
55
|
+
specification_version: 3
|
56
|
+
summary: Dynameek
|
57
|
+
test_files: []
|
58
|
+
|