arangodb-odm 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -6,6 +6,9 @@ group :development do
6
6
  gem "shoulda", ">= 0"
7
7
  gem "bundler", "~> 1.1.0"
8
8
  gem "jeweler", "~> 1.6.4"
9
- gem "rcov", ">= 0"
10
9
  gem "rdoc", "~> 2.4.2"
11
10
  end
11
+
12
+ group :test do
13
+ gem 'simplecov', :require => false
14
+ end
@@ -25,7 +25,6 @@ GEM
25
25
  multi_json (1.4.0)
26
26
  multi_xml (0.5.1)
27
27
  rake (10.0.2)
28
- rcov (1.0.0)
29
28
  rdoc (2.4.3)
30
29
  hoe (>= 1.12.1)
31
30
  minitest (~> 1.3)
@@ -36,6 +35,10 @@ GEM
36
35
  shoulda-matchers (1.4.2)
37
36
  activesupport (>= 3.0.0)
38
37
  bourne (~> 1.1.2)
38
+ simplecov (0.7.1)
39
+ multi_json (~> 1.0)
40
+ simplecov-html (~> 0.7.1)
41
+ simplecov-html (0.7.1)
39
42
 
40
43
  PLATFORMS
41
44
  ruby
@@ -45,6 +48,6 @@ DEPENDENCIES
45
48
  httparty
46
49
  jeweler (~> 1.6.4)
47
50
  json
48
- rcov
49
51
  rdoc (~> 2.4.2)
50
52
  shoulda
53
+ simplecov
data/README.md CHANGED
@@ -57,6 +57,12 @@
57
57
  #### First by example
58
58
 
59
59
  ExampleDocument.where('foo' => 'bar', 'a' => 'b').first
60
+
61
+ #### Range
62
+
63
+ # Make sure you've setup a skip-list index on the attribute
64
+ ExampleDocument.attribute('test').left(0).right(100).all
65
+ ExampleDocument.attribute('test').left(0).right(100).closed(true).skip(10).limit(10).all
60
66
 
61
67
  ## Callbacks
62
68
 
@@ -98,6 +104,20 @@
98
104
 
99
105
  def change_something_else; end
100
106
  end
107
+
108
+ ## Indices
109
+
110
+ ### Skip List Index Definition
111
+
112
+ class ExampleDocument < ArangoDb::Base
113
+ collection :examples
114
+ skiplist :test, :something_else
115
+ end
116
+
117
+ ### Creating indices
118
+
119
+ # Creates all indices defined in the document. Run it once when you setup your document model...
120
+ ExampleDocument.ensure_indices
101
121
 
102
122
  ## Copyright
103
123
 
data/Rakefile CHANGED
@@ -33,13 +33,7 @@ Rake::TestTask.new(:test) do |test|
33
33
  test.verbose = true
34
34
  end
35
35
 
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/test_*.rb'
40
- test.verbose = true
41
- test.rcov_opts << '--exclude "gems/*"'
42
- end
36
+ # TODO simplecov
43
37
 
44
38
  task :default => :test
45
39
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
@@ -1,7 +1,10 @@
1
1
  require "rubygems"
2
2
  require "httparty"
3
3
  require "json"
4
+
5
+ require "collections"
4
6
  require "queries"
7
+ require "indices"
5
8
 
6
9
  module ArangoDb
7
10
  class Transport
@@ -29,60 +32,83 @@ module ArangoDb
29
32
  end
30
33
  end
31
34
 
35
+ class Index
36
+ attr_accessor :indices
37
+
38
+ def initialize(indices)
39
+ @indices = indices
40
+ end
41
+ end
42
+
32
43
  module Properties
33
44
  def self.included(klass)
34
45
  klass.extend ClassMethods
35
46
  end
36
47
 
37
48
  module ClassMethods
49
+ # The collection to use for this document.
38
50
  def collection(value)
39
51
  (class << self; self; end).send(:define_method, 'collection') do
40
52
  value.to_s
41
53
  end
42
54
  end
43
55
 
56
+ def skiplist(*fields)
57
+ (class << self; self; end).send(:define_method, 'skiplist') do
58
+ fields.to_a
59
+ end
60
+ end
61
+
62
+ # Sets the transport class to use. Defaults to httparty.
44
63
  def transport(value)
45
64
  (class << self; self; end).send(:define_method, 'transport') do
46
65
  value
47
66
  end
48
67
  end
49
68
 
69
+ # Sets the document value proxy to use.
50
70
  def target(value)
51
71
  (class << self; self; end).send(:define_method, 'target') do
52
72
  value
53
73
  end
54
74
  end
55
75
 
76
+ # Callback that is being invoked before a document is first created.
56
77
  def before_create(value)
57
78
  self.send(:define_method, 'before_create') do
58
79
  value
59
80
  end
60
81
  end
61
82
 
83
+ # Callback that is being invoked after a document is first created.
62
84
  def after_create(value)
63
85
  self.send(:define_method, 'after_create') do
64
86
  value
65
87
  end
66
88
  end
67
89
 
90
+ # Callback that is being invoked before a document is updated.
68
91
  def before_save(value)
69
92
  self.send(:define_method, 'before_save') do
70
93
  value
71
94
  end
72
95
  end
73
96
 
97
+ # Callback that is being invoked after a document was updated.
74
98
  def after_save(value)
75
99
  self.send(:define_method, 'after_save') do
76
100
  value
77
101
  end
78
102
  end
79
103
 
104
+ # Callback that is being invoked before a document is destroyed.
80
105
  def before_destroy(value)
81
106
  self.send(:define_method, 'before_destroy') do
82
107
  value
83
108
  end
84
109
  end
85
110
 
111
+ # Callback that is being invoked after a document was destroyed.
86
112
  def after_destroy(value)
87
113
  self.send(:define_method, 'after_destroy') do
88
114
  value
@@ -106,18 +132,24 @@ module ArangoDb
106
132
  #
107
133
  # class ExampleDocument < ArangoDb::Base
108
134
  # collection :examples
135
+ # skiplist [:a, :b]
109
136
  # end
110
137
  class Base
111
138
  include ArangoDb::Properties
139
+ extend ArangoDb::Collections::ClassMethods
112
140
  extend ArangoDb::Queries::ClassMethods
141
+ extend ArangoDb::Indices::ClassMethods
113
142
  transport ArangoDb::Transport
114
143
  target ArangoDb::Document
115
144
  db_attrs []
116
- attr_reader :target
145
+ attr_reader :target, :index
117
146
 
118
147
  def initialize
119
148
  @transport = self.class.transport
120
149
  @target = self.class.target.new(self.class.collection, self.class.db_attributes)
150
+ if self.class.respond_to?(:skiplist) and self.class.skiplist
151
+ @index = ArangoDb::Index.new(:skiplist => self.class.skiplist)
152
+ end
121
153
  end
122
154
 
123
155
  def self.find(document_handle)
@@ -0,0 +1,24 @@
1
+ module ArangoDb
2
+ module Collections
3
+ module ClassMethods
4
+ # POST /_api/collection
5
+ # Creates an new collection with a given name. The request must contain an object with the following attributes.
6
+ # name: The name of the collection.
7
+ # waitForSync (optional, default: false): If true then the data is synchronised to disk before returning from a create or update of an document.
8
+ # journalSize (optional, default is a configuration parameter): The maximal size of a journal or datafile. Note that this also limits the maximal
9
+ # size of a single object. Must be at least 1MB.
10
+ # isSystem (optional, default is false): If true, create a system collection. In this case collection-name should start with an underscore.
11
+ # End users should normally create non-system collections only.
12
+ # API implementors may be required to create system collections in very special occasions, but normally a regular collection will do.
13
+ # type (optional, default is 2): the type of the collection to create. The following values for type are valid:
14
+ # 2: document collections
15
+ # 3: edge collection
16
+ def create_collection(options = {})
17
+ res = transport.post("/_api/collection", :body => options.merge('name' => collection).to_json)
18
+ if res.parsed_response and not res.parsed_response["code"] == 200
19
+ res.parsed_response["id"]
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,26 @@
1
+ module ArangoDb
2
+ module Indices
3
+ module ClassMethods
4
+
5
+ # POST /_api/index?collection=collection-identifier
6
+ # Creates a skip-list index for the collection collection-identifier, if it does not already exist. The call expects an object
7
+ # containing the index details.
8
+ # type: must be equal to "skiplist".
9
+ # fields: A list of attribute paths.
10
+ # unique: If true, then create a unique index.
11
+ def create_skiplist(fields)
12
+ query_parameters = { "type" => "skiplist", "unique" => false, "fields" => fields }
13
+ endpoint = "/_api/index?collection=#{collection}"
14
+ res = transport.post(endpoint, :body => query_parameters.to_json)
15
+ if res.parsed_response and not (res.parsed_response["code"] == 200 or res.parsed_response["code"] == 201)
16
+ raise "Couldn't create skip list index: #{res.parsed_response["code"]}"
17
+ end
18
+ end
19
+
20
+ def ensure_indices
21
+ create_skiplist(skiplist) if skiplist
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,6 +1,7 @@
1
1
  module ArangoDb
2
2
  module Queries
3
3
  class QueryResult < Array
4
+ # TODO
4
5
  end
5
6
 
6
7
  class Query
@@ -24,6 +25,26 @@ module ArangoDb
24
25
  self
25
26
  end
26
27
 
28
+ def attribute(attr_name)
29
+ @attribute = attr_name
30
+ self
31
+ end
32
+
33
+ def left(number)
34
+ @left = number
35
+ self
36
+ end
37
+
38
+ def right(number)
39
+ @right = number
40
+ self
41
+ end
42
+
43
+ def closed(boolean)
44
+ @closed = boolean
45
+ self
46
+ end
47
+
27
48
  def first
28
49
  @model.first(query_parameters)
29
50
  end
@@ -31,13 +52,17 @@ module ArangoDb
31
52
  def all
32
53
  @model.all(query_parameters)
33
54
  end
34
-
55
+
35
56
  private
36
57
  def query_parameters
37
58
  options = {}
38
59
  options['limit'] = @limit if @limit
39
60
  options['skip'] = @skip if @skip
40
61
  options['example'] = @where if @where
62
+ options['left'] = @left if @left
63
+ options['right'] = @right if @right
64
+ options['attribute'] = @attribute if @attribute
65
+ options['closed'] = @closed if @closed
41
66
  options
42
67
  end
43
68
  end
@@ -56,9 +81,24 @@ module ArangoDb
56
81
  # example: The example.
57
82
  # skip: The documents to skip in the query. (optional)
58
83
  # limit: The maximal amount of documents to return. (optional)
84
+ #
85
+ # PUT /_api/simple/range
86
+ # This will find all documents within a given range. You must declare a skip-list index on the attribute in order
87
+ # to be able to use a range query.The call expects a JSON hash array as body with the following attributes:
88
+ # collection: The identifier or name of the collection to query.
89
+ # attribute: The attribute path to check.
90
+ # left: The lower bound.
91
+ # right: The upper bound.
92
+ # closed: If true, use interval including left and right, otherwise exclude right, but include left.
93
+ # skip: The documents to skip in the query. (optional)
94
+ # limit: The maximal amount of documents to return. (optional)
59
95
  def all(options = {})
60
96
  query_parameters = {'collection' => collection}; endpoint = '/_api/simple/all'
61
- endpoint = '/_api/simple/by-example' if options and options['example'] and options['example'].any?
97
+ if options and options['example'] and options['example'].any?
98
+ endpoint = '/_api/simple/by-example'
99
+ elsif options and options['left'] and options['right'] and options['attribute']
100
+ endpoint = '/_api/simple/range'
101
+ end
62
102
  res = transport.put(endpoint, :body => query_parameters.merge(options).to_json)
63
103
  if res.code == 201 and res.parsed_response and res.parsed_response["result"]
64
104
  query_result = QueryResult.new
@@ -91,6 +131,22 @@ module ArangoDb
91
131
  def skip(number)
92
132
  Query.new(self).skip(number)
93
133
  end
134
+
135
+ def attribute(attr_name)
136
+ Query.new(self).attribute(attr_name)
137
+ end
138
+
139
+ def left(number)
140
+ Query.new(self).left(number)
141
+ end
142
+
143
+ def right(number)
144
+ Query.new(self).right(number)
145
+ end
146
+
147
+ def closed(boolean)
148
+ Query.new(self).closed(boolean)
149
+ end
94
150
  end
95
151
  end
96
152
  end
@@ -1,6 +1,7 @@
1
1
  class ExampleDocument < ArangoDb::Base
2
2
  collection :examples
3
-
3
+ skiplist :test
4
+
4
5
  before_create :add_something
5
6
  after_create :do_something_else
6
7
 
@@ -19,5 +19,10 @@ require 'another_example_document.rb'
19
19
  # Set your ArangoDB host...
20
20
  ArangoDb::Transport.base_uri 'http://localhost:8529'
21
21
 
22
+ # Initial setup
23
+ ExampleDocument.create_collection # only needed to be able to create indices on the initial test run
24
+ ExampleDocument.ensure_indices
25
+ # AnotherExampleDocument.create_collection
26
+
22
27
  class Test::Unit::TestCase
23
28
  end
@@ -0,0 +1,8 @@
1
+ require 'helper'
2
+
3
+ class TestArangoDbCollections < Test::Unit::TestCase
4
+ should "create a collection" do
5
+ assert true
6
+ # TODO
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestArangoDbIndices < Test::Unit::TestCase
4
+ should "create skiplist" do
5
+ assert ExampleDocument.ensure_indices
6
+ end
7
+ end
@@ -29,4 +29,24 @@ class TestArangoDbQueries < Test::Unit::TestCase
29
29
  example_document = ExampleDocument.where(:something => 'not existant').first
30
30
  assert_nil example_document
31
31
  end
32
+
33
+ should "get documents in a given range" do
34
+ ts = Time.now.to_i + rand(1000); count = 10
35
+ count.times {|i| ExampleDocument.create(:foo => "1", :test => ts + i)}
36
+
37
+ example_documents = ExampleDocument.attribute(:test).left(ts + 6).right(ts + 9).all
38
+ assert_not_nil example_documents
39
+ assert_equal example_documents.size, 3
40
+ assert_equal example_documents[0].test, ts + 6
41
+ assert_equal example_documents[1].test, ts + 7
42
+ assert_equal example_documents[2].test, ts + 8
43
+
44
+ example_documents = ExampleDocument.attribute(:test).left(ts + 6).right(ts + 9).closed(true).all
45
+ assert_not_nil example_documents
46
+ assert_equal example_documents.size, 4
47
+ assert_equal example_documents[0].test, ts + 6
48
+ assert_equal example_documents[1].test, ts + 7
49
+ assert_equal example_documents[2].test, ts + 8
50
+ assert_equal example_documents[3].test, ts + 9
51
+ end
32
52
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arangodb-odm
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 0
10
- version: 0.3.0
9
+ - 1
10
+ version: 0.3.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Oliver Kiessler
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-12-03 00:00:00 Z
18
+ date: 2012-12-08 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  requirement: &id001 !ruby/object:Gem::Requirement
@@ -93,20 +93,6 @@ dependencies:
93
93
  type: :development
94
94
  - !ruby/object:Gem::Dependency
95
95
  requirement: &id006 !ruby/object:Gem::Requirement
96
- none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- hash: 3
101
- segments:
102
- - 0
103
- version: "0"
104
- version_requirements: *id006
105
- name: rcov
106
- prerelease: false
107
- type: :development
108
- - !ruby/object:Gem::Dependency
109
- requirement: &id007 !ruby/object:Gem::Requirement
110
96
  none: false
111
97
  requirements:
112
98
  - - ~>
@@ -117,12 +103,12 @@ dependencies:
117
103
  - 4
118
104
  - 2
119
105
  version: 2.4.2
120
- version_requirements: *id007
106
+ version_requirements: *id006
121
107
  name: rdoc
122
108
  prerelease: false
123
109
  type: :development
124
110
  - !ruby/object:Gem::Dependency
125
- requirement: &id008 !ruby/object:Gem::Requirement
111
+ requirement: &id007 !ruby/object:Gem::Requirement
126
112
  none: false
127
113
  requirements:
128
114
  - - ">="
@@ -131,12 +117,12 @@ dependencies:
131
117
  segments:
132
118
  - 0
133
119
  version: "0"
134
- version_requirements: *id008
120
+ version_requirements: *id007
135
121
  name: httparty
136
122
  prerelease: false
137
123
  type: :runtime
138
124
  - !ruby/object:Gem::Dependency
139
- requirement: &id009 !ruby/object:Gem::Requirement
125
+ requirement: &id008 !ruby/object:Gem::Requirement
140
126
  none: false
141
127
  requirements:
142
128
  - - ">="
@@ -145,7 +131,7 @@ dependencies:
145
131
  segments:
146
132
  - 0
147
133
  version: "0"
148
- version_requirements: *id009
134
+ version_requirements: *id008
149
135
  name: json
150
136
  prerelease: false
151
137
  type: :runtime
@@ -167,11 +153,15 @@ files:
167
153
  - Rakefile
168
154
  - VERSION
169
155
  - lib/arangodb-odm.rb
156
+ - lib/collections.rb
157
+ - lib/indices.rb
170
158
  - lib/queries.rb
171
159
  - test/another_example_document.rb
172
160
  - test/example_document.rb
173
161
  - test/helper.rb
174
162
  - test/test_arangodb-odm.rb
163
+ - test/test_collections.rb
164
+ - test/test_indices.rb
175
165
  - test/test_queries.rb
176
166
  homepage: http://github.com/okiess/arangodb-odm
177
167
  licenses: