eb5335542e3419c6d308a3ebb6f61fab4e1ed0d9
[onis.git] / lib / Onis / Data / Persistent.pm
1 package Onis::Data::Persistent;
2
3 use strict;
4 use warnings;
5
6 use Carp qw(confess);
7
8 =head1 NAME
9
10 Onis::Data::Persistent - Interface for storage backends
11
12 =head1 DESCRIPTION
13
14 Abstraction layer for modules that act as a backend and are able to store
15 internal data for longer than one run..
16
17 =cut
18
19 use Onis::Config qw#get_config get_checksum#;
20
21 our $StoreModule = 'None';
22
23 =head1 CONFIGURATION OPTIONS
24
25 Since this is a B<interface> the options are very few. One, to be specific. See
26 your favorite backend's documentation on it's options..
27
28 =over 4
29
30 =item B<storage_module>
31
32 Selects the storage module to use. Defaults to I<None> which is a dummy module
33 that doesn't do anything with the data.. (Other than storing it internally..)
34 Currently implemented options are:
35
36     None       (todo)
37     Storable   (maybe)
38     GDBM/SDBM  (todo)
39     MySQL      (todo)
40     PostgreSQL (maybe)
41
42 =back
43
44 =cut
45
46 if (get_config ('storage_module'))
47 {
48         $StoreModule = ucfirst (lc (get_config ('storage_module')));
49 }
50
51 {
52         my $mod_name = "Onis::Data::Persistent::$StoreModule";
53
54         eval qq(use $mod_name;);
55
56         if ($@)
57         {
58                 print STDERR $/, __FILE__, ": Could not load storage module ``$StoreModule''. Are you sure it exists?";
59                 exit (1);
60         }
61
62         unshift (@Onis::Data::Persistent::ISA, $mod_name);
63 }
64
65 return (0);
66
67 =head1 INTERFACE
68
69 The child-modules have to provide the following interface:
70
71 =over 4
72
73 =item B<Onis::Data::Persistent-E<gt>new> (I<$name>, I<$key_name>, I<@field_names>)
74
75 This is the constructor for the objects that will hold the data. Some modules
76 may need a name for each field, and this is where plugins have to give the name
77 of each field. This is particularly important for backends using relational
78 databeses. I<$name> is merely a name for that variable or, in the database
79 world - a table. The name must be unique for each calling method's namespace.
80
81 Since this is a constructor it returns an object. The object "knows" the folling methods:
82
83 =item B<$data-E<gt>get> (I<$key>) 
84
85 Returns the data associated with the given I<$key> pair or an empty list if no
86 data has been stored under this tupel before..
87
88 =item B<$data-E<gt>put> (I<$key>, I<@fields>)
89
90 Stores the given values in the data structure. How this is done is described
91 below in L<another paragraph>. Doesn't return anything. The number of entries
92 in I<@fields> has to match the number of entries in I<@field_names> when
93 creating the object using B<new>.
94
95 =item B<$data-E<gt>keys> ([I<$field>, ...])
96
97 Returns a list of all the keys defined for this object. If one field is given
98 the list will be sorted by that field's values, if more fields are given the
99 list is sorted with the first field taking precedence over the others. If no
100 field is supplied the order is undefined.
101
102 =back
103
104 =head1 INTERNALS
105
106 The B<put> and B<get> methods can be found in the
107 B<Onis::Data::Persistent::None> module. Other modules are encouraged to inherit
108 from that module, but don't need to. The data is stored as follows: The object
109 that's returned to the caller is actually a hash with this layout:
110
111     %object =
112     (
113         data =>
114         {
115             key0 => [ qw(field0 field1 field2 ...) ],
116             key1 => [ qw(field0 field1 field2 ...) ],
117             key2 => [ qw(field0 field1 field2 ...) ],
118             ...
119         }
120     );
121
122 The actual data is not directly stored under I<%object> so database backends
123 can store metadata there (table name, credentials, whatever..).
124
125 =head1 FURTHER CONSIDERATIONS
126
127 Backend modules will probably read the entire data at startup and save
128 everything at the end. Another strategy might be reading (at least trying to)
129 an entry when it's first tried to B<get>..
130
131 =head1 AUTHOR
132
133 Florian octo Forster, L<octo@verplant.org>. Any comments welcome as long as I
134 haven't started implementing this ;)
135
136 =cut