Experimental has_many support

Posted by yrashk

I am happy to announce that StrokeDB got an experimental has_many support recently.

Now you can easily collect documents that refer to your document by defining has_many for your meta:

(All examples shown are done in test/console)

 
Playlist = Meta.new do
  has_many :songs
end
    ==>Playlist
Song = Meta.new
    ==>Song
playlist = Playlist.create!(:name => "My playlist")
    ==>#<Playlist name: "My playlist", __version__: 330f...>
song = Song.create!(:name => "My song", :playlist => playlist)
    ==>#<Song name: "My song", __version__: 530f..., playlist: #<Playlist name: "My playlist", __version__: 330f...>>
playlist.songs
    ==>[#<Song name: "My song", __version__: 530f..., playlist: #<Playlist name: "My playlist", __version__: 330f...>>]
 

So, here we define has_many :songs, which inflates :songs to Song meta and uses Song’s :playlist slot as a reference to Playlist. Like in ActiveRecord, this definition uses configuration by convention. And again, like in ActiveRecord, you can tweak it:

 
Playlist = Meta.new do
  has_many :all_songs, :through => :songs, :foreign_reference => :belongs_to_playlist
end
    ==>Playlist
Song = Meta.new
    ==>Song
playlist = Playlist.create!(:name => "My playlist")
    ==>#<Playlist name: "My playlist", __version__: 3245...>
song = Song.create!(:name => "My song", :belongs_to_playlist => playlist)
    ==>#<Song name: "My song", __version__: 5245..., belongs_to_playlist: #<Playlist name: "My playlist", __version__: 3245...>>
playlist.all_songs
    ==>[#<Song name: "My song", __version__: 5245..., belongs_to_playlist: #<Playlist name: "My playlist", __version__: 3245...>>]
 

Here we use :through option which tells StrokeDB to use Song meta to find documents, and :foreign_reference specifies Song’s slot name for the reference to Playlist. You can also add some conditions to has_many:


Playlist = Meta.new do
  has_many :rock_songs, :through => :songs, :foreign_reference => :belongs_to_playlist, :conditions => {:genre => "Rock"}
end
    ==>Playlist
Song = Meta.new
    ==>Song
playlist = Playlist.create!(:name => "My playlist")
    ==>#<Playlist name: "My playlist", __version__: 3cd6...>
rock_song = Song.create!(:name => "My song", :belongs_to_playlist => playlist, :genre => "Rock")
    ==>#<Song name: "My song", __version__: 5cd6..., belongs_to_playlist: #<Playlist name: "My playlist", __version__: 3cd6...>, genre: "Rock">
pop_song = Song.create!(:name => "My song 2", :belongs_to_playlist => playlist, :genre => "Pop")
    ==>#<Song name: "My song 2", __version__: 6cd6..., belongs_to_playlist: #<Playlist name: "My playlist", __version__: 3cd6...>, genre: "Pop">
playlist.rock_songs
    ==>[#<Song name: "My song", __version__: 5cd6..., belongs_to_playlist: #<Playlist name: "My playlist", __version__: 3cd6...>, genre: "Rock">]

Isn’t it nice? But lets go further. What if you want to know all authors of music in your playlist? That’s quite simple!

 
Playlist = Meta.new do
  has_many :authors, :through => [:songs, :author]
end
    ==>Playlist
Song = Meta.new
    ==>Song
playlist = Playlist.create!(:name => "My playlist")
    ==>#<Playlist name: "My playlist", __version__: 3903...>
song = Song.create!(:name => "My song", :playlist => playlist, :author => "John Doe")
    ==>#<Song name: "My song", __version__: 5903..., author: "John Doe", playlist: #<Playlist name: "My playlist", __version__: 3903...>>
playlist.authors
    ==>["John Doe"]

or

 
Playlist = Meta.new do
  has_many :authors, :through => [:songs, :author]
end
    ==>Playlist
Song = Meta.new
    ==>Song
Author = Meta.new
    ==>Author
playlist = Playlist.create!(:name => "My playlist")
    ==>#<Playlist name: "My playlist", __version__: 3b19...>
author = Author.create!(:name => "John Doe")
    ==>#<Author name: "John Doe", __version__: 5b19...>
song = Song.create!(:name => "My song", :playlist => playlist, :author => author)
    ==>#<Song name: "My song", __version__: 7b19..., author: #<Author name: "John Doe", __version__: 5b19...>, playlist: #<Playlist name: "My playlist", __version__: 3b19...>>
playlist.authors
    ==>[#<Author name: "John Doe", __version__: 5b19...>]

So here in these examples has_meta fetches all Songs and gets all their :author slots.

So here it is. Current has_many implementation is quite experimental and might change later (for example, we’re still thinking about improving :conditions stuff for :through => [...] case, since :conditions are currently applying only to Songs). And most probably it has some bugs :)

Comments

Leave a response

  1. EddieMarch 01, 2008 @ 05:50 PM

    Yurii,

    Very useful post. I did not use stockDB before but I guess this is the time to give it a try.

    Great code..

    Eddie,