dynameek 0.0.1a

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+