From: Robert Klemme Date: 2004-11-18T18:43:14+09:00 Subject: Re: In-memory Relational Data Storage "Curt Sampson" schrieb im Newsbeitrag news:Pine.NEB.4.58.0411181431440.649@angelic-vtfw.cvpn.cynic.net... > > I've been dealing with some slightly more complex groups of data lately. > Say, something like this: > > I have a dozen Libraries. Each library carries some volumes of zero > or more Journals. For example, Library L1 might have volumes 1-35 of > Journal J1, and Library L2 might have volumes 25-40 of Journal J1. Each > Volume has one or more Articles in it, and the same Article might be > found in multiple Volumes of the same or different Journals. > > So I make classes for all of these and started hooking them up together, > beginning with the obvious tree structure (Libraries reference Journals, > which reference Volumes, which reference Articles.) But then I realize > that I had some lookups I wanted to do that needed some different types > of references, for example, "name all the Journals that have published > Article A37." > > So I start adding more ways of doing efficient lookups, start to worry about > various data structures getting out of sync, get some fairly nasty code > to search down through tree structures, and start to become unhappy. > > And then it hits me. The source of all my problems is that, stuck in my > 'A has a B' reference rut, I've just constructed a hierarchial database, > which is the source of all my pain. > > Well, this is a problem we solved forty years ago when Codd came up with > the idea of relational databases. So, has anybody built some sort of > relational storage system for Ruby that will let me describe my data in > some sort of E/R-ish way and get stuff out from any direction I care to use? You probably just need bidrectional relations plus hashes as indexes. You could define some utility code that establishes a relation between two classes and a specialized indexing class that tracks attribute changes automatically. Something along this rough outline: require 'set' class Foo; attr_accessor :bar end class Index INDEXES = {} def initialize(cl, field) name = "#{cl.name}::#{field}" @cl = cl @field = field @h = Hash.new {|h,k| h[k]=Set.new} self.class::INDEXES[name] = self @cl.class_eval "def #{field}=(x) idx = Index::INDEXES['#{name}']; idx.remove(self, @#{field}); @#{field}=x; idx.add(self, @#{field}) end" end def add(obj, val) @h[val].add(obj) end def remove(obj, val) @h[val].delete(obj) end def get_all(val) @h[val] end end Index.new(Foo, :bar) f=Foo.new f.bar = 100 Index::INDEXES["Foo::bar"].get_all(100) I would not use a relational approach because you loose the expressiveness of an OO language. Kind regards robert