changing name of MX:T:Dependent to reflect more general problem domain
[gitmo/MooseX-Dependent.git] / specification.pod
1 =head1 TITLE
2
3 Specification - Technical details for dependent types
4
5 =head1 DESCRIPTION
6
7 Specification for extra, declaritive hinting to type constrain definitions.
8
9 =head1 INTRODUCTION
10
11 We'd like to be able to add additional 'facets' when declaring our type 
12 constraints.  These hints would form an extention to the core types built into
13 Moose, such as Str, Object, etc. as well as form the foundation for authors of
14 Type Constraint extentions to also add these hints.  The idea is these hints
15 would allow us to move a lot of the more common constraint types from the 
16 where clause of a subtype to the subtype meta data.  This would make it simple
17 to create a lot of the more common constraint types, improving usability and
18 consistency.  Also, since the implementations for these constraints would be
19 universally vetted, we are likely to improve global code quality.
20
21 Additional advantages would be those derived from the common code ecosystem, 
22 that is that more people would share common knowledge, improving our ability
23 to build a strong community of shared best practices.
24
25 Lastly, by hinting type constraints with additional metadata, the possibility
26 to introspect that metadata usefully for code generation becomes possible.  In
27 particular, we'd like these additional constraints to fit neatly with existing
28 code generation and mapping tools, such asd DBIx-Class, Reaction, Ernst, etc.
29
30 So, an important goal of choosing the hints to to choose and define ones that
31 can be mapped to other type constraint systems.  For example, having a maximum
32 length hint for a string type would map well to most database column types, 
33 but a hint to match a string to a regular expression should be defined 
34 carefully, since most databases have limited if any abilities to do this.
35
36 Therefore, it will be important to make sure the hinting system can degrade or
37 cast gracefully, that way hints defined at the application level will work
38 neatly with those defined at a possible database level.
39
40 =head1 PROPOSED SYNTAX
41
42 The following is proposed syntax for the faceted types:
43
44         subtype MyType,
45          is Str,
46          which hasMinLenth(5), hasMaxLength(20),
47          where {};
48
49 =head1 USE CASES
50
51 The following are possible use cases.
52
53 =head2 Str
54
55 It's common to add additional constraints to the STR type.  How many times have
56 you done something like:
57
58         my $tc = subtype MaxStr10, as Str, where { length($_) <= 10 };
59
60 To create a string of 10 characters or less.  Since this constraint is captured
61 in the code block it is not introspecable.  A possible syntax to declare a Str
62 type constraint with a maximum length hint might be:
63
64         my $tc = subtype MaxStr10, as Str, which hasMaxInclusiveLength(10);
65
66 this information might be introspectable via something like:
67
68         $tc->meta->facets->max_length_inclusive; ## returns 10
69
70 =head2 DataTime and coercion possibilities
71
72 The following example shows how this system could work to enhance type 
73 constraints in the MooseX-Types* namespace.  It also shows how coercions could
74 be hooked into the hint system to allow more finely tuned coercions:
75
76         use MooseX::Types::DateTime qw(DateTime);
77         
78         subtype USEasternDataTime,
79          is DateTime,
80          which hasTimeZone('US/Eastern');
81          
82         coerce USEasternDataTime,
83          from DateTime,
84           which hasTimeZone('Floating')
85          via {$_->timezone('US/Eastern')};
86          
87 The created subtype USEasternDataTime would only pass if the DateTime object
88 has the defined timezone.  Their is a coercion that would adjust timezone
89 information to the canonical type.
90
91 =head2 Code generation and mapping
92
93 Given a type constraint such as:
94
95         subtype ValidName, 
96          as Str, 
97          which hasMaxInclusiveLength(45), isAlpha(), 
98         
99 That becomes part of a class definition:
100
101         package MyApp::Person;
102         ...
103         has 'name' => (isa=>ValidName, required=>1);
104
105 A code generator or interpreter could introspect the metadata on the attribute
106 'short_name' to create a table like:
107
108         CREATE TABLE Person (
109                 short_name varchar(45)
110         );
111         
112 Please note how the code generator would need to aggregate meta information from
113 both the attribute options as well as it's type constraint, since in this case
114 the attribute is required.  Here's another, more complicated option.
115
116         package MyApp::Types::StatisticsPeople;
117         
118         ## both types are limited to 45 alphabetical characters that define a
119         ## single word (no whitespace before or after), like "John", but not allow
120         ## "   John", "  John  ", "john123", etc.
121         
122         subtype FirstName, 
123          as Str, 
124          which hasMaxInclusiveLength(45), isAlpha(), isWord();
125
126         subtype ValidName, 
127          as Str, 
128          which hasMaxInclusiveLength(45), isAlpha(), isWord();
129          
130         package MyApp::Person;
131          
132         use Moose;
133         use MyApp::Types::StatisticsPeople (qw/FirstName LastName/);
134          
135         has first_name => (isa=>FirstName, required=>1);
136         has last_name => (isa=>LastName, required=>1);
137         
138 The above might be generated into sql like so (let's assume a database that
139 has schema support, like Postgresql,
140
141         CREATE TABLE StatisticsPeople.FirstName (
142                 first_name_id uuid,
143                 value varchar(45),
144                 PRIMARY KEY('first_name_id')
145         );
146
147         CREATE TABLE StatisticsPeople.LastName (
148                 last_name_id uuid,
149                 value varchar(45),
150                 PRIMARY KEY('last_name_id')
151         );
152         
153         CREATE TABLE PersonFirstName (
154                 fk_person_id uuid,
155                 fk_first_name_id uuid,
156                 PRIMARY KEY('fk_person_id', 'fk_first_name_id'),
157         )
158         
159         CREATE TABLE Person (
160                 person_id uuid,
161                 fk_first_name_id uuid,
162                 fk_last_name_id uuid,           
163                 PRIMARY KEY ('person_id')
164                 CONSTRAINT 'person_validname' 
165                         FOREIGN KEY ('fk_last_name_id') 
166                         REFERENCES 'ValidName' ('valid_name_id'),
167         );
168         
169         my $person = model('Person')->create({
170                 person_first_name => { first_name => {value=>'John'} },
171                 ...
172         });
173
174 Probably an extreme options, but if we have types with all this meta data, why
175 not have it reflect down to the database model?
176
177 [Addional Code examples to follow]
178         
179 =head1 CORE TYPES AND FACET HEIRARCHY
180
181 The following is an outline of the possible hints associated with core Moose
182 type constraints.  Hints are assumed to be inherited.
183
184   Item[
185       Default
186       EqualTo
187       NotEqualTo
188   ]
189       Bool
190       Maybe[`a]
191       Undef
192       Defined
193           Value[
194               IsOneOf||IsNotOneOf
195               LessThanOrEqual || '<='
196               LessThan || '<'
197               GreaterThanOrEqual || '>='
198               GreaterThan || '>'
199               Between
200               NotBetween
201           ]
202               Num[
203                 Base
204                 Precision
205                 Scale
206 DDUNCAN
207               ]
208                 Int[
209                     Signed
210                     UnSigned
211                     Even
212                     Odd
213                 ]
214               Str[
215                   ASCII*
216                   Printable*
217                   isDigits*  (That is, a string that is a number like "123")
218                   Word (must be a single 'word')
219                   MaxLength
220                   MinLength
221                 EqualTo || 'eq'
222               ]
223
224         * Might be better as a general encoding type.
225         
226                 ClassName[
227                     PackageBase (For stuff like '::Plugin::MyPlugin')
228                 ]
229           Ref
230               ScalarRef
231               ArrayRef[`a][
232                   MaxElements
233                   MinElements
234                   hasDuplicates
235                   hasOnlyUnique
236               ]
237               HashRef[`a][
238                   HasAllKeys
239               ]
240               CodeRef
241               RegexpRef
242               GlobRef
243                 FileHandle
244               Object[
245                   HasMethods
246                   ISA
247               ]
248                   Role[
249                       Requires
250                       Does
251                   ]
252
253 **
254 Might like to have some stuff from the Math packages, like to validate if a
255 value matches a given function, or is in the domain or range of a function.