1Storm::Tutorial(3)    User Contributed Perl Documentation   Storm::Tutorial(3)
2
3
4

NAME

6       Storm::Tutorial - Getting started with Storm
7

DESCRIPTION

9       Storm is a Moose based library for storing and retrieving Moose based
10       objects using a DBI connection.
11

CONNECTING

13       Storm connects to databases using the uqiquitous DBI module. Database
14       handles are spawned using a Storm::Source object which holds connection
15       information. In the example below, the Storm::Source object is coerced
16       from the arguments passed to the Storm constructor.
17
18        use Storm;
19
20        $storm->new(
21           source => ['DBI:mysql:timsdev:10.0.1.11:3306', 'user', 'pass']
22        );
23

BUILDING

25       Storm is for storing Moose based objects. It is required that the
26       objects have the Storm roles and meta-roles applied.
27
28       Storm::Object is an extension of Moose which applies the appropriate
29       roles and meta-roles, as well as providing some sugar for defining
30       relationships.
31
32   Simple example
33        package Person;
34        use Storm::Object;
35        storm_table( 'Person' );
36
37        has 'id' => (
38            is => 'rw',
39            traits => [qw(PrimaryKey AutoIncrement)],
40        );
41
42        has 'name' => (
43            is => 'rw',
44        );
45
46        has 'dob' => (
47            is => 'rw',
48            column => 'birth_date',
49        );
50
51       This is a very simple example, but demonstrates a few key concepts:
52
53       •   Every class definition must have a meta-table defined. Storm uses
54           this information to determine what table to store the object to in
55           the database.
56
57       •   It is recomended that every class provide a primary key (via the
58           PrimaryKey attribute trait.) If you do not provide a primary key,
59           you will not be able to use lookup queries to restore objects, nor
60           will any other Storm enabled object be able to store references to
61           it.
62
63       •   Storm avoids requiring a separate schema by defining elements of a
64           schema in the object definition. By default, object attributes are
65           assigned a table column with the same name as the attribute.  The
66           default behavior can be changed by setting the column option.
67
68   Circular references
69        package Person;
70        use Storm::Object;
71        storm_table( 'People' );
72
73        has 'id' => (
74            is => 'rw',
75            traits => [qw(PrimaryKey AutoIncrement)],
76        );
77
78        has 'spouse' => (
79            is => 'rw',
80            isa => 'Person',
81            weak_ref => 1,
82        );
83
84       •   References to other Storm enabled classes are serialized
85           automatically using the primary key. This is accomplished by
86           setting the "isa" option to a Storm enabled class (type).
87
88       •   In a scenario such as this, where two objects will reference each
89           other in a circular structure, it is necessary to set the weak_ref
90           option to avoid memory leaks. When constructing and using objects
91           with circular references, it is necessary to manage the "scope".
92           The scope stops objects from being garbage collected to early (i.e.
93           when the only references to them are weak.)
94

RELATIONSHIPS

96       Relationships are devised in two ways. We demonstrated one manner in
97       the example above by setting an attributes "isa" option to a Storm
98       enabled class. This allows you to referance a singular object. Here we
99       will demonstrate making "one-to-many" and "many-to-many" relationships
100       using the "has_many" keyword.
101
102   One-to-many
103        package Person;
104        use Storm::Object;
105        storm_table( 'People' );
106
107        has 'id' => (
108            is => 'rw',
109            traits => [qw(PrimaryKey AutoIncrement)],
110        );
111
112        one_to_many 'pokemon' => (
113           foreign_class => 'Pokemon',
114           match_on => 'master',
115           handles => {
116               pokemon => 'iter',
117           }
118        );
119
120        package Pokemon;
121        use Storm::Object;
122        storm_->table( 'Pokemon' );
123
124        has 'id' => (
125            is => 'rw',
126            traits => [qw(PrimaryKey AutoIncrement)],
127        );
128
129        has 'master' => (
130            is => 'rw',
131            isa => 'Person',
132            weak_ref => 1,
133        );
134
135       Here, we define the components of a relationship between the Person
136       class and the Pokemon class uing the "one_to_many" keyword.
137
138       •   The "foreign_key => master" denotes that the relationship is made
139           by matching the primary key of the Person with the c<master>
140           attribute of the Pokemon.
141
142       •   Using the "handles" option, we create the "pokemon" method for
143           Person. This method returns a Person's Pokemon in the form of a
144           Storm::Query::Select::Iterator object.
145
146       •   To add another Pokemon to a Person, create a new Pokemon and set
147           the "master" attribute to a $person.
148
149   Many-to-many
150        package Person;
151        use Storm::Object;
152        storm_table( 'People' );
153
154        has 'id' => (
155            is => 'rw',
156            traits => [qw(PrimaryKey AutoIncrement)],
157        );
158
159        many_to_many 'pets' => (
160            foreign_class => 'Pets',
161            junction_table => 'PeoplesPets',
162            local_match => 'person',
163            foreign_match => 'pet',
164            handles => {
165                parents => 'iter',
166                add_pet => 'add',
167                remove_pet => 'remove',
168            }
169        )
170
171        package Pet;
172        use Storm::Object;
173        storm_table( 'Pets' );
174
175        has 'id' => (
176            is => 'rw',
177            traits => [qw(PrimaryKey AutoIncrement)],
178        );
179
180        many_to_many 'care_takers' => (
181            foreign_class => 'Pets',
182            junction_table => 'PeoplesPets',
183            local_match => 'person',
184            foreign_match => 'pets',
185            handles => {
186                care_takers => 'iter',
187                add_care_taker => 'add',
188                remove_care_taker => 'remove',
189            }
190        )
191
192       •   In a many-to-many relationship, a junction_table is required to
193           form the relationship. This is specified as an option to the
194           "many_to_many" keyword.
195
196       •   We also need to define the columns in the junction_table that will
197           be used to identify the components of the relationship. This is
198           done with local_match and foreign_match options. local_match is the
199           column in the junction table to match with the primary key of
200           defining class, while foreign_match is the the column to match with
201           the primary key of the foregin class.
202
203       •   Using the "handles" option, we create methods for retrieving a
204           Storm::Query::Select::Iterator, as well as methods for adding and
205           removing pets/caretakers. "$pet->add_care_taker( $person )" is
206           synanamous with "$person->add_pet( $pet )" and
207           "$pet->remove_care_taker( $person )" is synanamous with
208           "$person->remove_pet( $pet )".
209
210       •   As of version 0.05, Storm will automatically fill in the
211           "junction_table", "local_match", and forerign match if you do not
212           supply them.
213
214            package Person;
215            use Storm::Object;
216            storm_table( 'People' );
217
218            has 'id' => (
219                is => 'rw',
220                traits => [qw(PrimaryKey AutoIncrement)],
221            );
222
223            many_to_many 'pets' => (
224                foreign_class => 'Pets',
225                handles => {
226                    parents => 'iter',
227                    add_pet => 'add',
228                    remove_pet => 'remove',
229                }
230            )
231
232            package Pet;
233            use Storm::Object;
234            storm_table( 'Pets' );
235
236            has 'id' => (
237                is => 'rw',
238                traits => [qw(PrimaryKey AutoIncrement)],
239            );
240
241            many_to_many 'care_takers' => (
242                foreign_class => 'Pets',
243                handles => {
244                    care_takers => 'iter',
245                    add_care_taker => 'add',
246                    remove_care_taker => 'remove',
247                }
248            )
249

CRUD

251       Storm provides queries for the four basic data operations Create, Read,
252       Update, and Delete (CRUD) as well as a "select" query for searching.
253
254   Insert
255        $storm->insert( @objects );
256
257       Inserts @objects into the database. Objects may onle be inserted if
258       they do not already exist in the database. An error will be thrown if
259       you try to insert an object that already exists. An error will also be
260       thrown if the object has a primary key and it is undef (unless using
261       the AutoIncrement trait.)
262
263   Lookup
264        $storm->lookup( $class, @object_ids );
265
266       Retrieves object from the database by primary key. The $class attribute
267       is required so Storm knows where to find and how to inflate the
268       objects. If any of the object's attributes reference other Storm
269       enabled objects, they will be looked up and inflated as well. This will
270       continue until all dependent object have been retrieved and inflated.
271
272   Update
273        $storm->update( @objects );
274
275       Updates the state of the @objects in the database. If you try to call
276       "update" on an object that is not already in the database, an error
277       will be thrown. Only the @objects passed to "update" will be affected,
278       any Storm enabled objects they reference will not updated in the
279       database. You must call "update" on them yourself.
280
281   Delete
282        $storm->delete( @objects );
283
284       Deletes the @objects from the database. The local references to them
285       will still exists until you destroy them or they go out of scope.
286

SELECT

288       Searching is possible using a select query. The select query is a
289       little more complex than it's counterparts.
290
291   Iterators
292        $query = $storm->select( 'Person' );
293        $iter = $query->results;
294
295        while ( $object = $iter->next ) {
296
297           ... do stuff with $object ...
298
299        }
300
301       Calling the "results" method on a select query returns a
302       Storm::Query::Select::Iterator for iterating over the result set.
303
304   Where
305        $query = $storm->select( 'Person' );
306        $query->where( '.last_name', '=', 'Simpson' );
307        $query->where( '.age', '>', 10 );
308        $iter = $query->results;
309
310       Use Storm::Query::Select's "where" method to select specific objects.
311
312       •   The following comparisons are supported: =, <>, <, <=, =>, IN, NOT
313           IN, BETWEEN, LIKE, NOT LIKE
314
315       •   It is possible to use attributes in a comparison with the
316           ".attribute" notation (to distinguish them from regular strings.)
317
318            $query->where( '.spouse.first_name', '=', 'Marge' );
319
320           If the attribute is also a Storm enabled object you can can
321           reference it's attributes in the comparison as well.
322
323   Placeholders
324        $query->where( '.age', '>', '?' );
325        $iter = $query->results( 10 );
326
327       You can use a "?" as placeholder. Supply the arguments to replace the
328       placeholders when calling the "results" method.
329
330   Order-by
331        $query->order_by( '.lastname', '.age DESC' );
332
333       Use the "order_by" method to sort the results.
334

SCOPE

336       The scope ensures that objects aren't garbage collected to early. As
337       objects are inflated from the database, the are pushed onto the live
338       object scope, increasing their reference count.
339
340       Let's define out person class to use as an example.
341
342        package Person;
343        use Storm::Object;
344
345        has 'id' => (
346            is => 'rw',
347            traits => [qw(PrimaryKey AutoIncrement)],
348        );
349
350        has 'name' => (
351            is => 'rw',
352        );
353
354        has 'spouse' => (
355            is => 'rw',
356            isa => 'Person',
357            weak_ref => 1,
358        );
359
360       Now, insert some objects into the database.
361
362            $storm->insert(
363               Person->new( name = 'Homer' ),
364               Person->new( name = 'Marge' )
365            );
366
367       And then we can link them together:
368
369        {
370            my $scope = $storm->new_scope;
371
372            my ( $homer, $marge ) = $storm->lookup( $homer_id, $marge_id );
373            $homer->spouse( $marge );
374            $marge->spouse( $homer );
375            $storm->update( $homer, $marge );
376        }
377
378       Now we can we can load the objects from the database like this:
379
380        {
381            my $scope = $storm->new_scope;
382
383            my $homer = $storm->lookup( $homer_id );
384
385            print $homer->spouse->name; # Marge
386        }
387
388        {
389            my $scope = $storm->new_scope;
390
391            my $marge = $storm->lookup( $marge_id );
392
393            print $marge->spouse->name; # Homer Simpson
394
395            refaddr( $marge ) == refaddr( $marge->spouse->spouse ); # true
396        }
397
398       When the initial object is loaded, all the objects that the initial
399       object depends on will be loaded. This will continue until all
400       dependent objects have been inflated from the database.
401
402       If we did not use a scope, by the time $homer his spouse attribute
403       would have been cleared because there is no other reference to Marge.
404       Here is a code snippet that demonstrates why:
405
406        sub get_homer {
407            my $homer = Person->new( name => 'Homer' );
408            my $marge = Person->new( name => 'Marge' );
409
410            $homer->spouse( $marge );
411            $marge->spouse( $homer );
412
413            return $homer;
414
415           # at this point $homer and $marge go out of scope
416           # $homer has a refcount of 1 because it's the return value
417           # $marge has a refcount of 0, and gets destroyed
418           # the weak reference in $homer->spouse is cleared
419        }
420
421        my $homer = get_homer();
422
423        $homer->spouse; # this returns undef
424
425       By using this idiom:
426
427        {
428           my $scope = Storm->new_scope;
429
430           ... do all Storm work in here ...
431        }
432
433       You are ensuring that the objects live at least as long as necessary.
434
435       In a web application context, you usually create one new scope per
436       request.
437
438   Credit
439       The live object scope was largely inspired by the KiokuDB module. Some
440       of the code and documentation for this functionality was taken directly
441       from the KiokuDB source (and possibly modified.)
442

TRANSACTIONS

444       When using a supporting databse, you can use the "do_transaction"
445       method to execute a code block and commit the transaction.
446
447        eval {
448           $storm->do_transaction( sub {
449
450               ... do work on $storm ...
451
452           });
453        }
454
455        print $@ if $@; # prints error
456
457       The transaction will only be committed if they block executes
458       successfully. If any exceptions are thrown, the transaction will be
459       rolled back. It is recommended that you execute the transaction inside
460       an eval block to trap any errors that are thrown. Alternatively, you
461       can use a module like TryCatch or Try::Tiny to trap errors.
462

POLICY

464       The policy is used to determine what data type is used by the DBMS to
465       store a value. The policy also determines how different types of values
466       are inflated/deflated.
467
468        package My::Policy;
469        use Storm::Policy;
470
471        define 'DateTime', 'DATETIME';
472
473        transform 'DateTime',
474           inflate { DateTime::Form::SQLite->parse_datetime( $_ ) },
475           deflate { DateTime::Form::SQLite->format_datetime( $_ ) };
476
477
478        package main;
479        use Storm;
480
481        $storm->new( source => ..., policy => 'My::Policy' );
482
483       "define"
484           Use the "define" keyword to determine what data type the DBMS
485           should used to store a value of the given type. In this case we
486           want DateTime objects to be stored in the database using the
487           "DATETIME" data type.
488
489       "transform"
490           Use the "transform" keyword for setting a custom inflator/deflator
491           for a type.
492
493           The inflator is defined using the "inflate" keyword. The $_ special
494           variable will be set to the value to be inflated. The inflator is
495           expected to return the inflated value.
496
497           The deflator is defined using the "deflate" keyword. The $_ special
498           variable will be set to the value to be deflated. The deflator is
499           expected to return the deflated value.
500
501   Credit
502       The policy was inspired by the Fey::ORM module. Some of the code this
503       functionality was taken directly from theFey::ORM source (and possibly
504       modified.)
505

AEOLUS

507       Aeolus is the greek god of the wind.  Aeolus helps manage your database
508       installation. With Aeolus you can easily install and remove the tables
509       your classes need to store their data.
510
511        $storm->aeolus->install_class( 'Person' );
512
513       See Storm::Aeolus for more information.
514

AUTHORS

516       Jeffrey Ray Hallock <jeffrey.hallock at gmail dot com>
517
518       Dave Rolsky <autarch@urth.org>
519
520       Yuval Kogman <nothingmuch@woobling.org>
521
523           Copyright (c) 2010-2011 Jeffrey Ray Hallock.
524
525           Copyright (c) 2010-2011 Dave Rolsky.
526
527           Copyright (c) 2008, 2009 Yuval Kogman, Infinity Interactive.
528
529           All rights reserved. This program is free software; you can redistribute it
530           and/or modify it under the same terms as Perl itself.
531

POD ERRORS

533       Hey! The above document had some coding errors, which are explained
534       below:
535
536       Around line 252:
537           '=item' outside of any '=over'
538
539
540
541perl v5.34.0                      2021-07-22                Storm::Tutorial(3)
Impressum