changing name of MX:T:Dependent to reflect more general problem domain
[gitmo/MooseX-Dependent.git] / specification.pod
CommitLineData
3659fb05 1=head1 TITLE
2
3Specification - Technical details for dependent types
4
5=head1 DESCRIPTION
6
7Specification for extra, declaritive hinting to type constrain definitions.
8
9=head1 INTRODUCTION
10
b3469a41 11We'd like to be able to add additional 'facets' when declaring our type
3659fb05 12constraints. These hints would form an extention to the core types built into
13Moose, such as Str, Object, etc. as well as form the foundation for authors of
14Type Constraint extentions to also add these hints. The idea is these hints
15would allow us to move a lot of the more common constraint types from the
16where clause of a subtype to the subtype meta data. This would make it simple
17to create a lot of the more common constraint types, improving usability and
18consistency. Also, since the implementations for these constraints would be
19universally vetted, we are likely to improve global code quality.
20
21Additional advantages would be those derived from the common code ecosystem,
22that is that more people would share common knowledge, improving our ability
23to build a strong community of shared best practices.
24
25Lastly, by hinting type constraints with additional metadata, the possibility
26to introspect that metadata usefully for code generation becomes possible. In
27particular, we'd like these additional constraints to fit neatly with existing
28code generation and mapping tools, such asd DBIx-Class, Reaction, Ernst, etc.
29
30So, an important goal of choosing the hints to to choose and define ones that
31can be mapped to other type constraint systems. For example, having a maximum
32length hint for a string type would map well to most database column types,
33but a hint to match a string to a regular expression should be defined
34carefully, since most databases have limited if any abilities to do this.
35
36Therefore, it will be important to make sure the hinting system can degrade or
37cast gracefully, that way hints defined at the application level will work
38neatly with those defined at a possible database level.
39
b3469a41 40=head1 PROPOSED SYNTAX
41
42The following is proposed syntax for the faceted types:
43
44 subtype MyType,
45 is Str,
46 which hasMinLenth(5), hasMaxLength(20),
47 where {};
48
3659fb05 49=head1 USE CASES
50
51The following are possible use cases.
52
53=head2 Str
54
55It's common to add additional constraints to the STR type. How many times have
56you done something like:
57
58 my $tc = subtype MaxStr10, as Str, where { length($_) <= 10 };
59
60To create a string of 10 characters or less. Since this constraint is captured
61in the code block it is not introspecable. A possible syntax to declare a Str
62type constraint with a maximum length hint might be:
63
b3469a41 64 my $tc = subtype MaxStr10, as Str, which hasMaxInclusiveLength(10);
3659fb05 65
b3469a41 66this information might be introspectable via something like:
3659fb05 67
b3469a41 68 $tc->meta->facets->max_length_inclusive; ## returns 10
3659fb05 69
70=head2 DataTime and coercion possibilities
71
72The following example shows how this system could work to enhance type
73constraints in the MooseX-Types* namespace. It also shows how coercions could
74be hooked into the hint system to allow more finely tuned coercions:
75
76 use MooseX::Types::DateTime qw(DateTime);
77
78 subtype USEasternDataTime,
b3469a41 79 is DateTime,
80 which hasTimeZone('US/Eastern');
3659fb05 81
82 coerce USEasternDataTime,
b3469a41 83 from DateTime,
84 which hasTimeZone('Floating')
3659fb05 85 via {$_->timezone('US/Eastern')};
86
87The created subtype USEasternDataTime would only pass if the DateTime object
88has the defined timezone. Their is a coercion that would adjust timezone
89information to the canonical type.
90
91=head2 Code generation and mapping
92
b3469a41 93Given a type constraint such as:
94
95 subtype ValidName,
96 as Str,
97 which hasMaxInclusiveLength(45), isAlpha(),
3659fb05 98
99That becomes part of a class definition:
100
101 package MyApp::Person;
102 ...
b3469a41 103 has 'name' => (isa=>ValidName, required=>1);
3659fb05 104
105A code generator or interpreter could introspect the metadata on the attribute
106'short_name' to create a table like:
107
108 CREATE TABLE Person (
b3469a41 109 short_name varchar(45)
110 );
111
112Please note how the code generator would need to aggregate meta information from
113both the attribute options as well as it's type constraint, since in this case
114the 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
138The above might be generated into sql like so (let's assume a database that
139has 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'),
3659fb05 167 );
168
b3469a41 169 my $person = model('Person')->create({
170 person_first_name => { first_name => {value=>'John'} },
171 ...
172 });
173
174Probably an extreme options, but if we have types with all this meta data, why
175not have it reflect down to the database model?
176
3659fb05 177[Addional Code examples to follow]
178
b3469a41 179=head1 CORE TYPES AND FACET HEIRARCHY
3659fb05 180
181The following is an outline of the possible hints associated with core Moose
182type 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
206DDUNCAN
207 ]
208 Int[
209 Signed
210 UnSigned
b3469a41 211 Even
212 Odd
3659fb05 213 ]
3659fb05 214 Str[
215 ASCII*
216 Printable*
b3469a41 217 isDigits* (That is, a string that is a number like "123")
3659fb05 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
b3469a41 234 hasDuplicates
235 hasOnlyUnique
3659fb05 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 ]
b3469a41 252
253**
254Might like to have some stuff from the Math packages, like to validate if a
255value matches a given function, or is in the domain or range of a function.