1DBIx::SearchBuilder::ReUcsoerrd(C3o)ntributed Perl DocumDeBnItxa:t:iSoenarchBuilder::Record(3)
2
3
4
6 DBIx::SearchBuilder::Record - Superclass for records loaded by
7 SearchBuilder
8
10 package MyRecord;
11 use base qw/DBIx::SearchBuilder::Record/;
12
13 sub _Init {
14 my $self = shift;
15 my $DBIxHandle = shift; # A DBIx::SearchBuilder::Handle::foo object for your database
16
17 $self->_Handle($DBIxHandle);
18 $self->Table("Users");
19 }
20
21 # Tell Record what the primary keys are
22 sub _PrimaryKeys {
23 return ['id'];
24 }
25
26 # Preferred and most efficient way to specify fields attributes in a derived
27 # class, used by the autoloader to construct Attrib and SetAttrib methods.
28
29 # read: calling $Object->Foo will return the value of this record's Foo column
30 # write: calling $Object->SetFoo with a single value will set Foo's value in
31 # both the loaded object and the database
32 sub _ClassAccessible {
33 {
34 Tofu => { 'read' => 1, 'write' => 1 },
35 Maz => { 'auto' => 1, },
36 Roo => { 'read' => 1, 'auto' => 1, 'public' => 1, },
37 };
38 }
39
40 # A subroutine to check a user's password without returning the current value
41 # For security purposes, we didn't expose the Password method above
42 sub IsPassword {
43 my $self = shift;
44 my $try = shift;
45
46 # note two __s in __Value. Subclasses may muck with _Value, but
47 # they should never touch __Value
48
49 if ( $try eq $self->__Value('Password') ) {
50 return (1);
51 }
52 else {
53 return (undef);
54 }
55 }
56
57 # Override DBIx::SearchBuilder::Create to do some checking on create
58 sub Create {
59 my $self = shift;
60 my %fields = (
61 UserId => undef,
62 Password => 'default', #Set a default password
63 @_
64 );
65
66 # Make sure a userid is specified
67 unless ( $fields{'UserId'} ) {
68 die "No userid specified.";
69 }
70
71 # Get DBIx::SearchBuilder::Record->Create to do the real work
72 return (
73 $self->SUPER::Create(
74 UserId => $fields{'UserId'},
75 Password => $fields{'Password'},
76 Created => time
77 )
78 );
79 }
80
82 DBIx::SearchBuilder::Record is designed to work with
83 DBIx::SearchBuilder.
84
85 What is it trying to do.
86 DBIx::SearchBuilder::Record abstracts the agony of writing the common
87 and generally simple SQL statements needed to serialize and De-
88 serialize an object to the database. In a traditional system, you
89 would define various methods on your object 'create', 'find', 'modify',
90 and 'delete' being the most common. In each method you would have a
91 SQL statement like:
92
93 select * from table where value='blah';
94
95 If you wanted to control what data a user could modify, you would have
96 to do some special magic to make accessors do the right thing. Etc.
97 The problem with this approach is that in a majority of the cases, the
98 SQL is incredibly simple and the code from one method/object to the
99 next was basically the same.
100
101 <trumpets>
102
103 Enter, DBIx::SearchBuilder::Record.
104
105 With Record, you can in the simple case, remove all of that code and
106 replace it by defining two methods and inheriting some code. It's
107 pretty simple, and incredibly powerful. For more complex cases, you
108 can do more complicated things by overriding certain methods. Let's
109 stick with the simple case for now.
110
111 The two methods in question are "_Init" and "_ClassAccessible". All
112 they really do are define some values and send you on your way. As you
113 might have guessed the '_' means that these are private methods. They
114 will get called by your record object's constructor.
115
116 '_Init'
117 Defines what table we are talking about, and set a variable to
118 store the database handle.
119
120 '_ClassAccessible
121 Defines what operations may be performed on various data selected
122 from the database. For example you can define fields to be
123 mutable, or immutable, there are a few other options but I don't
124 understand what they do at this time.
125
126 And really, that's it. So let's have some sample code.
127
128 An Annotated Example
129 The example code below makes the following assumptions:
130
131 • The database is 'postgres',
132
133 • The host is 'reason',
134
135 • The login name is 'mhat',
136
137 • The database is called 'example',
138
139 • The table is called 'simple',
140
141 • The table looks like so:
142
143 id integer not NULL, primary_key(id),
144 foo varchar(10),
145 bar varchar(10)
146
147 First, let's define our record class in a new module named "Simple.pm".
148
149 000: package Simple;
150 001: use DBIx::SearchBuilder::Record;
151 002: @ISA = (DBIx::SearchBuilder::Record);
152
153 This should be pretty obvious, name the package, import ::Record and
154 then define ourself as a subclass of ::Record.
155
156 003:
157 004: sub _Init {
158 005: my $this = shift;
159 006: my $handle = shift;
160 007:
161 008: $this->_Handle($handle);
162 009: $this->Table("Simple");
163 010:
164 011: return ($this);
165 012: }
166
167 Here we set our handle and table name. While it's not obvious so far,
168 we'll see later that $handle (line: 006) gets passed via
169 "::Record::new" when a new instance is created. That's actually an
170 important concept: the DB handle is not bound to a single object but
171 rather, it is shared across objects.
172
173 013:
174 014: sub _ClassAccessible {
175 015: {
176 016: Foo => { 'read' => 1 },
177 017: Bar => { 'read' => 1, 'write' => 1 },
178 018: Id => { 'read' => 1 }
179 019: };
180 020: }
181
182 What's happening might be obvious, but just in case this method is
183 going to return a reference to a hash. That hash is where our columns
184 are defined, as well as what type of operations are acceptable.
185
186 021:
187 022: 1;
188
189 Like all perl modules, this needs to end with a true value.
190
191 Now, on to the code that will actually *do* something with this object.
192 This code would be placed in your Perl script.
193
194 000: use DBIx::SearchBuilder::Handle;
195 001: use Simple;
196
197 Use two packages, the first is where I get the DB handle from, the
198 latter is the object I just created.
199
200 002:
201 003: my $handle = DBIx::SearchBuilder::Handle->new();
202 004: $handle->Connect( 'Driver' => 'Pg',
203 005: 'Database' => 'test',
204 006: 'Host' => 'reason',
205 007: 'User' => 'mhat',
206 008: 'Password' => '');
207
208 Creates a new DBIx::SearchBuilder::Handle, and then connects to the
209 database using that handle. Pretty straight forward, the password ''
210 is what I use when there is no password. I could probably leave it
211 blank, but I find it to be more clear to define it.
212
213 009:
214 010: my $s = Simple->new($handle);
215 011:
216 012: $s->LoadById(1);
217
218 LoadById is one of four 'LoadBy' methods, as the name suggests it
219 searches for an row in the database that has id='0'. ::SearchBuilder
220 has, what I think is a bug, in that it current requires there to be an
221 id field. More reasonably it also assumes that the id field is unique.
222 LoadById($id) will do undefined things if there is >1 row with the same
223 id.
224
225 In addition to LoadById, we also have:
226
227 LoadByCol
228 Takes two arguments, a column name and a value. Again, it will do
229 undefined things if you use non-unique things.
230
231 LoadByCols
232 Takes a hash of columns=>values and returns the *first* to match.
233 First is probably lossy across databases vendors.
234
235 LoadFromHash
236 Populates this record with data from a DBIx::SearchBuilder. I'm
237 currently assuming that DBIx::SearchBuilder is what we use in cases
238 where we expect > 1 record. More on this later.
239
240 Now that we have a populated object, we should do something with it!
241 ::Record automagically generates accessos and mutators for us, so all
242 we need to do is call the methods. Accessors are named <Field>(), and
243 Mutators are named Set<Field>($). On to the example, just appending
244 this to the code from the last example.
245
246 013:
247 014: print "ID : ", $s->Id(), "\n";
248 015: print "Foo : ", $s->Foo(), "\n";
249 016: print "Bar : ", $s->Bar(), "\n";
250
251 That's all you have to to get the data. Now to change the data!
252
253 017:
254 018: $s->SetBar('NewBar');
255
256 Pretty simple! That's really all there is to it. Set<Field>($) returns
257 a boolean and a string describing the problem. Let's look at an
258 example of what will happen if we try to set a 'Id' which we previously
259 defined as read only.
260
261 019: my ($res, $str) = $s->SetId('2');
262 020: if (! $res) {
263 021: ## Print the error!
264 022: print "$str\n";
265 023: }
266
267 The output will be:
268
269 >> Immutable field
270
271 Currently Set<Field> updates the data in the database as soon as you
272 call it. In the future I hope to extend ::Record to better support
273 transactional operations, such that updates will only happen when "you"
274 say so.
275
276 Finally, adding a removing records from the database. ::Record
277 provides a Create method which simply takes a hash of key=>value pairs.
278 The keys exactly map to database fields.
279
280 023: ## Get a new record object.
281 024: $s1 = Simple->new($handle);
282 025: $s1->Create('Id' => 4,
283 026: 'Foo' => 'Foooooo',
284 027: 'Bar' => 'Barrrrr');
285
286 Poof! A new row in the database has been created! Now let's delete the
287 object!
288
289 028:
290 029: $s1 = undef;
291 030: $s1 = Simple->new($handle);
292 031: $s1->LoadById(4);
293 032: $s1->Delete();
294
295 And it's gone.
296
297 For simple use, that's more or less all there is to it. In the future,
298 we hope to expand this how-to to discuss using container classes,
299 overloading, etc.
300
302 Each method has a lower case alias; '_' is used to separate words. For
303 example, the method "_PrimaryKeys" has the alias "_primary_keys".
304
306 new
307 Instantiate a new record object.
308
309 id
310 Returns this row's primary key.
311
312 primary_keys
313 PrimaryKeys
314 Return a hash of the values of our primary keys for this function.
315
316 _Accessible KEY MODE
317 Private method.
318
319 Returns undef unless "KEY" is accessible in "MODE" otherwise returns
320 "MODE" value
321
322 _PrimaryKeys
323 Return our primary keys. (Subclasses should override this, but our
324 default is that we have one primary key, named 'id'.)
325
326 _ClassAccessible
327 An older way to specify fields attributes in a derived class. (The
328 current preferred method is by overriding "Schema"; if you do this and
329 don't override "_ClassAccessible", the module will generate an
330 appropriate "_ClassAccessible" based on your "Schema".)
331
332 Here's an example declaration:
333
334 sub _ClassAccessible {
335 {
336 Tofu => { 'read'=>1, 'write'=>1 },
337 Maz => { 'auto'=>1, },
338 Roo => { 'read'=>1, 'auto'=>1, 'public'=>1, },
339 };
340 }
341
342 ReadableAttributes
343 Returns an array of the attributes of this class defined as "read" => 1
344 in this class' _ClassAccessible datastructure
345
346 WritableAttributes
347 Returns an array of the attributes of this class defined as "write" =>
348 1 in this class' _ClassAccessible datastructure
349
350 __Value
351 Takes a field name and returns that field's value. Subclasses should
352 never override __Value.
353
354 _Value
355 _Value takes a single column name and returns that column's value for
356 this row. Subclasses can override _Value to insert custom access
357 control.
358
359 _Set
360 _Set takes a single column name and a single unquoted value. It
361 updates both the in-memory value of this column and the in-database
362 copy. Subclasses can override _Set to insert custom access control.
363
364 _Canonicalize PARAMHASH
365 This routine massages an input value (VALUE) for FIELD into something
366 that's going to be acceptable.
367
368 Takes
369
370 FIELD
371 VALUE
372 FUNCTION
373
374 Takes:
375
376 FIELD
377 VALUE
378 FUNCTION
379
380 Returns a replacement VALUE.
381
382 _Validate FIELD VALUE
383 Validate that VALUE will be an acceptable value for FIELD.
384
385 Currently, this routine does nothing whatsoever.
386
387 If it succeeds (which is always the case right now), returns true.
388 Otherwise returns false.
389
390 TruncateValue KEY VALUE
391 Truncate a value that's about to be set so that it will fit inside the
392 database' s idea of how big the column is.
393
394 (Actually, it looks at SearchBuilder's concept of the database, not
395 directly into the db).
396
397 _Object
398 _Object takes a single column name and an array reference. It creates
399 new object instance of class specified in _ClassAccessable structure
400 and calls LoadById on recently created object with the current column
401 value as argument. It uses the array reference as the object
402 constructor's arguments. Subclasses can override _Object to insert
403 custom access control or define default constructor arguments.
404
405 Note that if you are using a "Schema" with a "REFERENCES" field, this
406 is unnecessary: the method to access the column's value will
407 automatically turn it into the appropriate object.
408
409 Load
410 Takes a single argument, $id. Calls LoadById to retrieve the row whose
411 primary key is $id
412
413 LoadByCol
414 Takes two arguments, a column and a value. The column can be any table
415 column which contains unique values. Behavior when using a non-unique
416 value is undefined
417
418 LoadByCols
419 Takes a hash of columns and values. Loads the first record that matches
420 all keys.
421
422 The hash's keys are the columns to look at.
423
424 The hash's values are either: scalar values to look for OR has
425 references which contain 'operator' and 'value'
426
427 LoadById
428 Loads a record by its primary key. Your record class must define a
429 single primary key column.
430
431 LoadByPrimaryKeys
432 Like LoadById with basic support for compound primary keys.
433
434 LoadFromHash
435 Takes a hashref, such as created by DBIx::SearchBuilder and populates
436 this record's loaded values hash.
437
438 _LoadFromSQL QUERYSTRING @BIND_VALUES
439 Load a record as the result of an SQL statement
440
441 Create
442 Takes an array of key-value pairs and drops any keys that aren't known
443 as columns for this recordtype
444
445 Delete
446 Delete this record from the database. On failure return a
447 Class::ReturnValue with the error. On success, return 1;
448
449 Table
450 Returns or sets the name of the current Table
451
452 QuotedTableName
453 Returns the name of current Table, or the table provided as an
454 argument, including any quoting
455 based on yje Handle's QuoteTableNames flag and driver method.
456
457 _Handle
458 Returns or sets the current DBIx::SearchBuilder::Handle object
459
460
461
462perl v5.36.3 2023-12-04 DBIx::SearchBuilder::Record(3)