49
|
1 package IMPL::ORM::Schema;
|
|
2 use strict;
|
|
3 use warnings;
|
|
4
|
|
5 use base qw(IMPL::DOM::Document);
|
|
6 use IMPL::Class::Property;
|
|
7 require IMPL::ORM::Schema::Entity;
|
|
8 require IMPL::ORM::Schema::ValueType;
|
|
9
|
|
10 our %CTOR = (
|
|
11 'IMPL::DOM::Document' => sub { nodeName => 'ORMSchema' }
|
|
12 );
|
|
13
|
|
14 BEGIN {
|
|
15 public property mapValueTypes => prop_get | owner_set;
|
|
16 public property mapReferenceTypes => prop_get | owner_set;
|
|
17 public property mapPending => prop_get | owner_set;
|
|
18 public property prefix => prop_get | owner_set;
|
|
19 }
|
|
20
|
|
21 sub CTOR {
|
|
22 my ($this ) = @_;
|
|
23 $this->mapValueTypes({});
|
|
24 $this->mapReferenceTypes({});
|
|
25 $this->mapPending({});
|
|
26 }
|
|
27
|
|
28 # return an entity for the specified typename
|
|
29 # makes forward declaration if nesessary
|
|
30 sub resolveType {
|
|
31 my ($this,$typeName) = @_;
|
|
32
|
|
33 $this = ref $this ? $this : $this->instance;
|
|
34
|
|
35 if (my $entity = $this->mapReferenceTypes->{$typeName}) {
|
|
36 return $entity;
|
|
37 } elsif (UNIVERSAL::isa($typeName,'IMPL::ORM::Object')) {
|
|
38 return $this->declareReferenceType($typeName);
|
|
39 } else {
|
|
40 return undef;
|
|
41 }
|
|
42 }
|
|
43
|
|
44 sub declareReferenceType {
|
|
45 my ($this,$typeName) = @_;
|
|
46
|
|
47 my $entity = new IMPL::ORM::Schema::Entity($typeName->entityName);
|
|
48
|
|
49 $this->mapPending->{$typeName} = $entity;
|
|
50
|
|
51 $this->appendChild($entity);
|
|
52
|
|
53 return $this->mapReferenceTypes->{$typeName} = $entity;
|
|
54 }
|
|
55
|
|
56 sub _addReferenceType {
|
|
57 my ($this,$className) = @_;
|
|
58
|
|
59 if ( my $entity = delete $this->mapPending->{$className} ) {
|
|
60 $className->ormGetSchema($this,$entity);
|
|
61 } else {
|
|
62 return $this->appendChild( $this->mapReferenceTypes->{$className} = $className->ormGetSchema($this) );
|
|
63 }
|
|
64
|
|
65 }
|
|
66
|
|
67 # returns valuetype name
|
|
68 sub isValueType {
|
|
69 my ($this,$typeName) = @_;
|
|
70
|
|
71 $this = ref $this ? $this : $this->instance;
|
|
72
|
|
73 return $this->mapValueTypes->{$typeName};
|
|
74 }
|
|
75
|
|
76 my %instances;
|
|
77 sub instance {
|
|
78 my ($class) = @_;
|
|
79
|
|
80 return ($instances{$class} || ($instances{$class} = $class->new));
|
|
81 }
|
|
82
|
|
83 sub ValueTypes {
|
|
84 my ($this,%classes) = @_;
|
|
85
|
|
86 $this = ref $this ? $this : $this->instance;
|
|
87
|
|
88 while ( my ($typeName,$typeReflected) = each %classes ) {
|
|
89 $this->mapValueTypes->{$typeName} = $typeReflected;
|
|
90 $this->appendChild(IMPL::ORM::Schema::ValueType->new($typeName,$typeReflected));
|
|
91 }
|
|
92 }
|
|
93
|
|
94 sub Classes {
|
|
95 my ($this,@classNames) = @_;
|
|
96
|
|
97 $this = ref $this ? $this : $this->instance;
|
|
98
|
|
99 $this->_addReferenceType($this->prefix . $_) foreach @classNames;
|
|
100 }
|
|
101
|
|
102 sub usePrefix {
|
|
103 my ($this,$prefix) = @_;
|
|
104
|
|
105 $prefix .= '::' if $prefix and $prefix !~ /::$/;
|
|
106
|
|
107 (ref $this ? $this : $this->instance)->prefix($prefix);
|
|
108 }
|
|
109
|
|
110 sub CompleteSchema {
|
|
111 my ($this) = @_;
|
|
112
|
|
113 $this = ref $this ? $this : $this->instance;
|
|
114
|
|
115 $_->ormGetSchema($this,delete $this->mapPending->{$_}) foreach (keys %{$this->mapPending});
|
|
116 }
|
|
117
|
|
118 1;
|
|
119
|
|
120 __END__
|
|
121
|
|
122 =pod
|
|
123
|
79
|
124 =head1 NAME
|
|
125
|
|
126 C<IMPL::ORM::Schema> Схема отображения классов в реляционную структуру.
|
|
127
|
49
|
128 =head1 DESCRIPTION
|
|
129
|
|
130 Схема данных, представляет собой DOM документ, элементами которой
|
|
131 являются сущности.
|
|
132
|
|
133 Каждый узел - это описание сущности.
|
|
134
|
79
|
135 =begin code xml
|
|
136
|
49
|
137 <Schema>
|
|
138 <Entity entityName="My_Data_Foo">
|
|
139 <Field fieldName="Doo" fieldType="String"/>
|
|
140 <HasMany name="Boxes" target="My_Data_Box"/>
|
|
141 </Entity>
|
|
142 <Entity entityName="My_Data_Bar">
|
|
143 <Subclass base="My_Data_Foo"/>
|
|
144 <Field fieldName="Timestamp" fieldType="Integer"/>
|
|
145 </Entity>
|
|
146 <Entity entityName="My_Data_Box">
|
|
147 <Field fieldName="Capacity" fieldType="Integer"/>
|
|
148 </Entity>
|
|
149 </Schema>
|
|
150
|
79
|
151 =end code xml
|
|
152
|
49
|
153 =cut
|