Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tag: v0.2.0
Fetching contributors…

Cannot retrieve contributors at this time

182 lines (119 sloc) 5.53 kB

Generic Object Mapper

The Generic Object Mapper maps ruby objects to different storage engines and vice versa. The interface is designed to be small and try to avoid any unnecessary dependencies between GOM and your code. On the other side, the storage engine is plugged-in via an adapter interface. Currently, the following adapters are provided.

Configuration

At the beginning of your program the configuration should be read with the following command.

GOM::Storage::Configuration.read filename

The configuration file should be written in the YML format and look like…

storage_name:
  adapter: filesystem
  directory: /var/project-name/data

Look at the adapter pages to see the adapter-specific configuration values.

How to use

Storing an object

To store an object just pass it to GOM::Storage.store.

class Book

  attr_accessor :author_name
  attr_accessor :pages

end

book = Book.new
book.author_name = "Mr. Storyteller"
book.pages = 1253

GOM::Storage.store book, :storage_name

The storage name doesn't have to be specified. If it's missing, the object's previously use storage or the default storage is used.

There is no base class needed for your model class. GOM inspects your object, reads all the instance variables and passes the values to specified store adapter. The first time an object is stored, an id is generated and assigned to the object. This id an be determined by calling GOM::Object.id.

book_id = GOM::Object.id book
# book_id => "storage_name:1234..."

Fetching an object

Once an object is stored, it can be easily brought back to life by using it's id to fetch it from the storage.

book = GOM::Storage.fetch book_id

The storage name is encoded (prefixed) in the id and don't have to be specified. The classname of the object was also saved during the storage and the fetch instantiate a new object using the constructor. If the constructor requires arguments, nil will be passed for each of them. The internal state (the instance variables) will be overwritten anyway.

Removing an object

To remove an object from the storage, simply pass it to GOM::Storage.remove.

GOM::Storage.remove book

It's also possible to use just the id to remove the assigned object.

GOM::Storage.remove book_id

Relations

GOM does make a distinction between object properties and object relations. The properties are more atomic values that can be stored in a key/value-way and relations are links to more complex objects. Since in Ruby everything is an object, it's necessary to mark the relations. This is done by the following way.

class Book

  attr_accessor :author

end

class Author

  attr_accessor :name

end

author = Author.new
author.name = "Mr. Storyteller"

book = Book.new
book.author = GOM::Object.reference author

The GOM::Object.reference call creates a proxy to the referenced object, that passes every call to it. For example, the call

book.author.name

will return the instance variable @name (“Mr. Storyteller”) from the author object.

Views

Views are a kind of prepared queries to the data store. They are initialized during the setup and provide collections of results at runtime. There are several kinds of views.

Class views

There views simply provides a collection of all object of a specified class. They are defined at the storage configuration.

storage_name:
  adapter: filesystem
  directory: /var/project-name/data
  views:
    users:
      type: class
      class: User

The example defines a class view for all objects of the class User. The result can be fetched via…

users = GOM::Storage.collection :storage_name, :users

Collections can be handled like (read-only) ruby-arrays and the data will be fetched by the first read access to that array.

Map/Reduce views

These views are also defined in the storage configuration.

storage_name:
  adapter: couchdb
  views:
    active_user_count:
      type: map_reduce
      map:
        function(document) {
          if (document['model_class'] == 'User' && document['active']) {
            emit(document['_id'], 1);
          }
        }
      reduce:
        function(keys, values, rereduce) {
          return sum(values);
        }

The example defined a map/reduce view that results in a single row with the count of all active users. This row can be fetched by…

rows = GOM::Storage.collection :storage_name, :active_user_count
rows.first.value # => 123

If no reduce method is given, GOM will try to map the fetched data back to ruby-objects. The definition would be…

storage_name:
  adapter: couchdb
  views:
    active_users:
      type: map_reduce
      map:
        function(document) {
          if (document['model_class'] == 'User') {
            emit(document['_id'], null);
          }
        }

…and the fetch is done by…

active_users = GOM::Storage.collection :storage_name, :active_users

Development

Development has been done test-driven and the code follows at most the Clean Code paradigms. Code smells has been removed by using the reek code smell detector.

This project is still experimental and under development. Any bug report and contribution is welcome!

Jump to Line
Something went wrong with that request. Please try again.