In-memory Relational Data Storage

"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag news:...

"Curt Sampson" <cjs@cynic.net> 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:

<snip/>

Wait, this is better:

require 'set'

class Foo; attr_accessor :bar end

class Index
  def initialize(cl, field)
    name = field.to_sym
    get_indexes(cl)[name] = self

    @h = Hash.new {|h,k| h[k]=Set.new}

    cl.class_eval "def #{field}=(x) idx = self.class::INDEXES[:#{name}];
idx.remove(self, @#{field}); @#{field}=x; idx.add(self, @#{field}) end"
  end

  def get_indexes(cl)
    if cl.const_defined? "INDEXES"
      cl.const_get "INDEXES"
    else
      h = {}
      cl.const_set "INDEXES", h
      h
    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
Foo::INDEXES[:bar].get_all(100)

Regards

    robert