README.md in grumlin-0.23.0 vs README.md in grumlin-1.0.0.rc1

- old
+ new

@@ -80,129 +80,24 @@ ### Traversing graphs **Warning**: Not all steps and expressions defined in the reference documentation are supported. -#### Sugar - -Grumlin provides an easy to use module called `Grumlin::Sugar`. Once included in your class it injects some useful -constants and methods turning your class into an entrypoint for traversals with pure gremlin experience. - -```ruby -class MyRepository - include Grumlin::Sugar - - def nodes(property1:, property2:) - g.V() - .has(T.label, "node") - .has(:property1, property1) - .has(:property2, property2) - .order.by(:property3, Order.asc).limit(10) - .toList - end -end -``` - -#### Shortcuts - -**Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of -sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps. -Remember ActiveRecord scopes? Shortcuts are very similar. - -**Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be -be ignored because methods have higher priority. - -Shortcuts are designed to be used with `Grumlin::Repository` but still can be used separately, with `Grumlin::Sugar` -for example. - -**Defining**: -```ruby - -# Defining shortcuts -class ColorShortcut - extend Grumlin::Shortcuts - - # Custom step - shortcut :hasColor do |color| - has(:color, color) - end -end - -class ChooseShortcut - extend Grumlin::Shortcuts - - # Standard Gremlin step - shortcut :choose do |*args| - step(:choose, *args) - end -end - -class AllShortcuts - extend Grumlin::Shortcuts - - # Adding shortcuts from other modules - shortcuts_from ColorShortcut - shortcuts_from ChooseShortcut -end -``` - -**Using with Grumlin::Sugar**: -```ruby -class MyRepository - include Grumlin::Sugar - extend Grumlin::Shortcuts - - shortcuts_from AllShortcuts - - # Wrapping a traversal - def red_triangles - g(self.class.shortcuts).V.hasLabel(:triangle) - .hasColor("red") - .toList - end - - # Wrapping _ - def something_else - g(self.class.shortcuts).V.hasColor("red") - .repeat(__(self.class.shortcuts)) - .out(:has) - .hasColor("blue") - .toList - end -end -``` - -##### Overriding standard steps and shortcuts - -Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one -is still able to override standard steps if they know what they are doing: - -```ruby -shortcut :addV, override: true do |label| - super(label).property(:default, :value) -end -``` - -This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices -created by the repository that uses this shortcut. - -Shortcuts also can be overridden, but super() is not available. - #### Grumlin::Repository -`Grumlin::Repository` combines functionality of `Grumlin::Sugar` and `Grumlin::Shortcuts` as well as adds a few useful -shortcuts to make gremlin code more rubyish. Can be used as a drop in replacement for `Grumlin::Sugar`. Remember that -`Grumlin::Sugar` needs to be included, but `Grumlin::Repository` - extended. **Classes extending `Grumlin::Repository` -or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts +`Grumlin::Repository` - is a starting point for all traversals. It provides easy access to `g`, `__` and usual gremlin +expressions for you class. It has support for defining your own shortcuts and is even shipped with a couple of useful +shortcuts to make gremlin code more rubyish. **Classes extending `Grumlin::Repository` +or `Grumlin::Shortcuts` can be inherited**, successors don't need to extend them again and have access to shortcuts defined in the ancestor. **Definition** ```ruby class MyRepository extend Grumlin::Repository - - # Repository supports all Grumlin::Shortcut and Grumlin::Sugar features. + # read_only! - forbids mutating queries for this repository. May be useful for separation reads and writes + # It can add shortcuts from another repository or a shortcuts module shortcuts_from ChooseShortcut shortcut :red_triangles do |color| # hasAll unwraps a hash of properties into a chain of `has` steps: @@ -250,17 +145,17 @@ - `drop_vertex(id, start: g)` - `drop_edge(id = nil, from: nil, to: nil, label: nil, start: g)` - `drop_in_batches(traversal, batch_size: 10_000)` and a few methods that emulate upserts: -- `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)` +- `upsert_vertex(label, id, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)` - `upsert_edge(label, from:, to:, create_properties: {}, update_properties: {}, on_failure: :retry, start: g, **params)` - `upsert_edges(edges, batch_size: 100, on_failure: :retry, start: g, **params)` - `upsert_vertices(edges, batch_size: 100, on_failure: :retry, start: g, **params)` All of them support 3 different modes for error handling: `:retry`, `:ignore` and `:raise`. Retry mode is implemented -with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts +with [retryable](https://github.com/nfedyashev/retryable). **params will be merged to the default config for upserts and passed to `Retryable.retryable`. In case if you want to modify retryable behaviour you are to do so. If you want to use these methods inside a transaction simply pass your `gtx` as `start` parameter: ```ruby g.tx do |gtx| @@ -268,11 +163,11 @@ end ``` If you don't want to define you own repository, simply use -`Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`. +`Grumlin::Repository.new` returns an instance of an anonymous class extending `Grumlin::Repository`. **Usage** To execute the query defined in a query block one simply needs to call a method with the same name: @@ -293,10 +188,66 @@ `query` also provides a helper for profiling requests: `MyRepository.new.triangles_with_color(:red, query_params: { profile: true })` method will return profiling data of the results. +#### Shortcuts + +**Shortcuts** is a way to share and organize gremlin code. They let developers define their own steps consisting of +sequences of standard gremlin steps, other shortcuts and even add new initially unsupported by Grumlin steps. +Remember ActiveRecord scopes? Shortcuts are very similar. + +**Important**: if a shortcut's name matches a name of a method defined on the wrapped object, this shortcut will be +be ignored because methods have higher priority. + +**Defining**: +```ruby + +# Defining shortcuts +class ColorShortcut + extend Grumlin::Shortcuts + + # Custom step + shortcut :hasColor do |color| + has(:color, color) + end +end + +class ChooseShortcut + extend Grumlin::Shortcuts + + # Standard Gremlin step + shortcut :choose do |*args| + step(:choose, *args) + end +end + +class AllShortcuts + extend Grumlin::Shortcuts + + # Adding shortcuts from other modules + shortcuts_from ColorShortcut + shortcuts_from ChooseShortcut +end +``` + +##### Overriding standard steps and shortcuts + +Sometimes it may be useful to override standard steps. Grumlin does not allow it by default, but one +is still able to override standard steps if they know what they are doing: + +```ruby +shortcut :addV, override: true do |label| + super(label).property(:default, :value) +end +``` + +This will create a new shortcut that overrides the standard step `addV` and adds default properties to all vertices +created by the repository that uses this shortcut. + +Shortcuts also can be overridden, but super() is not available. + ##### Middlewares Middlewares can be used to perform certain actions before and after every query made by `Grumlin`. It can be useful for measuring query execution time or performing some modification or validation to the query before it reaches the server or modify the response before client gets it. @@ -321,46 +272,48 @@ end # commits automatically ``` #### IRB -An example of how to start an IRB session with support for executing gremlin queries: +Please check out [bin/console](bin/console) for inspiration. A similar trick may be applied to PRY. -```ruby -Async do - include Grumlin::Sugar - - IRB.start -ensure - Grumlin.close -end -``` - -Please check out [bin/console](bin/console) for full source. A similar trick may be applied to PRY. - #### Rails console In order to make it possible to execute gremlin queries from the rails console you need to define -a custom console class. It should look somehow like +a custom console class. It should look somewhat like ```ruby -class MyRailsConsole - def self.start +class Async::RailsConsole + extend Grumlin::Repository + + def start + self.class.shortcuts_from Shortcuts::Content + IRB::WorkSpace.prepend(Rails::Console::BacktraceCleaner) IRB::ExtendCommandBundle.include(Rails::ConsoleMethods) - Async do - include Grumlin::Sugar + IRB.setup(binding.source_location[0], argv: []) + workspace = IRB::WorkSpace.new(binding) - IRB.setup(binding.source_location[0], argv: []) - workspace = IRB::WorkSpace.new(binding) - - IRB::Irb.new(workspace).run(IRB.conf) - ensure - Grumlin.close + begin + Async do + IRB::Irb.new(workspace).run(IRB.conf) + ensure + Grumlin.close + end + rescue StandardError, Interrupt, Async::Stop, IRB::Abort + retry end end + + def inspect + 'main' + end + + def to_s + inspect + end end ``` Then you need to reference it in your application.rb: ```ruby @@ -379,16 +332,16 @@ ```ruby require 'async/rspec' require require "grumlin/test/rspec" ... config.include_context(Async::RSpec::Reactor) # Runs async reactor -config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects sugar and makes sure client is closed after every test +config.include_context(Grumlin::Test::RSpec::GremlinContext) # Injects `g`, `__` and expressions, makes sure client is closed after every test config.include_context(Grumlin::Test::RSpec::DBCleanerContext) # Cleans the database before every test ... ``` -It is highly recommended to use `Grumlin::Sugar` or `Grumlin::Repository` and not trying to use lower level APIs -as they are subject to change. +It is highly recommended to use `Grumlin::Repository` and not trying to use lower level APIs as they are subject to +change. ## Development Before running tests make sure you have gremlin-server running on your computer. The simplest way to run it is using [docker-compose](https://docs.docker.com/compose/) and provided `docker-compose.yml` and `gremlin_server/Dockerfile`: