Dynamoid 0.0.1

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.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ source "http://rubygems.org"
2
+ gem 'activemodel'
3
+ gem 'tzinfo'
4
+ gem 'aws-sdk'
5
+
6
+ # Add dependencies required to use your gem here.
7
+ # Example:
8
+ # gem "activesupport", ">= 2.3.5"
9
+
10
+ # Add dependencies to develop your gem here.
11
+ # Include everything needed to run rake, tests, features, etc.
12
+ group :development do
13
+ gem "mocha"
14
+ gem "rake"
15
+ gem "rspec"
16
+ gem "bundler"
17
+ gem "jeweler"
18
+ gem "rcov"
19
+ end
@@ -0,0 +1,58 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.1.3)
5
+ activesupport (= 3.1.3)
6
+ builder (~> 3.0.0)
7
+ i18n (~> 0.6)
8
+ activesupport (3.1.3)
9
+ multi_json (~> 1.0)
10
+ aws-sdk (1.3.5)
11
+ httparty (~> 0.7)
12
+ json (~> 1.4)
13
+ nokogiri (>= 1.4.4)
14
+ uuidtools (~> 2.1)
15
+ builder (3.0.0)
16
+ diff-lcs (1.1.3)
17
+ git (1.2.5)
18
+ httparty (0.8.1)
19
+ multi_json
20
+ multi_xml
21
+ i18n (0.6.0)
22
+ jeweler (1.6.4)
23
+ bundler (~> 1.0)
24
+ git (>= 1.2.5)
25
+ rake
26
+ json (1.6.5)
27
+ metaclass (0.0.1)
28
+ mocha (0.10.0)
29
+ metaclass (~> 0.0.1)
30
+ multi_json (1.0.4)
31
+ multi_xml (0.4.1)
32
+ nokogiri (1.5.0)
33
+ rake (0.9.2.2)
34
+ rcov (0.9.11)
35
+ rspec (2.8.0)
36
+ rspec-core (~> 2.8.0)
37
+ rspec-expectations (~> 2.8.0)
38
+ rspec-mocks (~> 2.8.0)
39
+ rspec-core (2.8.0)
40
+ rspec-expectations (2.8.0)
41
+ diff-lcs (~> 1.1.2)
42
+ rspec-mocks (2.8.0)
43
+ tzinfo (0.3.31)
44
+ uuidtools (2.1.2)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ activemodel
51
+ aws-sdk
52
+ bundler
53
+ jeweler
54
+ mocha
55
+ rake
56
+ rcov
57
+ rspec
58
+ tzinfo
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Synthetic LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # Dynamoid
2
+
3
+ Dynamoid is an ORM for Amazon's DynamoDB for Ruby applications. It provides similar functionality to ActiveRecord and improves on Amazon's existing [HashModel](http://docs.amazonwebservices.com/AWSRubySDK/latest/AWS/Record/HashModel.html) by providing better searching tools, native association support, and a local adapter for offline development.
4
+
5
+ ## Warning!
6
+
7
+ I'm still working on this gem a lot. Associations aren't working and that's a bummer, and you can only use the old-school ActiveRecord style finders like ```find_all_by_<attribute_name>``` or directly finding by an ID.
8
+
9
+ ## Usage
10
+
11
+ Using Dynamoid is pretty simple. First you need to initialize it to get it going, so put code similar to this somewhere (a Rails initializer would be a great place for this if you're using Rails):
12
+
13
+ ```ruby
14
+ Dynamoid.configure do |config|
15
+ config.adapter = 'local' # This adapter allows offline development without connecting to the DynamoDB servers.
16
+ # config.adapter = 'aws_sdk' # This adapter establishes a connection to the DynamoDB servers using's Amazon's own awful AWS gem.
17
+ # config.access_key = 'access_key' # If connecting to DynamoDB, your access key is required.
18
+ # config.secret_key = 'secret_key' # So is your secret key.
19
+ config.namespace = "dynamoid_#{Rails.application.class.parent_name}_#{Rails.env}" # To namespace tables created by Dynamoid from other tables you might have.
20
+ config.warn_on_scan = true # Output a warning to stdout when you perform a scan rather than a query on a table
21
+ end
22
+
23
+ ```
24
+
25
+ Inside your model:
26
+
27
+ ```ruby
28
+ class User
29
+ include Dynamoid::Document
30
+
31
+ field :name
32
+ field :email
33
+
34
+ index :name
35
+ index :email
36
+ index [:name, :email]
37
+
38
+ end
39
+ ```
40
+
41
+ Right now, you can only do a couple things with this amazing functionality:
42
+
43
+ ```ruby
44
+ u = User.new(:name => 'Josh')
45
+ u.email = 'josh@joshsymonds.com'
46
+ u.save
47
+
48
+ u == User.find(u.id)
49
+ u == User.find_by_name('Josh')
50
+ u == User.find_by_name_and_email('Josh','josh@joshsymonds.com')
51
+ ```
52
+
53
+ Not super exciting yet, true... but it's getting there!
54
+
55
+ ## Credits
56
+
57
+ Dynamoid borrows code, structure, and even its name very liberally from the truly amazing [Mongoid](https://github.com/mongoid/mongoid). Without Mongoid to crib from none of this would have been possible, and I hope they don't mind me reusing their very awesome ideas to make DynamoDB just as accessible to the Ruby world as MongoDB.
58
+
59
+ ## Running the tests
60
+
61
+ The tests can be run in the simple predictable way with ```rake```. However, if you provide environment variables for ACCESS_KEY and SECRET_KEY, the tests will use the aws_sdk adapter rather than the local adapter: ```ACCESS_KEY=<accesskey> SECRET_KEY=<secretkey> rake```. Keep in mind this takes much, much longer than the local tests.
62
+
63
+ ## Copyright
64
+
65
+ Copyright (c) 2012 Josh Symonds. See LICENSE.txt for further details.
66
+
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "Dynamoid"
18
+ gem.homepage = "http://github.com/Veraticus/Dynamoid"
19
+ gem.license = "MIT"
20
+ gem.summary = "Dynamoid is an ORM for Amazon's DynamoDB"
21
+ gem.description = "Dynamoid is an ORM for Amazon's DynamoDB that supports offline development, associations, querying, and everything else you'd expect from an ActiveRecord-style replacement."
22
+ gem.email = "josh@joshsymonds.com"
23
+ gem.authors = ["Josh Symonds"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rake/rdoctask'
42
+ Rake::RDocTask.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "dynamoid #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,31 @@
1
+ require "delegate"
2
+ require "time"
3
+ require "securerandom"
4
+ require "active_support/core_ext"
5
+ require 'active_support/json'
6
+ require "active_support/inflector"
7
+ require "active_support/lazy_load_hooks"
8
+ require "active_support/time_with_zone"
9
+ require "active_model"
10
+
11
+ require 'dynamoid/errors'
12
+ require 'dynamoid/attributes'
13
+ require 'dynamoid/fields'
14
+ require 'dynamoid/indexes'
15
+ require 'dynamoid/persistence'
16
+ require 'dynamoid/finders'
17
+ require 'dynamoid/config'
18
+ require 'dynamoid/components'
19
+ require 'dynamoid/document'
20
+ require 'dynamoid/adapter'
21
+
22
+ module Dynamoid
23
+ extend self
24
+
25
+ def configure
26
+ block_given? ? yield(Config) : Config
27
+ Dynamoid::Adapter.reconnect!
28
+ end
29
+ alias :config :configure
30
+
31
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+ module Dynamoid #:nodoc:
3
+
4
+ module Adapter
5
+ extend self
6
+
7
+ def adapter
8
+ reconnect! unless @adapter
9
+ @adapter
10
+ end
11
+
12
+ def reconnect!
13
+ require "dynamoid/adapter/#{Dynamoid::Config.adapter}" unless Dynamoid::Adapter.const_defined?(Dynamoid::Config.adapter.camelcase)
14
+ @adapter = Dynamoid::Adapter.const_get(Dynamoid::Config.adapter.camelcase)
15
+ @adapter.connect! if @adapter.respond_to?(:connect!)
16
+ end
17
+
18
+ def method_missing(method, *args)
19
+ return @adapter.send(method, *args) if @adapter.respond_to?(method)
20
+ super
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,99 @@
1
+ require 'aws'
2
+
3
+ module Dynamoid
4
+ module Adapter
5
+ module AwsSdk
6
+ extend self
7
+ @@connection = nil
8
+
9
+ def connect!
10
+ @@connection = AWS::DynamoDB.new(:access_key_id => Dynamoid::Config.access_key, :secret_access_key => Dynamoid::Config.secret_key)
11
+ end
12
+
13
+ def connection
14
+ @@connection
15
+ end
16
+
17
+ # BatchGetItem
18
+ def batch_get_item(options)
19
+ batch = AWS::DynamoDB::BatchGet.new(:config => @@connection.config)
20
+ options.each do |t, ids|
21
+ batch.table(t, :all, Array(ids))
22
+ end
23
+ hash = Hash.new{|h, k| h[k] = []}
24
+ batch.each do |table_name, attributes|
25
+ hash[table_name] << attributes.symbolize_keys!
26
+ end
27
+ hash
28
+ end
29
+
30
+ # CreateTable
31
+ def create_table(table_name, key)
32
+ table = @@connection.tables.create(table_name, 10, 5, :hash_key => {key.to_sym => :string})
33
+ sleep 0.5 while table.status == :creating
34
+ return table
35
+ end
36
+
37
+ # DeleteItem
38
+ def delete_item(table_name, key)
39
+ table = @@connection.tables[table_name]
40
+ table.load_schema
41
+ result = table.items[key]
42
+ result.delete unless result.attributes.to_h.empty?
43
+ true
44
+ end
45
+
46
+ # DeleteTable
47
+ def delete_table(table_name)
48
+ @@connection.tables[table_name].delete
49
+ end
50
+
51
+ # DescribeTable
52
+
53
+ # GetItem
54
+ def get_item(table_name, key)
55
+ table = @@connection.tables[table_name]
56
+ table.load_schema
57
+ result = table.items[key].attributes.to_h
58
+ if result.empty?
59
+ nil
60
+ else
61
+ result.symbolize_keys!
62
+ end
63
+ end
64
+
65
+ # ListTables
66
+ def list_tables
67
+ @@connection.tables.collect(&:name)
68
+ end
69
+
70
+ # PutItem
71
+ def put_item(table_name, object)
72
+ table = @@connection.tables[table_name]
73
+ table.load_schema
74
+ table.items.create(object.delete_if{|k, v| v.nil?})
75
+ end
76
+
77
+ # Query
78
+ def query(table_name, id)
79
+ get_item(table_name, id)
80
+ end
81
+
82
+ # Scan
83
+ def scan(table_name, scan_hash)
84
+ table = @@connection.tables[table_name]
85
+ table.load_schema
86
+ results = []
87
+ table.items.select do |data|
88
+ attributes = data.attributes.symbolize_keys!
89
+ results << attributes if scan_hash.all?{|k, v| !attributes[k].nil? && attributes[k] == v}
90
+ end
91
+ results
92
+ end
93
+
94
+ # UpdateItem
95
+
96
+ # UpdateTable
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,77 @@
1
+ module Dynamoid
2
+ module Adapter
3
+ module Local
4
+ extend self
5
+ # Gimpy hash that should be somewhat equivalent to what Amazon's actual DynamoDB, for offline development.
6
+
7
+ def data
8
+ @data ||= {}
9
+ end
10
+
11
+ def reset_data
12
+ self.data.each {|k, v| v[:data] = {}}
13
+ end
14
+
15
+ # BatchGetItem
16
+ def batch_get_item(options)
17
+ Hash.new { |h, k| h[k] = Array.new }.tap do |hash|
18
+ options.each do |table_name, keys|
19
+ table = data[table_name]
20
+ Array(keys).each do |key|
21
+ hash[table_name] << table[:data][key]
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ # CreateTable
28
+ def create_table(table_name, key)
29
+ data[table_name] = {:id => key, :data => {}}
30
+ end
31
+
32
+ # DeleteItem
33
+ def delete_item(table_name, key)
34
+ data[table_name][:data].delete(key)
35
+ end
36
+
37
+ # DeleteTable
38
+ def delete_table(table_name)
39
+ data.delete(table_name)
40
+ end
41
+
42
+ # DescribeTable
43
+
44
+ # GetItem
45
+ def get_item(table_name, key)
46
+ data[table_name][:data][key]
47
+ end
48
+
49
+ # ListTables
50
+ def list_tables
51
+ data.keys
52
+ end
53
+
54
+ # PutItem
55
+ def put_item(table_name, object)
56
+ table = data[table_name]
57
+ table[:data][object[table[:id]]] = object
58
+ end
59
+
60
+ # Query
61
+ def query(table_name, id)
62
+ get_item(table_name, id)
63
+ end
64
+
65
+ # Scan
66
+ def scan(table_name, scan_hash)
67
+ return [] if data[table_name].nil?
68
+ data[table_name][:data].values.select{|d| scan_hash.all?{|k, v| !d[k].nil? && d[k] == v}}
69
+ end
70
+
71
+ # UpdateItem
72
+
73
+ # UpdateTable
74
+
75
+ end
76
+ end
77
+ end