File Coverage

blib/lib/DBIx/Class/Sims.pm
Criterion Covered Total %
statement 6 15 40.0
branch 0 4 0.0
condition n/a
subroutine 3 4 75.0
pod n/a
total 9 23 39.1


line stmt bran cond sub pod time code
1             # vim: set sw=2 ft=perl:
2             package DBIx::Class::Sims;
3              
4 26     26   2501144 use 5.010_001;
  26         164  
5              
6 26     26   368 use strictures 2;
  26         1364  
  26         901  
7              
8             our $VERSION = '0.300900';
9              
10             {
11             # Do **NOT** import a clone() function into the DBIx::Class::Schema namespace
12             # because that will override DBIC's clone() method and break all the things.
13             package MyCloner;
14              
15             sub clone {
16 0     0     my ($data) = @_;
17              
18 0 0         if (ref($data) eq 'HASH') {
    0          
19             return {
20 0           map { $_ => clone($data->{$_}) }
  0            
21             keys %$data
22             };
23             }
24             elsif (ref($data) eq 'ARRAY') {
25             return [
26 0           map { clone($_) }
  0            
27             @$data
28             ];
29             }
30              
31 0           return $data;
32             }
33             }
34              
35 26     26   9782 use DDP;
  0            
  0            
36              
37             use Data::Walk qw( walk );
38             use DateTime;
39             use DBIx::Class::TopoSort ();
40             use Hash::Merge qw( merge );
41             use List::Util qw( first );
42             use List::MoreUtils qw( natatime );
43             use Scalar::Util qw( blessed reftype );
44              
45             {
46             # The aliases in this block are done at BEGIN time so that the ::Types class
47             # can use them when it is loaded through `use`.
48              
49             my @sim_names;
50             my %sim_types;
51             my @sim_matchers;
52              
53             sub set_sim_type {
54             shift;
55             my $types = shift // '';
56              
57             if (ref($types) eq 'HASH') {
58             while ( my ($name, $meth) = each(%$types) ) {
59             next unless ref($meth) eq 'CODE';
60              
61             $sim_types{$name} = $meth;
62             push @sim_names, $name;
63             }
64             }
65             elsif (ref($types) eq 'ARRAY') {
66             foreach my $item (@$types) {
67             next unless ref($item->[2]) eq 'CODE';
68              
69             push @sim_names, $item->[0];
70             push @sim_matchers, [ qr/^$item->[1]$/, $item->[2] ];
71             }
72             }
73              
74             return;
75             }
76             BEGIN { *set_sim_types = \&set_sim_type; }
77              
78             sub __find_sim_type {
79             my ($str) = @_;
80              
81             unless (exists $sim_types{$str}) {
82             my $item = first { $str =~ $_->[0] } @sim_matchers;
83             if ($item) {
84             $sim_types{$str} = $item->[1];
85             }
86             }
87              
88             return $sim_types{$str};
89             }
90              
91             sub sim_type {
92             shift;
93              
94             # If no specific type requested, then return the complete list of all
95             # registered types.
96             return sort @sim_names if @_ == 0;
97              
98             return __find_sim_type($_[0]) if @_ == 1;
99             return map { __find_sim_type($_) } @_;
100             }
101             BEGIN { *sim_types = \&sim_type; }
102             }
103             use DBIx::Class::Sims::Types;
104              
105             use DBIx::Class::Sims::Runner;
106             use DBIx::Class::Sims::Util;
107              
108             sub add_sims {
109             my $class = shift;
110             my ($schema, $source, @remainder) = @_;
111              
112             my $rsrc = $schema->source($source);
113             my $it = natatime(2, @remainder);
114             while (my ($column, $sim_info) = $it->()) {
115             my $col_info = $schema->source($source)->column_info($column) // next;
116             $col_info->{sim} = merge(
117             $col_info->{sim} // {},
118             $sim_info // {},
119             );
120             }
121              
122             return;
123             }
124             *add_sim = \&add_sims;
125              
126             sub load_sims {
127             my $self = shift;
128             my $schema;
129             if (ref($self) && $self->isa('DBIx::Class::Schema')) {
130             $schema = $self;
131             }
132             else {
133             $schema = shift(@_);
134             }
135             my ($spec_proto, $opts_proto) = @_;
136             $spec_proto = MyCloner::clone($spec_proto // {});
137             $opts_proto = MyCloner::clone($opts_proto // {});
138              
139             my $spec = massage_input($schema, normalize_input($spec_proto));
140             my $opts = normalize_input($opts_proto);
141              
142             # 1. Ensure the belongs_to relationships are in $reqs
143             # 2. Set the rel_info as the leaf in $reqs
144             my $reqs = normalize_input($opts->{constraints} // {});
145              
146             # 2: Create the rows in toposorted order
147             my $hooks = $opts->{hooks} // {};
148             $hooks->{preprocess} //= sub {};
149             $hooks->{postprocess} //= sub {};
150              
151             # Create a lookup of the items passed in so we can return them back.
152             my $initial_spec = {};
153             foreach my $name (keys %$spec) {
154             my $normalized = DBIx::Class::Sims::Util->normalize_aoh($spec->{$name});
155             unless ($normalized) {
156             warn "Skipping $name - I don't know what to do!\n";
157             delete $spec->{$name};
158             next;
159             }
160             $spec->{$name} = $normalized;
161              
162             foreach my $item (@{$spec->{$name}}) {
163             $initial_spec->{$name}{$item} = 1;
164             }
165             }
166              
167             my ($rows, $additional) = ({}, {});
168             if (keys %{$spec}) {
169             # Yes, this invokes srand() twice, once in implicitly in rand() and once
170             # again right after. But, that's okay. We don't care what the seed is and
171             # this allows DBIC to be called multiple times in the same process in the
172             # same second without problems.
173             $additional->{seed} = $opts->{seed} //= rand(time & $$);
174             srand($opts->{seed});
175              
176             my @toposort = DBIx::Class::TopoSort->toposort(
177             $schema,
178             %{$opts->{toposort} // {}},
179             );
180              
181             my $runner = DBIx::Class::Sims::Runner->new(
182             parent => $self,
183             schema => $schema,
184             toposort => \@toposort,
185             initial_spec => $initial_spec,
186             spec => $spec,
187             hooks => $hooks,
188             reqs => $reqs,
189             );
190              
191             $rows = eval {
192             $runner->run();
193             }; if ($@) {
194             $additional->{error} = $@;
195              
196             if ($opts->{die_on_failure} // 1) {
197             warn "SEED: $opts->{seed}\n";
198             die $@;
199             }
200             }
201              
202             $additional->{created} = $runner->{created};
203             $additional->{duplicates} = $runner->{duplicates};
204              
205             # Force a reload from the database of every row we're returning.
206             foreach my $item (values %$rows) {
207             $_->discard_changes for @$item;
208             }
209             }
210              
211             if (wantarray) {
212             return ($rows, $additional);
213             }
214             else {
215             return $rows;
216             }
217             }
218              
219             use YAML::Any qw( LoadFile Load );
220             sub normalize_input {
221             my ($proto) = @_;
222              
223             if ( ref($proto) ) {
224             return $proto;
225             }
226              
227             # Doing a stat on a filename with a newline throws an error.
228             my $x = eval {
229             no warnings;
230             if ( -e $proto ) {
231             return LoadFile($proto);
232             }
233             };
234             return $x if $x;
235              
236             return Load($proto);
237             }
238              
239             sub massage_input {
240             my ($schema, $struct) = @_;
241              
242             my $dtp = $schema->storage->datetime_parser;
243             walk({
244             preprocess => sub {
245             # Don't descend into the weeds. Only do the things we care about.
246             return if grep { blessed($_) } @_;
247             return unless grep { reftype($_) } @_;
248             return @_;
249             },
250             wanted => sub {
251             return unless (reftype($_)//'') eq 'HASH' && !blessed($_);
252             foreach my $k ( keys %$_ ) {
253             my $t = $_;
254              
255             # Expand the dot-naming convention.
256             while ( $k =~ /([^.]*)\.(.*)/ ) {
257             $t->{$1} = { $2 => delete($t->{$k}) };
258             $t = $t->{$1}; $k = $2;
259             }
260              
261             # Handle DateTime values passed to us.
262             if (defined $t->{$k}) {
263             if ( $t->{$k} =~ /^(\d\d\d\d)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)$/ ) {
264             # format_datetime() requires a DateTime object. This may be a
265             # string, therefore hoist it if need-be.
266             unless (blessed($t->{$k})) {
267             $t->{$k} = DateTime->new(
268             year => $1, month => $2, day => $3,
269             hour => $4, minute => $5, second => $6,
270             );
271             }
272             $t->{$k} = $dtp->format_datetime($t->{$k});
273             }
274             }
275             }
276             },
277             }, $struct);
278              
279             return $struct;
280             }
281              
282             1;
283             __END__
284              
285             =head1 NAME
286              
287             DBIx::Class::Sims - The addition of simulating data to DBIx::Class
288              
289             =head1 SYNOPSIS (CLASS VERSION)
290              
291             DBIx::Class::Sims->add_sims(
292             $schema, 'source_name',
293             address => { type => 'us_address' },
294             zip_code => { type => 'us_zipcode' },
295             # ...
296             );
297              
298             my $rows = DBIx::Class::Sims->load_sims($schema, {
299             Table1 => [
300             {}, # Take sims or default values for everything
301             { # Override some values, take sim values for others
302             column1 => 20,
303             column2 => 'something',
304             },
305             ],
306             });
307              
308             =head1 SYNOPSIS (COMPONENT VERSION)
309              
310             Within your schema class:
311              
312             __PACKAGE__->load_components('Sims');
313              
314             Within your resultsources, specify the sims generation rules for columns that
315             need specified.
316              
317             __PACKAGE__->add_columns(
318             ...
319             address => {
320             data_type => 'varchar',
321             is_nullable => 1,
322             data_length => 10,
323             sim => { type => 'us_address' },
324             },
325             zipcode => {
326             data_type => 'varchar',
327             is_nullable => 1,
328             data_length => 10,
329             sim => { type => 'us_zipcode' },
330             },
331             column1 => {
332             data_type => 'int',
333             is_nullable => 0,
334             sim => {
335             min => 10,
336             max => 20,
337             },
338             },
339             column2 => {
340             data_type => 'varchar',
341             is_nullable => 1,
342             data_length => 10,
343             default_value => 'foobar',
344             },
345             ...
346             );
347              
348             Later:
349              
350             $schema->deploy({
351             add_drop_table => 1,
352             });
353              
354             my $rows = $schema->load_sims({
355             Table1 => [
356             {}, # Take sims or default values for everything
357             { # Override some values, take sim values for others
358             column1 => 20,
359             column2 => 'something',
360             },
361             ],
362             });
363              
364             =head1 PURPOSE
365              
366             Generating test data for non-simplistic databases is extremely hard, especially
367             as the schema grows and changes. Designing scenarios B<should> be doable by only
368             specifying the minimal elements actually used in the test with the test being
369             resilient to any changes in the schema that don't affect the elements specified.
370             This includes changes like adding a new parent table, new required child tables,
371             and new non-NULL columns to the table being tested.
372              
373             With Sims, you specify only what you care about. Any required parent rows are
374             automatically generated. If a row requires a certain number of child rows (all
375             artists must have one or more albums), that can be set as well. If a column must
376             have specific data in it (a US zipcode or a range of numbers), you can specify
377             that in the table definition.
378              
379             And, in all cases, you can override anything.
380              
381             =head1 DESCRIPTION
382              
383             This is a L<DBIx::Class> component that adds a few methods to your
384             L<DBIx::Class::Schema> object. These methods make it much easier to create data
385             for testing purposes (though, obviously, it's not limited to just test data).
386              
387             Alternately, it can be used as a class method vs. a component, if that fits your
388             needs better.
389              
390             =head1 METHODS
391              
392             =head2 load_sims
393              
394             C<< $rv, $addl? = $schema->load_sims( $spec, ?$opts ) >>
395             C<< $rv, $addl? = DBIx::Class::Sims->load_sims( $schema, $spec, ?$opts ) >>
396              
397             This method will load the rows requested in C<$spec>, plus any additional rows
398             necessary to make those rows work. This includes any parent rows (as defined by
399             C<belongs_to>) and per any constraints defined in C<$opts->{constraints}>. If
400             need-be, you can pass in hooks (as described below) to manipulate the data.
401              
402             load_sims does all of its work within a call to L<DBIx::Class::Schema/txn_do>.
403             If anything goes wrong, load_sims will rethrow the error after the transaction
404             is rolled back.
405              
406             This, of course, assumes that the tables you are working with support
407             transactions. (I'm looking at you, MyISAM!) If they do not, that is on you.
408              
409             =head3 Return value
410              
411             This returns one or two values, depending on if you call load_sims in a scalar
412             or array context.
413              
414             The first value is a hash of arrays of hashes. This will match the C<$spec>,
415             except that where the C<$spec> has a requested set of things to make, the return
416             will have the DBIx::Class::Row objects that were created.
417              
418             Note that you do not get back the objects for anything other than the objects
419             specified at the top level.
420              
421             This second value is a hashref with additional items that may be useful. It may
422             contain:
423              
424             =over 4
425              
426             =item * error
427              
428             This will contain any error that happened while trying to create the rows.
429              
430             This is most useful when C<< die_on_failure >> is set to 0.
431              
432             =item * seed
433              
434             This is the random seed that was used in this run. If you set the seed in the
435             opts parameter in the load_sims call, it will be that value. Otherwise, it will
436             be set to a usefully random value for you. It will be different every time even
437             if you call load_sims multiple times within the same process in the same second.
438              
439             =item * created
440              
441             This is a hashref containing a count of each source that was created. This is
442             different from the first return value in that this lists everything created, not
443             just what was requested. It also only has counts, not the actual rows.
444              
445             =item * duplicates
446              
447             This is a hashref containing a list for each source of all the duplicates that
448             were found when creating rows for that source. For each duplicate found, there
449             will be an entry that specifies the criteria used to find that duplicate and the
450             row in the database that was found.
451              
452             The list will be ordered by when the duplicate was found, but that ordering will
453             B<NOT> be stable across different runs unless the same C<< seed >> is used.
454              
455             =back
456              
457             =head2 set_sim_type
458              
459             C<< $class_or_obj->set_sim_type({ $name => $handler, ... }); >>
460             C<< $class_or_obj->set_sim_type([ [ $name, $regex, $handler ], ... ]); >>
461              
462             This method will set the handler for the C<$name> sim type. The C<$handler> must
463             be a reference to a subroutine. You may pass in as many name/handler pairs as you
464             like.
465              
466             You may alternately pass in an arrayref of triplets. This allows you to use a
467             regex to match the provided type. C<$name> will be returned when the user
468             introspects the list of loaded sim types. C<$regex> will be used when finding the
469             type to handle this column. C<$handler> must be a reference to a subroutine.
470              
471             You cannot set pairs and triplets in the same invocation.
472              
473             This method may be called as a class or object method.
474              
475             This method returns nothing.
476              
477             C<set_sim_types()> is an alias to this method.
478              
479             =head2 sim_types
480              
481             C<< $class_or_obj->sim_types(); >>
482              
483             This method will return a sorted list of all registered sim types.
484              
485             This method may be called as a class or object method.
486              
487             =head1 SPECIFICATION
488              
489             The specification can be passed along as a filename that contains YAML or JSON,
490             a string that contains YAML or JSON, or as a hash of arrays of hashes. The
491             structure should look like:
492              
493             {
494             ResultSourceName => [
495             {
496             column => $value,
497             column => $value,
498             relationship => $parent_object,
499             relationship => {
500             column => $value,
501             },
502             'relationship.column' => $value,
503             'rel1.rel2.rel3.column' => $value,
504             },
505             ],
506             }
507              
508             If a column is a belongs_to relationship name, then the row associated with that
509             relationship specifier will be used. This is how you would specify a specific
510             parent-child relationship. (Otherwise, a random choice will be made as to which
511             parent to use, creating one as necessary if possible.) The dots will be followed
512             as far as necessary.
513              
514             If a column's value is a hashref, then that will be treated as a sim entry.
515             Example:
516              
517             {
518             Artist => [
519             {
520             name => { type => 'us_name' },
521             },
522             ],
523             }
524              
525             That will use the provided sim type 'us_name'. This will override any sim entry
526             specified on the column. See L</SIM ENTRY> for more information.
527              
528             Note: Before 0.300800, this behavior was triggered by a reference to a hashref.
529             That will still work, but is deprecated, throws a warning, and will be removed
530             in a future release.
531              
532             Columns that have not been specified will be populated in one of two ways. The
533             first is if the database has a default value for it. Otherwise, you can specify
534             the C<sim> key in the column_info for that column. This is a new key that is not
535             used by any other component. See L</SIM ENTRY> for more information.
536              
537             (Please see L<DBIx::Class::ResultSource/add_columns> for details on column_info)
538              
539             B<NOTE>: The keys of the outermost hash are resultsource names. The keys within
540             the row-specific hashes are either columns or relationships. Not resultsources.
541              
542             =head2 Reuse wherever possible
543              
544             The Sims's normal behavior is to attempt to reuse whenever possible. The theory
545             is that if you didn't say you cared about something, you do B<NOT> care about
546             that thing.
547              
548             =head3 Unique constraints
549              
550             If a source has unique constraints defined, the Sims will use them to determine
551             if a new row with these values I<can> be created or not. If a row already
552             exists with these values for the unique constraints, then that row will be used
553             instead of creating a new one.
554              
555             This is B<REGARDLESS> of the values for the non-unique-constraint rows.
556              
557             =head3 Forcing creation of a parent
558              
559             If you do not specify values for a parent (i.e., belongs_to), then the first row
560             for that parent will be be used. If you don't care what values the parent has,
561             but you care that a different parent is used, then you can set the __META__ key
562             as follows:
563              
564             $schema->load_sims({
565             Album => {
566             artist => { __META__ => { create => 1 } },
567             name => 'Some name',
568             }
569             })
570              
571             This will force the creation of a parent instead of reusing the parent.
572              
573             B<NOTE>: If the simmed values within the parent's class would result in values
574             that are the same across a unique constraint with an existing row, then that
575             row will be used. This just bypasses the "attempt to use the first parent".
576              
577             =head2 Alternatives
578              
579             =head3 Hard-coded number of things
580              
581             If you only want N of a thing, not really caring just what the column values end
582             up being, you can take a shortcut:
583              
584             {
585             ResultSourceName => 3,
586             }
587              
588             That will create 3 of that thing, taking all the defaults and sim'ed options as
589             exist.
590              
591             This will also work if you want 3 of a child via a has_many relationship. For
592             example, you can do:
593              
594             {
595             Artist => {
596             name => 'Someone Famous',
597             albums => 240,
598             },
599             }
600              
601             That will create 240 different albums for that artist, all with the defaults.
602              
603             =head3 Just one thing
604              
605             If you are creating one of a thing and setting some of the values, you can skip
606             the arrayref and pass the hashref directly.
607              
608             {
609             ResultSourceName => {
610             column => $value,
611             column => $value,
612             relationship => {
613             column => $value,
614             },
615             'relationship.column' => $value,
616             'rel1.rel2.rel3.column' => $value,
617             },
618             }
619              
620             And that will work exactly as expected.
621              
622             =head3 References
623              
624             Let's say you have a table that's a child of two other tables. You can specify
625             that relationship as follows:
626              
627             {
628             Parent1 => 1,
629             Parent2 => {
630             Child => {
631             parent1 => \"Parent1[0]",
632             },
633             },
634             }
635              
636             That's a reference to a string with the tablename as a pseudo-array, then the
637             index into that array. This only works for rows that you are going to return
638             back from the C<< load_sims() >> call.
639              
640             This also only works for belongs_to relationships. Since all parents are created
641             before all children, the Sims cannot back-reference into children.
642              
643             =head2 Notes
644              
645             =over 4
646              
647             =item * Multiply-specified children
648              
649             Sometimes, you will have a table with more than one parent (q.v. t/t5.t for an
650             example of this). If you specify a row for each parent and, in each parent,
651             specify a child with the same characteristics, only one child will be created.
652             The assumption is that you meant the same row.
653              
654             This does B<not> apply to creating multiple rows with the same characteristics
655             as children of the same parent. The assumption is that you meant to do that.
656              
657             =back
658              
659             =head1 OPTS
660              
661             There are several possible options.
662              
663             =head2 constraints
664              
665             The constraints can be passed along as a filename that contains YAML or JSON, a
666             string that contains YAML or JSON, or as a hash of arrays of hashes. The
667             structure should look like:
668              
669             {
670             Person => {
671             addresses => 2,
672             },
673             }
674              
675             All the C<belongs_to> relationships are automatically added to the constraints.
676             You can add additional constraints, as needed. The most common use for this will
677             be to add required child rows. For example, C<< Person->has_many('addresses') >>
678             would normally mean that if you create a Person, no Address rows would be
679             created. But, we could specify a constraint that says "Every person must have
680             at least 2 addresses." Now, whenever a Person is created, two Addresses will be
681             added along as well, if they weren't already created through some other
682             specification.
683              
684             =head2 die_on_failure
685              
686             If set to 0, this will prevent a die when creating a row. Instead, you will be
687             responsible for checking C<< $additional->{error} >> yourself.
688              
689             This defaults to 1.
690              
691             =head2 seed
692              
693             If set, this will be the srand() seed used for this invocation.
694              
695             =head2 toposort
696              
697             This is passed directly to the call to C<< DBIx::Class::TopoSort->toposort >>.
698              
699             =head2 hooks
700              
701             Most people will never need to use this. But, some schema definitions may have
702             reasons that prevent a clean simulating with this module. For example, there may
703             be application-managed sequences. To that end, you may specify the following
704             hooks:
705              
706             =over 4
707              
708             =item * preprocess
709              
710             This receives C<$name, $source, $spec> and expects nothing in return. C<$spec>
711             is the hashref that will be passed to C<<$schema->resultset($name)->create()>>.
712             This hook is expected to modify C<$spec> as needed.
713              
714             =item * postprocess
715              
716             This receives C<$name, $source, $row> and expects nothing in return. This hook
717             is expected to modify the newly-created row object as needed.
718              
719             =back
720              
721             =head1 SIM ENTRY
722              
723             To control how a column's values are simulated, add a "sim" entry in the
724             column_info for that column. The sim entry is a hash that can have the followingkeys:
725              
726             =over 4
727              
728             =item * value / values
729              
730             This behaves just like default_value would behave, but doesn't require setting a
731             default value on the column.
732              
733             sim => {
734             value => 'The value to always use',
735             },
736              
737             This can be either a string, number, or an arrayref of strings or numbers. If it
738             is an arrayref, then a random choice from that array will be selected.
739              
740             =item * type
741              
742             This labels the column as having a certain type. A type is registered using
743             L</set_sim_type>. The type acts as a name for a function that's used to generate
744             the value. See L</Types> for more information.
745              
746             =item * min / max
747              
748             If the column is numeric, then the min and max bound the random value generated.
749             If the column is a string, then the min and max are the length of the random
750             value generated.
751              
752             =item * func
753              
754             This is a function that is provided the column info. Its return value is used to
755             populate the column.
756              
757             =item * null_chance
758              
759             If the column is nullable I<and> this is set I<and> it is a number between 0 and
760             1, then if C<rand()> is less than that number, the column will be set to null.
761             Otherwise, the standard behaviors will apply.
762              
763             If the column is B<not> nullable, this setting is ignored.
764              
765             =back
766              
767             (Please see L<DBIx::Class::ResultSource/add_columns> for details on column_info)
768              
769             =head2 Types
770              
771             The handler for a sim type will receive the column info (as defined in
772             L<DBIx::Class::ResultSource/add_columns>). From that, the handler returns the
773             value that will be used for this column.
774              
775             Please see L<DBIx::Class::Sims::Types> for the list of included sim types.
776              
777             =head1 SEQUENCE OF EVENTS
778              
779             When an item is created, the following actions are taken (in this order):
780              
781             =over 4
782              
783             =item 1 The columns are fixed up.
784              
785             This is where generated values are generated. After this is done, all the values
786             that will be inserted into the database are now available.
787              
788             q.v. L</SIM ENTRY> for more information.
789              
790             =item 1 The preprocess hook fires.
791              
792             You can modify the hashref as necessary. This includes potentially changing what
793             parent and/or child rows to associate with this row.
794              
795             =item 1 All foreign keys are resolved.
796              
797             If it's a parent relationship, the parent row will be found or created. All
798             parent rows will go through the same sequence of events as described here.
799              
800             If it's a child relationship, creation of the child rows will be deferred until
801             later.
802              
803             =item 1 The row is found or created.
804              
805             It might be found by unique constraint or created.
806              
807             =item 1 All child relationships are handled
808              
809             Because they're a child relationship, they are deferred until the time that
810             model is handled in the toposorted graph. They are not created now because they
811             might associate with a different parent that has not been created yet.
812              
813             =item 1 The postprocess hook fires.
814              
815             Note that any child rows are not guaranteed to exist yet.
816              
817             =back
818              
819             =head1 TODO
820              
821             =head2 Multi-column types
822              
823             In some applications, columns like "state" and "zipcode" are correlated. Values
824             for one must be legal for the value in the other. The Sims currently has no way
825             of generating correlated columns like this.
826              
827             This is most useful for saying "These 6 columns should be a coherent address".
828              
829             =head2 Allow a column to reference other columns
830              
831             Sometimes, a column should alter its behavior based on other columns. A fullname
832             column may have the firstname and lastname columns concatenated, with other
833             things thrown in. Or, a zipcode column should only generate a zipcode that're
834             legal for the state.
835              
836             =head1 BUGS/SUGGESTIONS
837              
838             This module is hosted on Github at
839             L<https://github.com/robkinyon/dbix-class-sims>. Pull requests are strongly
840             encouraged.
841              
842             =head1 DBIx::Class::Fixtures
843              
844             L<DBIx::Class::Fixtures> is another way to load data into a database. Unlike
845             this module, L<DBIx::Class::Fixtures> approaches the problem by loading the same
846             data every time. This is complementary because some tables (such as lookup
847             tables of countries) want to be seeded with the same data every time. The ideal
848             solution would be to have a set of tables loaded with fixtures and another set
849             of tables loaded with sims.
850              
851             =head1 SEE ALSO
852              
853             L<DBIx::Class>, L<DBIx::Class::Fixtures>
854              
855             =head1 AUTHOR
856              
857             Rob Kinyon <rob.kinyon@gmail.com>
858              
859             =head1 LICENSE
860              
861             Copyright (c) 2013 Rob Kinyon. All Rights Reserved.
862             This is free software, you may use it and distribute it under the same terms
863             as Perl itself.
864              
865             =cut