active_datastore 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +14 -6
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +9 -1
- data/README.md +45 -6
- data/Rakefile +6 -0
- data/active_datastore.gemspec +3 -3
- data/lib/active_datastore.rb +4 -0
- data/lib/active_datastore/client.rb +32 -0
- data/lib/active_datastore/dataset.rb +15 -0
- data/lib/active_datastore/version.rb +1 -1
- data/spec/client_spec.rb +20 -0
- data/spec/credentials.yml.example +2 -0
- data/spec/dataset_spec.rb +34 -0
- data/spec/spec_helper.rb +13 -0
- metadata +25 -10
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
MGQ0ZDdhOTg2MjdkNDM1ZjEwYzc5NzE4NzU0YzMyMGNmNTU4NjcxOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NzQxYzljYjdiM2I3YWVmYWIwMDliMTEzM2ViYTQzY2UxZmVlMDM3Mw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZGIwOTdmM2VjNGRmNjk5YmM3YjE5ZGMyY2UzNTk4ZWJmODhiNGM5NTczM2Vh
|
10
|
+
OTJjMTEzZmJmYjJjOWE2NGIzM2I3ZWE2ZmE0NTEyMzMzMDViOWE3NTg2N2U2
|
11
|
+
MDgzYWEzZDljNmY1OTIyZmUwOGZlNTdjYmRkODRkZTk5MmNmMDg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ODE5MTlmYTdjNjU1MjdhMjIwMjUxMDU1MmM2MzY2MDc0M2U5YmQwZDI1MGJk
|
14
|
+
ZDFjNzViOGQzYWZmYjRjNzdiNmY5MjZhNGViYzExNDdmMmZkNGI3NTIwN2Ey
|
15
|
+
YTY2YTY3NWQ2NDgyY2EzMjk5MTFiMWE2ZWEyOTNlZjQxNjE4OGQ=
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p392
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# ActiveDatastore
|
2
2
|
|
3
|
-
|
3
|
+
With the release of the [Google Cloud Datastore API](https://developers.google.com/datastore/), it's finally possible to leverage the datastore in pretty much any stack. Since Google seems to be supporting NodeJS, Python and Java right of the bat, it makes sense to bridge the Ruby gap.
|
4
|
+
|
5
|
+
ActiveDatastore is (eventually) meant to be comparable to [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord) in terms of API, features and ease of use. It will rely heavily on [ActiveModel](https://github.com/rails/rails/tree/master/activemodel), but will continue to be framework agnostic and usable with or without [Rails](http://rubyonrails.org/).
|
6
|
+
|
7
|
+
## Current Status
|
8
|
+
I've built a wrapper over the GCD API (`ActiveDatastore::Dataset`) that's fully functional and can be used for pretty much all the examples given in the documentation. The wrapper's API is very similar to what you see in the NodeJS examples.
|
9
|
+
|
10
|
+
Right now, ActiveDatastore is very much a work in progress. Please evaluate it before production use, and do remember that the API will undergo breaking changes until we hit v1.0.
|
4
11
|
|
5
12
|
## Installation
|
6
13
|
|
@@ -18,12 +25,44 @@ Or install it yourself as:
|
|
18
25
|
|
19
26
|
## Usage
|
20
27
|
|
21
|
-
|
28
|
+
Follow the instructions [here](https://developers.google.com/datastore/docs/activate#google_cloud_datastore_from_other_platforms) to get your **service account** (`AUTH_EMAIL`), **private key** (`AUTH_KEY`) and **dataset id** (`DATASET_ID`).
|
29
|
+
|
30
|
+
In your initializer (if you're on Rails you could create `config/initializers/datastore.rb`):
|
31
|
+
|
32
|
+
require 'active_datastore'
|
33
|
+
|
34
|
+
AUTH_EMAIL = "something@developer.gserviceaccount.com"
|
35
|
+
AUTH_KEY = File.open("path/to/my/secret.key.p12").read
|
36
|
+
DATASET_ID = "my-dataset"
|
37
|
+
|
38
|
+
client = ActiveDatastore::Client.new AUTH_EMAIL, AUTH_KEY
|
39
|
+
$dataset = ActiveDatastore::Dataset.new DATASET_ID, client
|
40
|
+
|
41
|
+
The initialization of the client seems be performance / network intensive, so it might make sense to do it once and hold the `$dataset` for the lifetime of the application. `ActiveDatastore::Dataset` is stateless and should support this.
|
42
|
+
|
43
|
+
To make calls to the datastore, use the methods documented on the [JSON API Reference](https://developers.google.com/datastore/docs/apis/v1beta1/datasets) (but remember use the underscore equivalent names.)
|
44
|
+
|
45
|
+
start_response = $dataset.begin_transaction({
|
46
|
+
isolationLevel: "snapshot"
|
47
|
+
})
|
48
|
+
|
49
|
+
start_response.data.kind # Should be "datastore#beginTransactionResponse"
|
50
|
+
transaction_id = start_response.data.transaction
|
51
|
+
|
52
|
+
rollback_response = $dataset.rollback({
|
53
|
+
transaction: transaction_id
|
54
|
+
})
|
55
|
+
|
56
|
+
rollback_response.data.kind # Should be "datastore#rollbackResponse"
|
57
|
+
|
58
|
+
Remeber that both the request body and the `response.data` are hashes with camel case keys, as shown in the [docs](https://developers.google.com/datastore/docs/apis/v1beta1/datasets/lookup#response). I know it's a little inconsistent that way, but an effort to deeply walk through each hash and convert keys will probably be more trouble than it's worth.
|
59
|
+
|
22
60
|
|
23
61
|
## Contributing
|
24
62
|
|
25
|
-
1. Fork
|
63
|
+
1. Fork the repo
|
26
64
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3.
|
28
|
-
4.
|
29
|
-
5.
|
65
|
+
3. **WRITE GOOD AND CLEAR TESTS**. Do remember that this gem may be used in production to serve millions of requests. Bugs can be catastrophic. Also, I can't merge and maintain code I don't fully understand.
|
66
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
67
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
68
|
+
6. Create new Pull Request
|
data/Rakefile
CHANGED
data/active_datastore.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = ActiveDatastore::VERSION
|
9
9
|
spec.authors = ["Sudhir Jonathan"]
|
10
10
|
spec.email = ["sudhir.j@gmail.com"]
|
11
|
-
spec.description = "
|
12
|
-
spec.summary = "
|
13
|
-
spec.homepage = ""
|
11
|
+
spec.description = "With the release of the Google Cloud Datastore API, its now possible to use the full power of Google's datastore in Ruby apps. ActiveDatastore is right now a clean wrapper over the API, and I'd like to take to a point where it's camparable and similar to ActiveRecord."
|
12
|
+
spec.summary = "ODM (Object-Document-Mapper) for the Google Cloud Datastore."
|
13
|
+
spec.homepage = "https://github.com/sudhirj/active_datastore"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
data/lib/active_datastore.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'google/api_client'
|
2
|
+
|
3
|
+
module ActiveDatastore
|
4
|
+
class Client
|
5
|
+
def initialize email, secret
|
6
|
+
@client = Google::APIClient.new
|
7
|
+
key = Google::APIClient::KeyUtils.load_from_pkcs12(secret, 'notasecret')
|
8
|
+
service_account = Google::APIClient::JWTAsserter.new(
|
9
|
+
email,
|
10
|
+
['https://www.googleapis.com/auth/datastore', 'https://www.googleapis.com/auth/userinfo.email'],
|
11
|
+
key)
|
12
|
+
@client.authorization = service_account.authorize
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid?
|
17
|
+
not @client.authorization.expired?
|
18
|
+
end
|
19
|
+
|
20
|
+
def api
|
21
|
+
@api ||= @client.discovered_api('datastore', 'v1beta1').datasets
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute opts
|
25
|
+
@client.execute({
|
26
|
+
api_method: api.send(opts[:method]),
|
27
|
+
body_object: opts[:body],
|
28
|
+
parameters: opts[:params]
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActiveDatastore
|
2
|
+
class Dataset
|
3
|
+
METHODS = [:allocate_ids, :begin_transaction, :blind_write, :commit, :lookup, :rollback, :run_query]
|
4
|
+
def initialize dataset_id, client
|
5
|
+
@client = client
|
6
|
+
@dataset_id = dataset_id
|
7
|
+
end
|
8
|
+
|
9
|
+
METHODS.each do |method|
|
10
|
+
define_method method do |body={}|
|
11
|
+
@client.execute method: method, body: body, params: {datasetId: @dataset_id}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pry'
|
3
|
+
describe ActiveDatastore::Client do
|
4
|
+
|
5
|
+
let (:client) { ActiveDatastore::Client.new AUTH_EMAIL, AUTH_KEY }
|
6
|
+
|
7
|
+
it 'should connect to the GCD, given credentials' do
|
8
|
+
client.valid?.should be_true
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should discover the datastore api' do
|
12
|
+
client.api.lookup.generate_uri(datasetId: 'abc').to_s.should == "https://www.googleapis.com/datastore/v1beta1/datasets/abc/lookup"
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should execute calls made using the google client' do
|
16
|
+
response = client.execute method: :begin_transaction, body: {"isolationLevel" => "snapshot"}, params: {datasetId: 'active-datastore-test'}
|
17
|
+
response.data.transaction.should_not be_nil
|
18
|
+
response.data.kind.should == 'datastore#beginTransactionResponse'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveDatastore::Dataset do
|
4
|
+
let (:client) { ActiveDatastore::Client.new AUTH_EMAIL, AUTH_KEY }
|
5
|
+
let (:dataset) { ActiveDatastore::Dataset.new 'active-datastore-test', client }
|
6
|
+
|
7
|
+
it "should have all the datastore api methods" do
|
8
|
+
discovered_methods = client.api.discovered_methods.map(&:id).map{|n| n.split('.')[2]}.map(&:underscore).map(&:to_sym)
|
9
|
+
ActiveDatastore::Dataset::METHODS.sort.should == discovered_methods.sort
|
10
|
+
|
11
|
+
ActiveDatastore::Dataset::METHODS.each do |method|
|
12
|
+
dataset.respond_to?(method).should be_true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should execute corresponding methods on the client with the given parameters, always including the dataset id" do
|
17
|
+
ActiveDatastore::Dataset::METHODS.each do |method|
|
18
|
+
client.should_receive(:execute).with(method: method, body: {abc: 42}, params: {datasetId: 'active-datastore-test'} )
|
19
|
+
dataset.send(method, {abc: 42})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "transactions" do
|
24
|
+
it 'should start and rollback a transaction' do
|
25
|
+
start_response = dataset.begin_transaction
|
26
|
+
start_response.data.kind.should == "datastore#beginTransactionResponse"
|
27
|
+
start_response.data.transaction.should_not be_nil
|
28
|
+
|
29
|
+
rollback_response = dataset.rollback({transaction: start_response.data.transaction})
|
30
|
+
rollback_response.data.kind.should == "datastore#rollbackResponse"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
require 'active_datastore'
|
5
|
+
|
6
|
+
credentials = YAML.load File.open 'spec/credentials.yml'
|
7
|
+
|
8
|
+
AUTH_EMAIL = credentials["EMAIL"]
|
9
|
+
AUTH_KEY = File.open(credentials["KEY_PATH"]).read
|
10
|
+
|
11
|
+
RSpec.configure do |config|
|
12
|
+
|
13
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_datastore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sudhir Jonathan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-06-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,17 +28,20 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - '>='
|
31
|
+
- - ! '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - '>='
|
38
|
+
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
description:
|
41
|
+
description: With the release of the Google Cloud Datastore API, its now possible
|
42
|
+
to use the full power of Google's datastore in Ruby apps. ActiveDatastore is right
|
43
|
+
now a clean wrapper over the API, and I'd like to take to a point where it's camparable
|
44
|
+
and similar to ActiveRecord.
|
42
45
|
email:
|
43
46
|
- sudhir.j@gmail.com
|
44
47
|
executables: []
|
@@ -46,14 +49,22 @@ extensions: []
|
|
46
49
|
extra_rdoc_files: []
|
47
50
|
files:
|
48
51
|
- .gitignore
|
52
|
+
- .rspec
|
53
|
+
- .ruby-version
|
49
54
|
- Gemfile
|
50
55
|
- LICENSE.txt
|
51
56
|
- README.md
|
52
57
|
- Rakefile
|
53
58
|
- active_datastore.gemspec
|
54
59
|
- lib/active_datastore.rb
|
60
|
+
- lib/active_datastore/client.rb
|
61
|
+
- lib/active_datastore/dataset.rb
|
55
62
|
- lib/active_datastore/version.rb
|
56
|
-
|
63
|
+
- spec/client_spec.rb
|
64
|
+
- spec/credentials.yml.example
|
65
|
+
- spec/dataset_spec.rb
|
66
|
+
- spec/spec_helper.rb
|
67
|
+
homepage: https://github.com/sudhirj/active_datastore
|
57
68
|
licenses:
|
58
69
|
- MIT
|
59
70
|
metadata: {}
|
@@ -63,12 +74,12 @@ require_paths:
|
|
63
74
|
- lib
|
64
75
|
required_ruby_version: !ruby/object:Gem::Requirement
|
65
76
|
requirements:
|
66
|
-
- - '>='
|
77
|
+
- - ! '>='
|
67
78
|
- !ruby/object:Gem::Version
|
68
79
|
version: '0'
|
69
80
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
81
|
requirements:
|
71
|
-
- - '>='
|
82
|
+
- - ! '>='
|
72
83
|
- !ruby/object:Gem::Version
|
73
84
|
version: '0'
|
74
85
|
requirements: []
|
@@ -76,5 +87,9 @@ rubyforge_project:
|
|
76
87
|
rubygems_version: 2.0.3
|
77
88
|
signing_key:
|
78
89
|
specification_version: 4
|
79
|
-
summary:
|
80
|
-
test_files:
|
90
|
+
summary: ODM (Object-Document-Mapper) for the Google Cloud Datastore.
|
91
|
+
test_files:
|
92
|
+
- spec/client_spec.rb
|
93
|
+
- spec/credentials.yml.example
|
94
|
+
- spec/dataset_spec.rb
|
95
|
+
- spec/spec_helper.rb
|