-
-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathОбъектМодели.os
290 lines (223 loc) · 19.1 KB
/
ОбъектМодели.os
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
#Использовать annotations
#Использовать reflector
#Использовать strings
Перем ТипСущности;
Перем ИмяТаблицы;
Перем ИсточникиДанных;
Перем Колонки;
Перем ПодчиненныеТаблицы;
// TODO: Первичный ключ из нескольких полей?
Перем Идентификатор;
Перем МодельДанных;
Перем Рефлектор;
Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных)
МодельДанных = ПМодельДанных;
ТипСущности = ПТипСущности;
ЗаполнитьКолонки();
ЗаполнитьПодчиненныеТаблицы();
Рефлектор = Новый Рефлектор;
КонецПроцедуры
Функция ИмяТаблицы() Экспорт
Возврат ИмяТаблицы;
КонецФункции
Функция ИсточникиДанных() Экспорт
Возврат ИсточникиДанных;
КонецФункции
Функция Колонки() Экспорт
Возврат Колонки.Скопировать();
КонецФункции
Функция ПодчиненныеТаблицы() Экспорт
Возврат ПодчиненныеТаблицы.Скопировать();
КонецФункции
// @internal
// TODO: вынести отсюда. Возможно стоит разработать отдельный служебный билдер Объекта модели,
// вытащив заполнение из конструктора в этот билдер, а в конструктор передавать уже готовые для сохранения
// в объект данные.
//
Функция Служебный_Колонки() Экспорт
Возврат Колонки;
КонецФункции
// @internal
Процедура Служебный_ИмяТаблицы(ПИмяТаблицы) Экспорт
ИмяТаблицы = ПИмяТаблицы;
КонецПроцедуры
Функция Идентификатор() Экспорт
Возврат Новый ФиксированнаяСтруктура(Идентификатор);
КонецФункции
Функция МодельДанных() Экспорт
Возврат МодельДанных;
КонецФункции
Функция ТипСущности() Экспорт
Возврат ТипСущности;
КонецФункции
Функция ПолучитьЗначениеИдентификатора(Сущность) Экспорт
ЗначениеИдентификатора = ПолучитьЗначениеПоля(Сущность, Идентификатор().ИмяПоля);
Возврат ЗначениеИдентификатора;
КонецФункции
Функция ПолучитьПриведенноеЗначениеПоля(Сущность, ИмяПоля) Экспорт
ЗначениеПоля = ПолучитьЗначениеПоля(Сущность, ИмяПоля);
Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");
Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
ОбъектМоделиСсылки = МодельДанных.Получить(Колонка.ТипСсылки);
Если ЗначениеПоля = Неопределено Тогда
ЗначениеПоля = ОбъектМоделиСсылки.ПривестиЗначениеПоля(ЗначениеПоля, ОбъектМоделиСсылки.Идентификатор().ИмяПоля);
Иначе
ЗначениеПоля = ОбъектМоделиСсылки.ПолучитьЗначениеИдентификатора(ЗначениеПоля);
КонецЕсли;
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.ДвоичныеДанные Тогда
// Просто ничего не делаем, все работает само
Иначе
ЗначениеПоля = ПривестиЗначениеПоля(ЗначениеПоля, ИмяПоля);
КонецЕсли;
Возврат ЗначениеПоля;
КонецФункции
Процедура УстановитьЗначениеКолонкиВПоле(Сущность, ИмяКолонки, ЗначениеПоля) Экспорт
Колонка = Колонки().Найти(ИмяКолонки, "ИмяКолонки");
Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
УстанавливаемоеЗначениеПоля = ЗначениеПоля;
Иначе
УстанавливаемоеЗначениеПоля = ВыполнитьПриведениеЗначения(Колонка, ЗначениеПоля);
КонецЕсли;
Рефлектор.УстановитьСвойство(Сущность, Колонка.ИмяПоля, УстанавливаемоеЗначениеПоля);
КонецПроцедуры
Процедура УстановитьЗначениеПодчиненнойТаблицыВПоле(Сущность, ИмяПоля, ЗначениеПоля) Экспорт
Рефлектор.УстановитьСвойство(Сущность, ИмяПоля, ЗначениеПоля);
КонецПроцедуры
Функция ПривестиЗначениеПоля(ЗначениеПоля, ИмяПоля) Экспорт
Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");
Возврат ВыполнитьПриведениеЗначения(Колонка, ЗначениеПоля);
КонецФункции
Функция ПолучитьЗначениеПоля(Сущность, ИмяПоля) Экспорт
ЗначениеПоля = Рефлектор.ПолучитьСвойство(Сущность, ИмяПоля);
Возврат ЗначениеПоля;
КонецФункции
Процедура ЗаполнитьКолонки()
ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");
ОписаниеТиповБулево = Новый ОписаниеТипов("Булево");
Колонки = Новый ТаблицаЗначений;
Колонки.Колонки.Добавить("ИмяПоля", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ИмяКолонки", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ТипКолонки", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ГенерируемоеЗначение", ОписаниеТиповБулево);
Колонки.Колонки.Добавить("Идентификатор", ОписаниеТиповБулево);
Колонки.Колонки.Добавить("ТипСсылки");
РефлекторОбъекта = Новый РефлекторОбъекта(ТипСущности);
МетодСущность = РефлекторОбъекта.ПолучитьТаблицуМетодов("Сущность", Ложь)[0];
АннотацияСущность = РаботаСАннотациями.НайтиАннотацию(МетодСущность.Аннотации, "Сущность");
ИмяТаблицы = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияСущность, "ИмяТаблицы", Строка(ТипСущности));
ИсточникиДанных = Новый ФиксированныйМассив(
РаботаСАннотациями.ПолучитьЗначенияПараметровАннотации(АннотацияСущность, "ИсточникДанных")
);
ТаблицаСвойств = РефлекторОбъекта.ПолучитьТаблицуСвойств();
Для Каждого Свойство Из ТаблицаСвойств Цикл
Аннотации = Свойство.Аннотации;
АннотацияПодчиненнаяТаблица = РаботаСАннотациями.НайтиАннотацию(Аннотации, "ПодчиненнаяТаблица");
Если АннотацияПодчиненнаяТаблица <> Неопределено Тогда
Продолжить;
КонецЕсли;
ДанныеОКолонке = НовыйДанныеОКолонке();
ДанныеОКолонке.ИмяПоля = Свойство.Имя;
АннотацияКолонка = РаботаСАннотациями.НайтиАннотацию(Аннотации, "Колонка");
ДанныеОКолонке.ИмяКолонки = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияКолонка, "Имя", ДанныеОКолонке.ИмяПоля);
ДанныеОКолонке.ТипКолонки = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияКолонка, "Тип", ТипыКолонок.Строка);
ТипСсылки = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияКолонка, "ТипСсылки", Неопределено, Истина);
ДанныеОКолонке.ТипСсылки = ?(ТипСсылки = Неопределено, Неопределено, Тип(ТипСсылки));
Если РаботаСАннотациями.НайтиАннотацию(Аннотации, "Идентификатор") <> Неопределено Тогда
ДанныеОКолонке.Идентификатор = Истина;
Идентификатор = ДанныеОКолонке;
КонецЕсли;
Если РаботаСАннотациями.НайтиАннотацию(Аннотации, "ГенерируемоеЗначение") <> Неопределено Тогда
ДанныеОКолонке.ГенерируемоеЗначение = Истина;
КонецЕсли;
ЗаполнитьЗначенияСвойств(Колонки.Добавить(), ДанныеОКолонке);
КонецЦикла;
КонецПроцедуры
Процедура ЗаполнитьПодчиненныеТаблицы()
ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");
ОписаниеТиповБулево = Новый ОписаниеТипов("Булево");
ПодчиненныеТаблицы = Новый ТаблицаЗначений;
ПодчиненныеТаблицы.Колонки.Добавить("ИмяПоля", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ИмяТаблицы", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ТипТаблицы", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ТипЭлемента");
ПодчиненныеТаблицы.Колонки.Добавить("КаскадноеЧтение", ОписаниеТиповБулево);
РефлекторОбъекта = Новый РефлекторОбъекта(ТипСущности);
ТаблицаСвойств = РефлекторОбъекта.ПолучитьТаблицуСвойств("ПодчиненнаяТаблица");
Для Каждого Свойство Из ТаблицаСвойств Цикл
ДанныеОПодчиненнойТаблице = НовыйДанныеОПодчиненнойТаблице();
ДанныеОПодчиненнойТаблице.ИмяПоля = Свойство.Имя;
Аннотации = Свойство.Аннотации;
АннотацияПодчиненнаяТаблица = РаботаСАннотациями.НайтиАннотацию(Аннотации, "ПодчиненнаяТаблица");
ИмяТаблицыПоУмолчанию = СтрШаблон(
"%1_%2",
Строка(ТипСущности),
ДанныеОПодчиненнойТаблице.ИмяПоля
);
ДанныеОПодчиненнойТаблице.ИмяТаблицы = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияПодчиненнаяТаблица, "ИмяТаблицы", ИмяТаблицыПоУмолчанию);
ДанныеОПодчиненнойТаблице.ТипТаблицы = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияПодчиненнаяТаблица, "Тип", Неопределено, Истина);
ТипЭлемента = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияПодчиненнаяТаблица, "ТипЭлемента", Неопределено, Истина);
ДанныеОПодчиненнойТаблице.ТипЭлемента = ?(ТипЭлемента = Неопределено, Неопределено, Тип(ТипЭлемента));
ДанныеОПодчиненнойТаблице.КаскадноеЧтение = РаботаСАннотациями.ПолучитьЗначениеПараметраАннотации(АннотацияПодчиненнаяТаблица, "КаскадноеЧтение", Ложь);
ЗаполнитьЗначенияСвойств(ПодчиненныеТаблицы.Добавить(), ДанныеОПодчиненнойТаблице);
КонецЦикла;
КонецПроцедуры
Функция НовыйДанныеОКолонке()
ДанныеОКолонке = Новый Структура;
ДанныеОКолонке.Вставить("ИмяПоля", "");
ДанныеОКолонке.Вставить("ИмяКолонки", "");
ДанныеОКолонке.Вставить("ТипКолонки", "");
ДанныеОКолонке.Вставить("ГенерируемоеЗначение", Ложь);
ДанныеОКолонке.Вставить("Идентификатор", Ложь);
ДанныеОКолонке.Вставить("ТипСсылки");
Возврат ДанныеОКолонке;
КонецФункции
Функция НовыйДанныеОПодчиненнойТаблице()
ДанныеОПодчиненнойТаблице = Новый Структура;
ДанныеОПодчиненнойТаблице.Вставить("ИмяПоля", "");
ДанныеОПодчиненнойТаблице.Вставить("ИмяТаблицы", "");
ДанныеОПодчиненнойТаблице.Вставить("ТипТаблицы");
ДанныеОПодчиненнойТаблице.Вставить("ТипЭлемента");
ДанныеОПодчиненнойТаблице.Вставить("КаскадноеЧтение", Ложь);
Возврат ДанныеОПодчиненнойТаблице;
КонецФункции
Функция СоответствиеТиповМоделиОписанийТипов()
Перем Карта;
Карта = Новый Соответствие;
Карта.Вставить(ТипыКолонок.Целое, Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла( , 0)));
Карта.Вставить(ТипыКолонок.Дробное, Новый ОписаниеТипов("Число"));
Карта.Вставить(ТипыКолонок.Булево, Новый ОписаниеТипов("Булево"));
Карта.Вставить(ТипыКолонок.Строка, Новый ОписаниеТипов("Строка"));
Карта.Вставить(ТипыКолонок.Дата, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));
Карта.Вставить(ТипыКолонок.Время, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Время)));
Карта.Вставить(ТипыКолонок.ДатаВремя, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)));
Карта.Вставить(ТипыКолонок.ДвоичныеДанные, Новый ОписаниеТипов("ДвоичныеДанные"));
Возврат Карта;
КонецФункции
Функция ВыполнитьПриведениеЗначения(Колонка, Значение)
// Если тип колонки и значение - двоичные данные, то приводить не нужно.
// по крайней мере пока oscript не научится приводить тип двоичных данных
// https://github.com/EvilBeaver/OneScript/issues/1327
Если Колонка.ТипКолонки = ТипыКолонок.ДвоичныеДанные
И ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
Возврат Значение;
КонецЕсли;
ОбработанноеЗначение = Значение;
КартаОписанийТипов = СоответствиеТиповМоделиОписанийТипов();
ОписаниеТипов = КартаОписанийТипов.Получить(Колонка.ТипКолонки);
Если ОписаниеТипов = Неопределено Тогда
ВызватьИсключение "Неизвестный тип колонки " + Колонка.ИмяКолонки;
КонецЕсли;
// Некоторые коннекторы возвращают дату/время в виде строки в формате ISO.
Если ТипЗнч(ОбработанноеЗначение) = Тип("Строка") Тогда
Если Колонка.ТипКолонки = ТипыКолонок.Дата Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.Дата);
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.ДатаВремя Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.ДатаВремя);
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.Время Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.Время);
Иначе
// no-op
КонецЕсли;
КонецЕсли;
Возврат ОписаниеТипов.ПривестиЗначение(ОбработанноеЗначение);
КонецФункции