Aqua: A Ruby Object Database … just add water (and CouchDB).
Even with ORMs like ActiveRecord, DataMapper which ease the pain of relational data storage, considerable developer effort goes into wrangling Ruby objects into their databases. Document-oriented databases have made it possible to store nested data structures that easily map to Ruby objects. Aqua (github.com/baccigalupi/aqua) is a new Ruby library that aims to painlessly persists objects, allowing developers to focus more on object oriented code and less on storage.
Currently Aqua is in pre-alpha testing, with the following big things left to implement:
-
A data query syntax and implementation (yeah, ouch!)
-
Class and code storage to allow the sharing and persistence of classes with their data
-
Other storage systems, most notably a filestore, so that users can try Aqua out without having to install CouchDb
-
Data storage amenity add-ons including: validation, callbacks, AR-styled syntax, and properties that automate some of the object typing, validation, and searchability option.
Aqua aims to be lean and modular, in addition to transparent. Currently it weighs in at < 1200 lines of code with half of that for the CouchDB storage engine.
Aqua persists a Ruby instance’s state through its instance variables, and in the case of primitives like arrays and hashes, through their core data. The first step towards working in Aqua is shedding the limitations of ORMs and other storage classes, and get back to pure Ruby. Once you have an Ruby class, the simple declaration aquatic
in the class will allow you to #commit and #reload the object.
Currently, Aqua uses CouchDB for its storage. Make sure you have CouchDB installed and running before you start storing objects. If your CouchDB installation is running at a non-standard url, visit the documentation to learn how to configure Aqua for your setup.
require 'rubygems' require 'aqua' class User aquatic # adds persistence methods to your object attr_accessor :name, # An array of strings or a hash of strings :created_at, # Time :dob, # Date :username, # simple string :name, # Array, Hash, Name Object? :password, # hidden value :credentials # hash with salt and encrypted password, or ... transient_attr :password # Aqua can hide certain instance variables that you would prefer not save # possible way to initialize your data ... def initialize( hash={} ) hash.each do |key, value| send( "#{key}=", value ) end self.created_at = Time.now end # lots more user code here as you see fit ... end user = User.new( :username => 'kane', :name =>{:first => 'Kane', :last => 'Baccigalupi'}, :dob => Date.parse( '12/23/1969' ), :password => 'ubber_secret!' ) user.commit! # ! makes it raise an exception on failure puts user.inspect # #<User:0x103e818 @dob=#<Date: 4881157/2,0,2299161>, @name={:first=>"Kane", :last=>"Baccigalupi"}, @__pack=nil, @created_at=Fri Aug 21 12:03:45 -0700 2009, @_store=nil, @password="ubber_secret!", @username="kane", @_rev="1-1789597473", @id="8e770a31107741f4bdcd325de30e1d67"> user.name = ['Kane', 'Baccigalupi'] user.commit # will return false on failure, otherwise returns its saved self puts user.inspect # #<User:0x103e818 @dob=#<Date: 4881157/2,0,2299161>, @name=["Kane", "Baccigalupi"], @__pack=nil, @created_at=Fri Aug 21 12:03:45 -0700 2009, @_store=nil, @password="ubber_secret!", @username="kane", @_rev="2-2449437616", @id="8e770a31107741f4bdcd325de30e1d67"> user.reload # retrieves the latest saved version of the object u = User.load( user.id ) # returns your persisted user object, like you just added water! puts u.inspect # #<User:0x1a16480 @name=["Kane", "Baccigalupi"], @created_at=Fri Aug 21 12:07:39 -0700 2009, @_store=nil, @username="kane", @dob=#<Date: 4881157/2,0,2299161>, @id="c664770982b92e9fa802e0ed664a9846"> # woot!
Aqua is so young that it hasn’t made it over to the established land of rubyforge. So for now you can install the gem by including github as a source, and then do a sudo gem install
gem sources -a http://gems.github.com sudo gem install 'baccigalupi-aqua'
Also, beware that Aqua has an unstated dependency: httpclient. The CouchDB engine was built with flexibility and speed in mind. The http_client gem seems like the best thing since sliced bread now, but may become outdated or slow comparatively. Developers are encouraged to build adapters to their preferred http clients. To do this please fork the project and request a pull once you have your adapter built and tested.
Meanwhile, you will want to make sure that http_client is available to Aqua.
sudo gem install http-client
Twitter: twitter.com/rubyaqua
Rdocs: ruby-aqua.org
Pivotal Tracker: www.pivotaltracker.com/projects/26677
Bug fixes and features are welcome.
-
Fork the project.
-
Make your feature addition or bug fix.
-
Add tests for it. This is important so I don’t break it in a future version unintentionally.
-
Commit, do not mess with rakefile, version, or history.(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-
Send me a pull request. Bonus points for topic branches.
Copyright © 2009 Kane Baccigalupi. See LICENSE for details. Some parts of the CouchDB storage engine were derived from CouchRest. Their LICENSE is also included and will apply.