guacamole 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +1 -1
  3. data/.travis.yml +16 -15
  4. data/CHANGELOG.md +16 -0
  5. data/GOALS.md +8 -0
  6. data/Guardfile +4 -0
  7. data/README.md +21 -81
  8. data/guacamole.gemspec +3 -3
  9. data/lib/guacamole.rb +1 -0
  10. data/lib/guacamole/aql_query.rb +6 -1
  11. data/lib/guacamole/collection.rb +34 -66
  12. data/lib/guacamole/configuration.rb +53 -25
  13. data/lib/guacamole/document_model_mapper.rb +149 -38
  14. data/lib/guacamole/edge.rb +74 -0
  15. data/lib/guacamole/edge_collection.rb +91 -0
  16. data/lib/guacamole/exceptions.rb +0 -5
  17. data/lib/guacamole/graph_query.rb +31 -0
  18. data/lib/guacamole/model.rb +4 -0
  19. data/lib/guacamole/proxies/proxy.rb +7 -3
  20. data/lib/guacamole/proxies/relation.rb +22 -0
  21. data/lib/guacamole/railtie.rb +1 -1
  22. data/lib/guacamole/transaction.rb +177 -0
  23. data/lib/guacamole/version.rb +1 -1
  24. data/shared/transaction.js +66 -0
  25. data/spec/acceptance/aql_spec.rb +32 -40
  26. data/spec/acceptance/relations_spec.rb +239 -0
  27. data/spec/acceptance/spec_helper.rb +2 -2
  28. data/spec/fabricators/author_fabricator.rb +2 -0
  29. data/spec/setup/arangodb.sh +2 -2
  30. data/spec/unit/collection_spec.rb +20 -97
  31. data/spec/unit/configuration_spec.rb +73 -50
  32. data/spec/unit/document_model_mapper_spec.rb +84 -77
  33. data/spec/unit/edge_collection_spec.rb +174 -0
  34. data/spec/unit/edge_spec.rb +57 -0
  35. data/spec/unit/proxies/relation_spec.rb +35 -0
  36. metadata +22 -14
  37. data/lib/guacamole/proxies/referenced_by.rb +0 -15
  38. data/lib/guacamole/proxies/references.rb +0 -15
  39. data/spec/acceptance/association_spec.rb +0 -40
  40. data/spec/unit/example_spec.rb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da19a1adc7e260053f9749aaaa5af277e706fbda
4
- data.tar.gz: 08392381e86a454d91a3da30efac6b86599234be
3
+ metadata.gz: 8e3a2220d3b6b1d046bb962bf652a800b899e825
4
+ data.tar.gz: 2de4ad8f20cfc6af2cb55aaf312177507974cac8
5
5
  SHA512:
6
- metadata.gz: 40ec254c0113a1f8ee0bc2dbdb8624c2d5f3c0ea55cb1e981e45d91b38eb4167f590896cce392d9c5a8419ddea208ce29600f116b24fbf7f2108aa0181c54b47
7
- data.tar.gz: b7b301e8c84692d620316a29e02ee654b6358427e5e92016957a7f66aeb9b249268eacffffe9d715bb28f7508f9ec3ca8746ef92f043326c56ecc7a0f4cab708
6
+ metadata.gz: 78e8fd40d3284e7abd1eac0c97d46d59413c53edc8c23693d8f6f686948486aa353443b3484fa67f5d39b247382674b17840d05591e00353b61735b008226db2
7
+ data.tar.gz: cbaeb3e19f0223bdca0f52122d042169528b4ba8f9ef7d983a4364d016b29d40ed39463ea7d77c08d9ccd9f1c59a82a7f2dbd0adb8a4672e0ee5739277c2b1e3
data/.hound.yml CHANGED
@@ -22,7 +22,7 @@ CollectionMethods:
22
22
  PreferredMethods:
23
23
  collect: 'map'
24
24
  inject: 'reduce'
25
- find: 'detect'
25
+ find: 'find'
26
26
  find_all: 'select'
27
27
 
28
28
  SignalException:
@@ -1,24 +1,25 @@
1
1
  language: ruby
2
- bundler_args: --without debug
2
+ bundler_args: "--without debug"
3
3
  before_script:
4
- - ./spec/setup/arangodb.sh
4
+ - "./spec/setup/arangodb.sh"
5
5
  rvm:
6
- - 1.9.3
7
- - 2.0.0
8
- - 2.1.2
9
- - jruby-19mode
10
- - jruby-head
11
- - rbx-19mode
12
- - ruby-head
6
+ - 1.9.3
7
+ - 2.0.0
8
+ - 2.1.2
9
+ - jruby-19mode
10
+ - jruby-head
11
+ - ruby-head
13
12
  env:
14
- - ARANGODB_DISABLE_AUTHENTIFICATION=true VERSION=2.0
13
+ - ARANGODB_DISABLE_AUTHENTIFICATION=true VERSION=2.2
15
14
  matrix:
16
15
  allow_failures:
17
- - rvm: jruby-19mode
18
- - rvm: ruby-head
19
- - rvm: jruby-head
20
- - rvm: rbx-19mode
21
- script: "bundle exec rake ci"
16
+ - rvm: jruby-19mode
17
+ - rvm: ruby-head
18
+ - rvm: jruby-head
19
+ script: bundle exec rake ci
22
20
  addons:
23
21
  code_climate:
24
22
  repo_token: cd5dd119d022e5b0d4fda98d25aa93473ed5b580c3f621475c3e605a858f5790
23
+ notifications:
24
+ slack:
25
+ secure: H8F0Eo0dc0uP0kh4Wm4D6kDuDeEQrjTotUpz2n4Ls8errJp0r0C9CbXrRE574B1VeZF/tBzm9IUx4wDRuR2xaYfIww5gJTz2+RKp+thgspz8L3KW5nuLttxzqp8cNP2b9Gedj72nTebQK3gEt7v/HFgo9lg2QSEvZ4n7zYFkmIc=
@@ -1,3 +1,19 @@
1
+ ## Version 0.4.0
2
+
3
+ **Codename: Theatre of Pain**
4
+
5
+ This release focus on the graph integration of ArangoDB 2.2. We implemented relations on top of graphs. The old implementation for relations **has been removed**. If you still need it **don't just upgrade**.
6
+
7
+ Notable changes are:
8
+
9
+ * Implement relations with a graph (#83)
10
+ * Added section about design to GOALS.md
11
+ * AQL Support is default now (#91)
12
+ * Typo fixes in the README (@badboy, @ifraixedes, @solnic @timoschilling)
13
+ * Internal changes
14
+ * Relations based on foreign keys have been removed
15
+
16
+
1
17
  ## Version 0.3.0
2
18
 
3
19
  **Codename: Spread your Wings**
data/GOALS.md CHANGED
@@ -6,9 +6,17 @@
6
6
  * Reflect the nature of NoSQL in general and ArangoDB in particular
7
7
  * Use the Datamapper pattern, because it allows us to leverage ArangoDB features like nesting in a really nice way
8
8
  * Support ArangoDB features like transactions, the query language and graphs
9
+ * Don't cut corners on quality
10
+ * Strive for simplicity
9
11
 
10
12
  *The two main goals may conflict from time to time.*
11
13
 
14
+ ## Design Decisions
15
+
16
+ We are well aware that the decision for data mapper in favor of active record has certain drawbacks. But this is the case with every single decision one will ever make in software development. We have strong believes in a simple software design. We think when it comes to building applications a good simple design can only be achieved by using simple libraries and frameworks. ActiveRecord is not simple anymore. And its usage will result in a not simple application. In our opinion one reason for this is the usage of the active record pattern. ActiveRecord is very convenient but it is not simple. Going with a data mapper approach is less convenient at first but will pay off in the long run.
17
+
18
+ At the same time Guacamole should enable people to use [ArangoDB](https://www.arangodb.com) in their Ruby and especially Rails projects. Due to this we will always have to compromise between our pursuit of simplicity and the usability for a wide range of developers who are mostly used to the Rails Way of doing things. We try do be more on the simple side but eventually we will fail from time to time. We don't think this is inherently a bad thing because to fail is to learn as well. We will always re-evaluate our decisions and refactor whenever possible.
19
+
12
20
  ## Features of Guacamole 1.0
13
21
 
14
22
  **This is definitely a moving target and up to discussion. For non-moving targets refer to our [milestones](https://github.com/triAGENS/guacamole/issues/milestones).**
data/Guardfile CHANGED
@@ -7,3 +7,7 @@ guard 'rspec', spec_paths: ['spec/unit'] do
7
7
  watch(%r{spec/.+\.rb})
8
8
  watch(%r{lib/guacamole/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
9
9
  end
10
+
11
+ guard 'rspec', spec_path: ['spec/acceptance'] do
12
+ watch(%r{spec/acceptance/.+\.rb})
13
+ end
data/README.md CHANGED
@@ -3,10 +3,11 @@
3
3
  [![Code Climate](http://img.shields.io/codeclimate/github/triAGENS/guacamole.svg)](https://codeclimate.com/github/triAGENS/guacamole)
4
4
  [![Inline docs](http://inch-ci.org/github/triAGENS/guacamole.svg)](http://inch-ci.org/github/triAGENS/guacamole)
5
5
  [![Gem Version](http://img.shields.io/gem/v/guacamole.svg)](https://rubygems.org/gems/guacamole)
6
+ [![Codeship Status](https://codeship.io/projects/a30d6040-350a-0132-1102-3e0229153f11/status)](https://codeship.io/projects/40903)
6
7
 
7
8
  # Guacamole
8
9
 
9
- Guacamole is an Object Document Mapper (ODM) for the multi-model NoSQL database [ArangoDB](https://www.arangodb.org/). Its main goal is to support easy integration into Ruby on Rails but will likely work in other Rack-based frameworks as well. There are a couple of design goals behind Guacamole which should drive all our development effort:
10
+ Guacamole is an Object Document Mapper (ODM) for the multi-model NoSQL database [ArangoDB](https://www.arangodb.com/). Its main goal is to support easy integration into Ruby on Rails but will likely work in other Rack-based frameworks as well. There are a couple of design goals behind Guacamole which should drive all our development effort:
10
11
 
11
12
  * Easy integration on the View layer (i.e. form builders)
12
13
  * Reflect the nature of NoSQL in general and ArangoDB in particular
@@ -86,7 +87,7 @@ After you created a configuration file you can create the database as in any oth
86
87
  bundle exec rake db:create
87
88
  ```
88
89
 
89
- If you're using Capistrano or something else make sure you change your deployment recipes accordingly to use the `guacamole.yml` and not the `database.yml`. Of course you would want to add [authentication](https://www.arangodb.org/manuals/2/DbaManualAuthentication.html) for the production environment. Additionally you may want to consider putting ArangoDB behind a SSL-proxy or use the [built in SSL support](https://www.arangodb.org/manuals/2/CommandLine.html#CommandLineArangoEndpoint).
90
+ If you're using Capistrano or something else make sure you change your deployment recipes accordingly to use the `guacamole.yml` and not the `database.yml`. Of course you would want to add [authentication](https://docs.arangodb.com/ConfigureArango/Authentication.html) for the production environment. Additionally you may want to consider putting ArangoDB behind a SSL-proxy or use the [built in SSL support](https://docs.arangodb.com/ConfigureArango/Arangod.html).
90
91
 
91
92
  Now where everything is set up we can go ahead and create our application's logic. Before we give you some code to copy and paste we first give you a general usage and design overview.
92
93
 
@@ -146,7 +147,7 @@ We will automatically add both a `created_at` and an `updated_at` attribute to a
146
147
 
147
148
  #### The ID of a model
148
149
 
149
- In ArangoDB a document has three internal fields: `_id`, `_key` and `_rev`. For a detailed explanation how these three work together please refer to the [ArangoDB documentation](https://www.arangodb.org/manuals/2/HandlingDocuments.html#HandlingDocumentsIntro). Within Guacamole we will always use the `_key` because it is enough the identify any document within a collection. Both the `_key` and `_rev` attribute are available through the `Guacamole::Model#key` and `Guacamole::Model#rev` attribute. You don't have to do anything for this, we will take care of this for you.
150
+ In ArangoDB a document has three internal fields: `_id`, `_key` and `_rev`. For a detailed explanation how these three work together please refer to the [ArangoDB documentation](https://docs.arangodb.com/Documents/DocumentAddress.html). Within Guacamole we will always use the `_key` because it is enough the identify any document within a collection. Both the `_key` and `_rev` attribute are available through the `Guacamole::Model#key` and `Guacamole::Model#rev` attribute. You don't have to do anything for this, we will take care of this for you.
150
151
 
151
152
  Additionally you will find an `id` method on you models. This is just an alias for `key`. This was added for `ActiveModel::Conversion` compliance. You **should always** use `key`.
152
153
 
@@ -189,10 +190,10 @@ As with the models we provide a generator to help you creating your collection c
189
190
  bundle exec rails generate collection ponies
190
191
  ```
191
192
 
192
- Currently your options what you can do with a collection are quire limited. We will eventually add more features, but for now you basically have this features:
193
+ Currently your options what you can do with a collection are quite limited. We will eventually add more features, but for now you basically have this features:
193
194
 
194
195
  * CRUD operations for your models
195
- * Where the "Read"-part is limited to [Simple Queries](https://www.arangodb.org/manuals/2/SimpleQueries.html). But more on this later.
196
+ * Where the "Read"-part is limited to [Simple Queries](https://docs.arangodb.com/SimpleQueries/README.html). But more on this later.
196
197
  * Mapping embedded models
197
198
  * Realizing basic associations
198
199
 
@@ -235,7 +236,7 @@ PoniesCollection.delete existing_pony
235
236
 
236
237
  #### Retrieve models
237
238
 
238
- As mentioned before querying for models is quite limited as of now. We only support [Simple Queries](https://www.arangodb.org/manuals/2/SimpleQueries.html) at this point. You can perform the following basic operations with them:
239
+ As mentioned before querying for models is quite limited as of now. We only support [Simple Queries](https://docs.arangodb.com/SimpleQueries/README.html) at this point. You can perform the following basic operations with them:
239
240
 
240
241
  * Getting a single model `by_key`
241
242
  * Getting `all` models from a collection.
@@ -252,7 +253,7 @@ some_ponies.first
252
253
  # => #<Pony:0x90u81 …>
253
254
  ```
254
255
 
255
- We're well aware this is not sufficient for building sophisticated applications. We're are working on something to make [AQL](https://www.arangodb.org/manuals/2/Aql.html) usable from Guacamole.
256
+ We're well aware this is not sufficient for building sophisticated applications. We're are working on something to make [AQL](https://docs.arangodb.com/Aql/README.html) usable from Guacamole.
256
257
 
257
258
  ### Mapping
258
259
 
@@ -296,6 +297,7 @@ Currently there is no option to change the mapping of attributes. If you want to
296
297
 
297
298
  #### Associations
298
299
 
300
+ **TODO: This needs some work to include relations**
299
301
  Besides simple attributes we want to handle associations between models. To add an association between your models you have two options: __embedded__ and __referenced__.
300
302
 
301
303
  #### Embedded references
@@ -354,67 +356,9 @@ As you can see, from the model perspective there is nothing special about an emb
354
356
 
355
357
  **Note**: Again this will only work if you stick with the convention. So far there is no support to configure this more fine grained.
356
358
 
357
- #### References
359
+ ### Relations
358
360
 
359
- While there are perfect use cases to embed documents into each other there are still plenty of use cases where referencing documents makes perfect sense. In fact this one feature where ArangoDB can really shine: Instead of just getting all referenced documents with dedicated calls to the server and without the possibility to perform any functions like filtering or sorting the data, ArangoDB can perform joins over your data just like a RDBMS.
360
-
361
- **Note**: In the current version we're not using this power since we need to support AQL before that. As of now references are realized with dedicated calls to the database.
362
-
363
- To define references between models you just add the appropriate attributes to the `Model` classes:
364
-
365
- ```ruby
366
- class Author
367
- include Guacamole::Model
368
-
369
- attribute :name, String
370
- attribute :posts, Array[Post]
371
- end
372
-
373
- class Post
374
- include Guacamole::Model
375
-
376
- attribute :title, String
377
- attribute :author, Author
378
- end
379
- ```
380
-
381
- As with the embedded models the real work happens in the `Collection` classes:
382
-
383
- ```ruby
384
- class AuthorsCollection
385
- include Guacamole::Collection
386
-
387
- map do
388
- referenced_by :posts
389
- end
390
- end
391
-
392
- class PostsCollection
393
- include Guacamole::Collection
394
-
395
- map do
396
- references :author
397
- end
398
- end
399
- ```
400
-
401
- Under the hood we will add an `author_id` to all posts holding the reference to the author. As a user this will be completely transparent for you:
402
-
403
- ```ruby
404
- author = AuthorsCollection.by_key "23124"
405
- author.posts
406
- # => [#<Post:0x12341 …>, …]
407
- ```
408
-
409
- The same goes for saving the data. Just add `Post`s to an `Author` as you would in plain Ruby. Passing one of the models to its `Collection` class will take care of the rest:
410
-
411
- ```ruby
412
- author = Author.new(name: "Lauren Faust")
413
- author.posts << Post.new(title: "This is amazing")
414
-
415
- AuthorsCollection.save author
416
- # => Will save both the author and the post
417
- ```
361
+ **>>>> Insert documentation for relations here!**
418
362
 
419
363
  ### Callbacks
420
364
 
@@ -442,7 +386,7 @@ class User
442
386
  end
443
387
  ```
444
388
 
445
- You can define define callbacks for the following actions:
389
+ You can define callbacks for the following actions:
446
390
 
447
391
  * `before_validate`
448
392
  * `around_validate`
@@ -560,33 +504,29 @@ While there are a lot of open issues we would like to present you a high level o
560
504
  * An example Rails application to be used as both an acceptance test suite and a head start for Guacamole and ArangoDB
561
505
  * An AQL query builder
562
506
 
563
- ### Experimental AQL Support
507
+ ### AQL Support
564
508
 
565
- As mentioned before we're working on [something more sophisticated to support AQL](https://github.com/moonglum/brazil/issues/8). But this will not be finished any time soon. Meanwhile you could play with the experimental AQL support:
566
-
567
- ```ruby
568
- config.guacamole.experimental_features = [:aql_support]
569
- ```
570
-
571
- After that you can perform very basic queries like this one:
509
+ As mentioned before we're working on [something more sophisticated to support AQL](https://github.com/moonglum/brazil/issues/8). But this will not be finished any time soon. That said, there is still a way to to perform AQL queries against ArangoDB. For simple queries you can do something like this:
572
510
 
573
511
  ```ruby
574
512
  PoniesCollection.by_aql('FILTER pony.name == @name', name: 'Rainbow Dash')
575
513
  ```
576
514
 
577
- The result of this will a correctly mapped Array of `Pony` models.
578
-
579
- **Note**: Please use only this form to pass parameters into a query. Using string interpolation will leave you vulnerable to AQL-injections.
515
+ The result of this will a correctly mapped Array of `Pony` models. If this is not enough thou, don't worry, you can get really fancy with this. Due to this you can deactivate the automatic mapping of the response. In that case you will receive just a raw document you can work with. **Note**: Please use only this form to pass parameters into a query. Using string interpolation will leave you vulnerable to AQL-injections.
580
516
 
581
517
  For more information about usage please refer to the RDoc and the code.
582
518
 
583
519
  ## Issues or Questions
584
520
 
585
- If you find a bug in this gem, please report it on [our tracker](https://github.com/triAGENS/guacamole/issues). We use [Waffle.io](https://waffle.io/triagens/guacamole) to manage the tickets – go there to see the current status of the ticket. If you have a question, just contact us via the [mailing list](https://groups.google.com/forum/?fromgroups#!forum/ashikawa) – we are happy to help you :smile:
521
+ If you find a bug in this gem, please report it on [our tracker](https://github.com/triAGENS/guacamole/issues). If you have a question, just contact us via the [mailing list](https://groups.google.com/forum/?fromgroups#!forum/ashikawa) – we are happy to help you :smile:
586
522
 
587
523
  ## Contributing
588
524
 
589
- If you want to contribute to the project, see CONTRIBUTING.md for details. It contains information on our process and how to set up everything. The following people have contributed to this project:
525
+ If you want to contribute to the project, see [CONTRIBUTING.md](CONTRIBUTING.md) for details. It contains information on our process and how to set up everything. The following people have contributed to this project:
590
526
 
591
527
  * Lucas Dohmen ([@moonglum](https://github.com/moonglum)): Developer
592
528
  * Dirk Breuer ([@railsbros-dirk](https://github.com/railsbros-dirk)): Developer
529
+
530
+ ## Inspiration
531
+
532
+ The work on Guacamole is heavily inspired by the remarkable work of the [ROM](http://rom-rb.org) team and especially by [Piotr Solnica](http://solnic.eu).
@@ -7,7 +7,7 @@ Gem::Specification.new do |spec|
7
7
  spec.name = 'guacamole'
8
8
  spec.version = Guacamole::VERSION
9
9
  spec.authors = ['Lucas Dohmen', 'Dirk Breuer']
10
- spec.email = ['moonglum@moonbeamlabs.com', 'dirk.breuer@gmail.com']
10
+ spec.email = ['lucas@arangodb.com', 'dirk@arangodb.com']
11
11
  spec.description = %q{ODM for ArangoDB}
12
12
  spec.summary = %q{An ODM for ArangoDB that uses the DataMapper pattern.}
13
13
  spec.homepage = 'http://guacamolegem.org'
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(spec)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'ashikawa-core', '~> 0.12.0'
21
+ spec.add_dependency 'ashikawa-core', '~> 0.13.1'
22
22
  spec.add_dependency 'virtus', '~> 1.0.1'
23
23
  spec.add_dependency 'activesupport', '>= 4.0.0'
24
24
  spec.add_dependency 'activemodel', '>= 4.0.0'
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency 'pry', '~> 0.9.12'
37
37
  spec.add_development_dependency 'rake', '~> 10.3.2'
38
38
  spec.add_development_dependency 'reek', '~> 1.3.7'
39
- spec.add_development_dependency 'rspec', '~> 3.0.0'
39
+ spec.add_development_dependency 'rspec', '~> 3.1.0'
40
40
  spec.add_development_dependency 'timecop', '~> 0.7.1'
41
41
  spec.add_development_dependency 'yard', '~> 0.8.7.4'
42
42
  end
@@ -5,6 +5,7 @@ require 'guacamole/exceptions'
5
5
  require 'guacamole/configuration'
6
6
  require 'guacamole/model'
7
7
  require 'guacamole/collection'
8
+ require 'guacamole/edge'
8
9
  require 'guacamole/callbacks'
9
10
  require 'guacamole/document_model_mapper'
10
11
  require 'guacamole/identity_map'
@@ -44,7 +44,7 @@ module Guacamole
44
44
  #
45
45
  # @return [String] An AQL string ready to be send to Arango
46
46
  def aql_string
47
- aql_string = "FOR #{model_name} IN #{collection_name} #{aql_fragment} #{return_as}"
47
+ aql_string = "#{for_in} #{aql_fragment} #{return_as}"
48
48
  Guacamole.logger.debug "[AQL] #{aql_string} | bind_parameters: #{bind_parameters}"
49
49
  aql_string
50
50
  end
@@ -56,6 +56,10 @@ module Guacamole
56
56
  options[:return_as]
57
57
  end
58
58
 
59
+ def for_in
60
+ options[:for_in]
61
+ end
62
+
59
63
  # Should the mapping step be perfomed? If set to false we will return the raw document.
60
64
  #
61
65
  # @return [Boolean] Either if the mapping should be perfomed or not
@@ -69,6 +73,7 @@ module Guacamole
69
73
  def default_options
70
74
  {
71
75
  return_as: "RETURN #{model_name}",
76
+ for_in: "FOR #{model_name} IN #{collection_name}",
72
77
  mapping: true
73
78
  }
74
79
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'guacamole/query'
4
4
  require 'guacamole/aql_query'
5
+ require 'guacamole/transaction'
5
6
 
6
7
  require 'ashikawa-core'
7
8
  require 'active_support'
@@ -34,7 +35,7 @@ module Guacamole
34
35
  def_delegators :mapper, :model_to_document
35
36
  def_delegator :connection, :fetch, :fetch_document
36
37
 
37
- attr_accessor :connection, :mapper, :database
38
+ attr_accessor :connection, :mapper, :database, :graph
38
39
 
39
40
  # The raw `Database` object that was configured
40
41
  #
@@ -47,18 +48,33 @@ module Guacamole
47
48
  @database ||= Guacamole.configuration.database
48
49
  end
49
50
 
51
+ # The application graph to be used
52
+ #
53
+ # This is quite important since we're using the Graph module to realize relations
54
+ # between models. To guarantee consistency of your data all requests must be routed
55
+ # through the graph module.
56
+ #
57
+ # @see http://rubydoc.info/gems/ashikawa-core/Ashikawa/Core/Graph
58
+ # @return [Ashikawa::Core::Graph]
59
+ def graph
60
+ @graph ||= Guacamole.configuration.graph
61
+ end
62
+
50
63
  # The raw `Collection` object for this collection
51
64
  #
52
65
  # You can use this method for low level communication with the collection.
53
66
  # Details can be found in the Ashikawa::Core documentation.
54
67
  #
55
- # @note We're well aware that we return a Ashikawa::Core::Collection here
68
+ # @note We're well aware that we return a Ashikawa::Core::VertecCollection here
56
69
  # but naming it a connection. We think the name `connection` still
57
70
  # fits better in this context.
58
- # @see http://rubydoc.info/gems/ashikawa-core/Ashikawa/Core/Collection
59
- # @return [Ashikawa::Core::Collection]
71
+ # @see http://rubydoc.info/gems/ashikawa-core/Ashikawa/Core/VertexCollection
72
+ # @return [Ashikawa::Core::VertexCollection]
60
73
  def connection
61
- @connection ||= database[collection_name]
74
+ # FIXME: This is a workaround for a bug in Ashikawa::Core (https://github.com/triAGENS/ashikawa-core/issues/139)
75
+ @connection ||= graph.add_vertex_collection(collection_name)
76
+ rescue
77
+ @connection ||= graph.vertex_collection(collection_name)
62
78
  end
63
79
 
64
80
  # The DocumentModelMapper for this collection
@@ -231,13 +247,7 @@ module Guacamole
231
247
  #
232
248
  # Since Simple Queries are quite limited in their possibilities you will need to
233
249
  # use AQL for more advanced data retrieval. Currently there is only a very basic
234
- # and experimental support for AQL. Eventually we will replace it with an advanced
235
- # query builder DSL. Due to this, we deactivated this feature per default. You
236
- # need to activate it with {Configuration#aql_support}:
237
- #
238
- # Guacamole::Configuration.aql_support = :experimental
239
- #
240
- # If not activated it we will raise an error.
250
+ # support for AQL. Nevertheless it will allow to use any arbitrary query you want.
241
251
  #
242
252
  # @param [String] aql_fragment An AQL string that will will be put between the
243
253
  # `FOR x IN coll` and the `RETURN x` part.
@@ -246,13 +256,10 @@ module Guacamole
246
256
  # @option options [String] :return_as ('RETURN #{model_name}') A custom `RETURN` statement
247
257
  # @option options [Boolean] :mapping (true) Should the mapping be performed?
248
258
  # @return [Query]
249
- # @raise [AQLNotSupportedError] If `aql_support` was not activated
250
259
  # @note Please use always bind parameters since they provide at least some form
251
260
  # of protection from AQL injection.
252
- # @see https://www.arangodb.org/manuals/2/Aql.html AQL Documentation
261
+ # @see https://docs.arangodb.com/Aql/README.html AQL Documentation
253
262
  def by_aql(aql_fragment, bind_parameters = {}, options = {})
254
- raise AQLNotSupportedError unless Guacamole.configuration.experimental_features.include?(:aql_support)
255
-
256
263
  query = AqlQuery.new(self, mapper, options)
257
264
  query.aql_fragment = aql_fragment
258
265
  query.bind_parameters = bind_parameters
@@ -294,54 +301,12 @@ module Guacamole
294
301
  # persisted. In future versions we should add something like `:autosave`
295
302
  # to always save associated models.
296
303
  def create_document_from(model)
297
- create_referenced_models_of model
304
+ result = with_transaction(model)
298
305
 
299
- document = connection.create_document(model_to_document(model))
306
+ model.key = result[model.object_id.to_s]['_key']
307
+ model.rev = result[model.object_id.to_s]['_rev']
300
308
 
301
- model.key = document.key
302
- model.rev = document.revision
303
-
304
- create_referenced_by_models_of model
305
-
306
- document
307
- end
308
-
309
- # Creates all not yet persisted referenced models of `model`
310
- #
311
- # Referenced models needs to be created before the parent model, because it needs their `key`
312
- #
313
- # @api private
314
- # @todo This method should be considered 'work in progress'. We already know we need to change this.
315
- # @return [void]
316
- def create_referenced_models_of(model)
317
- mapper.referenced_models.each do |ref_model_name|
318
- ref_collection = mapper.collection_for(ref_model_name)
319
-
320
- ref_model = model.send(ref_model_name)
321
- next unless ref_model
322
-
323
- ref_collection.save ref_model unless ref_model.persisted?
324
- end
325
- end
326
-
327
- # Creates all not yet persisted models which are referenced by `model`
328
- #
329
- # Referenced by models needs to created after the parent model, because they need its `key`
330
- #
331
- # @api private
332
- # @todo This method should be considered 'work in progress'. We already know we need to change this.
333
- # @return [void]
334
- def create_referenced_by_models_of(model)
335
- mapper.referenced_by_models.each do |ref_model_name|
336
- ref_collection = mapper.collection_for(ref_model_name)
337
-
338
- ref_models = model.send(ref_model_name)
339
-
340
- ref_models.each do |ref_model|
341
- ref_model.send("#{model.class.name.demodulize.underscore}=", model)
342
- ref_collection.save ref_model unless ref_model.persisted?
343
- end
344
- end
309
+ model
345
310
  end
346
311
 
347
312
  # Replace a document in the database with this model
@@ -349,12 +314,15 @@ module Guacamole
349
314
  # @api private
350
315
  # @note This will **not** update associated models (see {#create})
351
316
  def replace_document_from(model)
352
- document = model_to_document(model)
353
- response = connection.replace(model.key, document)
317
+ result = with_transaction(model)
354
318
 
355
- model.rev = response['_rev']
319
+ model.rev = result['_rev']
320
+
321
+ model
322
+ end
356
323
 
357
- document
324
+ def with_transaction(model)
325
+ Transaction.run(collection: self, model: model)
358
326
  end
359
327
 
360
328
  # Gets the callback class for the given model class