forked from nixel2007/entity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ОбъектМодели.os
405 lines (312 loc) · 24.6 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
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
#Использовать reflector
#Использовать strings
Перем ТипСущности;
Перем ИмяТаблицы;
Перем Колонки;
Перем ПодчиненныеТаблицы;
// TODO: Первичный ключ из нескольких полей?
Перем Идентификатор;
Перем МодельДанных;
Перем Рефлектор;
Процедура ПриСозданииОбъекта(ПТипСущности, ПМодельДанных)
МодельДанных = ПМодельДанных;
ТипСущности = ПТипСущности;
ЗаполнитьКолонки();
ЗаполнитьПодчиненныеТаблицы();
Рефлектор = Новый Рефлектор;
КонецПроцедуры
Функция ИмяТаблицы() Экспорт
Возврат ИмяТаблицы;
КонецФункции
Функция Колонки() Экспорт
Возврат Колонки.Скопировать();
КонецФункции
Функция ПодчиненныеТаблицы() Экспорт
Возврат ПодчиненныеТаблицы.Скопировать();
КонецФункции
// @internal
// TODO: вынести отсюда. Возможно стоит разработать отдельный служебный билдер Объекта модели,
// вытащив заполнение из конструктора в этот билдер, а в конструктор передавать уже готовые для сохранения
// в объект данные.
//
Функция Служебный_Колонки() Экспорт
Возврат Колонки;
КонецФункции
// @internal
Процедура Служебный_ИмяТаблицы(ПИмяТаблицы) Экспорт
ИмяТаблицы = ПИмяТаблицы;
КонецПроцедуры
Функция Идентификатор() Экспорт
Возврат Новый ФиксированнаяСтруктура(Идентификатор);
КонецФункции
Функция МодельДанных() Экспорт
Возврат МодельДанных;
КонецФункции
Функция ТипСущности() Экспорт
Возврат ТипСущности;
КонецФункции
Функция ПолучитьЗначениеИдентификатора(Сущность) Экспорт
ЗначениеИдентификатора = ПолучитьЗначениеПоля(Сущность, Идентификатор().ИмяПоля);
Возврат ЗначениеИдентификатора;
КонецФункции
Функция ПолучитьПриведенноеЗначениеПоля(Сущность, ИмяПоля) Экспорт
ЗначениеПоля = ПолучитьЗначениеПоля(Сущность, ИмяПоля);
Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");
Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
ОбъектМоделиСсылки = МодельДанных.Получить(Колонка.ТипСсылки);
Если ЗначениеПоля = Неопределено Тогда
ЗначениеПоля = ОбъектМоделиСсылки.ПривестиЗначениеПоля(ЗначениеПоля, ОбъектМоделиСсылки.Идентификатор().ИмяПоля);
Иначе
ЗначениеПоля = ОбъектМоделиСсылки.ПолучитьЗначениеИдентификатора(ЗначениеПоля);
КонецЕсли;
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.ДвоичныеДанные Тогда
// Просто ничего не делаем, все работает само
Иначе
ЗначениеПоля = ПривестиЗначениеПоля(ЗначениеПоля, ИмяПоля);
КонецЕсли;
Возврат ЗначениеПоля;
КонецФункции
Процедура УстановитьЗначениеКолонкиВПоле(Сущность, ИмяКолонки, ЗначениеПоля) Экспорт
Колонка = Колонки().Найти(ИмяКолонки, "ИмяКолонки");
Если Колонка.ТипКолонки = ТипыКолонок.Ссылка Тогда
УстанавливаемоеЗначениеПоля = ЗначениеПоля;
Иначе
УстанавливаемоеЗначениеПоля = ВыполнитьПриведениеЗначения(Колонка, ЗначениеПоля);
КонецЕсли;
Рефлектор.УстановитьСвойство(Сущность, Колонка.ИмяПоля, УстанавливаемоеЗначениеПоля);
КонецПроцедуры
Процедура УстановитьЗначениеПодчиненнойТаблицыВПоле(Сущность, ИмяПоля, ЗначениеПоля) Экспорт
Рефлектор.УстановитьСвойство(Сущность, ИмяПоля, ЗначениеПоля);
КонецПроцедуры
Функция ПривестиЗначениеПоля(ЗначениеПоля, ИмяПоля) Экспорт
Колонка = Колонки().Найти(ИмяПоля, "ИмяПоля");
Возврат ВыполнитьПриведениеЗначения(Колонка, ЗначениеПоля);
КонецФункции
Функция ПолучитьЗначениеПоля(Сущность, ИмяПоля) Экспорт
ЗначениеПоля = Рефлектор.ПолучитьСвойство(Сущность, ИмяПоля);
Возврат ЗначениеПоля;
КонецФункции
Процедура ЗаполнитьКолонки()
ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");
ОписаниеТиповБулево = Новый ОписаниеТипов("Булево");
ИмяТаблицы = "";
Колонки = Новый ТаблицаЗначений;
Колонки.Колонки.Добавить("ИмяПоля", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ИмяКолонки", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ТипКолонки", ОписаниеТиповСтрока);
Колонки.Колонки.Добавить("ГенерируемоеЗначение", ОписаниеТиповБулево);
Колонки.Колонки.Добавить("Идентификатор", ОписаниеТиповБулево);
Колонки.Колонки.Добавить("ТипСсылки");
РефлекторОбъекта = Новый РефлекторОбъекта(ТипСущности);
МетодСущность = РефлекторОбъекта.ПолучитьТаблицуМетодов("Сущность", Ложь)[0];
АннотацияСущность = МетодСущность.Аннотации.Найти("сущность", "Имя");
ПараметрИмяТаблицы = АннотацияСущность.Параметры.Найти("ИмяТаблицы", "Имя");
ИмяТаблицы = ?(ПараметрИмяТаблицы = Неопределено, Строка(ТипСущности), ПараметрИмяТаблицы.Значение);
ТаблицаСвойств = РефлекторОбъекта.ПолучитьТаблицуСвойств();
Для Каждого Свойство Из ТаблицаСвойств Цикл
Аннотации = Свойство.Аннотации;
АннотацияПодчиненнаяТаблица = Аннотации.Найти("ПодчиненнаяТаблица", "Имя");
Если АннотацияПодчиненнаяТаблица <> Неопределено Тогда
Продолжить;
КонецЕсли;
ДанныеОКолонке = НовыйДанныеОКолонке();
ДанныеОКолонке.ИмяПоля = Свойство.Имя;
АннотацияКолонка = Аннотации.Найти("Колонка", "Имя");
ЗаполнитьИмяКолонки(ДанныеОКолонке, АннотацияКолонка);
ЗаполнитьТипКолонки(ДанныеОКолонке, АннотацияКолонка);
ЗаполнитьТипСсылки(ДанныеОКолонке, АннотацияКолонка);
Если Аннотации.Найти("Идентификатор", "Имя") <> Неопределено Тогда
ДанныеОКолонке.Идентификатор = Истина;
Идентификатор = ДанныеОКолонке;
КонецЕсли;
Если Аннотации.Найти("ГенерируемоеЗначение", "Имя") <> Неопределено Тогда
ДанныеОКолонке.ГенерируемоеЗначение = Истина;
КонецЕсли;
ЗаполнитьЗначенияСвойств(Колонки.Добавить(), ДанныеОКолонке);
КонецЦикла;
КонецПроцедуры
Процедура ЗаполнитьПодчиненныеТаблицы()
ОписаниеТиповСтрока = Новый ОписаниеТипов("Строка");
ОписаниеТиповБулево = Новый ОписаниеТипов("Булево");
ПодчиненныеТаблицы = Новый ТаблицаЗначений;
ПодчиненныеТаблицы.Колонки.Добавить("ИмяПоля", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ИмяТаблицы", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ТипТаблицы", ОписаниеТиповСтрока);
ПодчиненныеТаблицы.Колонки.Добавить("ТипЭлемента");
ПодчиненныеТаблицы.Колонки.Добавить("КаскадноеЧтение", ОписаниеТиповБулево);
РефлекторОбъекта = Новый РефлекторОбъекта(ТипСущности);
ТаблицаСвойств = РефлекторОбъекта.ПолучитьТаблицуСвойств("ПодчиненнаяТаблица");
Для Каждого Свойство Из ТаблицаСвойств Цикл
ДанныеОПодчиненнойТаблице = НовыйДанныеОПодчиненнойТаблице();
ДанныеОПодчиненнойТаблице.ИмяПоля = Свойство.Имя;
Аннотации = Свойство.Аннотации;
АннотацияПодчиненнаяТаблица = Аннотации.Найти("ПодчиненнаяТаблица", "Имя");
ЗаполнитьИмяПодчиненнойТаблицы(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица);
ЗаполнитьТипТаблицы(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица);
ЗаполнитьТипЭлемента(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица);
ЗаполнитьКаскадноеЧтение(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица);
ЗаполнитьЗначенияСвойств(ПодчиненныеТаблицы.Добавить(), ДанныеОПодчиненнойТаблице);
КонецЦикла;
КонецПроцедуры
Функция НовыйДанныеОКолонке()
ДанныеОКолонке = Новый Структура;
ДанныеОКолонке.Вставить("ИмяПоля", "");
ДанныеОКолонке.Вставить("ИмяКолонки", "");
ДанныеОКолонке.Вставить("ТипКолонки", "");
ДанныеОКолонке.Вставить("ГенерируемоеЗначение", Ложь);
ДанныеОКолонке.Вставить("Идентификатор", Ложь);
ДанныеОКолонке.Вставить("ТипСсылки");
Возврат ДанныеОКолонке;
КонецФункции
Функция НовыйДанныеОПодчиненнойТаблице()
ДанныеОПодчиненнойТаблице = Новый Структура;
ДанныеОПодчиненнойТаблице.Вставить("ИмяПоля", "");
ДанныеОПодчиненнойТаблице.Вставить("ИмяТаблицы", "");
ДанныеОПодчиненнойТаблице.Вставить("ТипТаблицы");
ДанныеОПодчиненнойТаблице.Вставить("ТипЭлемента");
ДанныеОПодчиненнойТаблице.Вставить("КаскадноеЧтение", Ложь);
Возврат ДанныеОПодчиненнойТаблице;
КонецФункции
Процедура ЗаполнитьИмяКолонки(ДанныеОКолонке, АннотацияКолонка)
ЗначениеПоУмолчанию = ДанныеОКолонке.ИмяПоля;
Если АннотацияКолонка = Неопределено ИЛИ АннотацияКолонка.Параметры = Неопределено Тогда
ИмяКолонки = ЗначениеПоУмолчанию;
Иначе
ПараметрИмяКолонки = АннотацияКолонка.Параметры.Найти("Имя", "Имя");
Если ПараметрИмяКолонки = Неопределено ИЛИ ПараметрИмяКолонки.Значение = Неопределено Тогда
ИмяКолонки = ЗначениеПоУмолчанию;
Иначе
ИмяКолонки = ПараметрИмяКолонки.Значение;
КонецЕсли;
КонецЕсли;
ДанныеОКолонке.ИмяКолонки = ИмяКолонки;
КонецПроцедуры
Процедура ЗаполнитьИмяПодчиненнойТаблицы(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица)
ПараметрИмяТаблицы = АннотацияПодчиненнаяТаблица.Параметры.Найти("ИмяТаблицы", "Имя");
Если ПараметрИмяТаблицы = Неопределено Тогда
ДанныеОПодчиненнойТаблице.ИмяТаблицы = СтрШаблон(
"%1_%2",
Строка(ТипСущности),
ДанныеОПодчиненнойТаблице.ИмяПоля
);
Иначе
ДанныеОПодчиненнойТаблице.ИмяТаблицы = ПараметрИмяТаблицы.Значение;
КонецЕсли;
КонецПроцедуры
Процедура ЗаполнитьТипКолонки(ДанныеОКолонке, АннотацияКолонка)
ЗначениеПоУмолчанию = ТипыКолонок.Строка;
Если АннотацияКолонка = Неопределено ИЛИ АннотацияКолонка.Параметры = Неопределено Тогда
ТипКолонки = ЗначениеПоУмолчанию;
Иначе
ПараметрТипКолонки = АннотацияКолонка.Параметры.Найти("Тип", "Имя");
Если ПараметрТипКолонки = Неопределено ИЛИ ПараметрТипКолонки.Значение = Неопределено Тогда
ТипКолонки = ЗначениеПоУмолчанию;
Иначе
ТипКолонки = ПараметрТипКолонки.Значение;
КонецЕсли;
КонецЕсли;
ДанныеОКолонке.ТипКолонки = ТипКолонки;
КонецПроцедуры
Процедура ЗаполнитьТипТаблицы(ДанныеОПодчиненнойТаблице, АннотацияПодчиненнаяТаблица)
ЗначениеПоУмолчанию = Неопределено;
Если АннотацияПодчиненнаяТаблица = Неопределено ИЛИ АннотацияПодчиненнаяТаблица.Параметры = Неопределено Тогда
ТипКолонки = ЗначениеПоУмолчанию;
Иначе
ПараметрТипКолонки = АннотацияПодчиненнаяТаблица.Параметры.Найти("Тип", "Имя");
Если ПараметрТипКолонки = Неопределено ИЛИ ПараметрТипКолонки.Значение = Неопределено Тогда
ТипКолонки = ЗначениеПоУмолчанию;
Иначе
ТипКолонки = ПараметрТипКолонки.Значение;
КонецЕсли;
КонецЕсли;
ДанныеОПодчиненнойТаблице.ТипТаблицы = ТипКолонки;
КонецПроцедуры
Процедура ЗаполнитьТипСсылки(ДанныеОКолонке, АннотацияКолонка)
ЗначениеПоУмолчанию = Неопределено;
Если АннотацияКолонка = Неопределено ИЛИ АннотацияКолонка.Параметры = Неопределено Тогда
ТипСсылки = ЗначениеПоУмолчанию;
ИначеЕсли ДанныеОКолонке.ТипКолонки <> ТипыКолонок.Ссылка Тогда
ТипСсылки = ЗначениеПоУмолчанию;
Иначе
ПараметрТипСсылки = АннотацияКолонка.Параметры.Найти("ТипСсылки", "Имя");
Если ПараметрТипСсылки = Неопределено Тогда
ТипСсылки = ЗначениеПоУмолчанию;
Иначе
ТипСсылки = Тип(ПараметрТипСсылки.Значение);
КонецЕсли;
КонецЕсли;
ДанныеОКолонке.ТипСсылки = ТипСсылки;
КонецПроцедуры
Процедура ЗаполнитьТипЭлемента(ДанныеОКолонке, АннотацияКолонка)
ЗначениеПоУмолчанию = Неопределено;
// TODO:
// ТипыКолонокСЭлементами.Добавить(ТипыКолонок.Таблица);
Если АннотацияКолонка = Неопределено ИЛИ АннотацияКолонка.Параметры = Неопределено Тогда
ТипЭлемента = ЗначениеПоУмолчанию;
Иначе
ПараметрТипЭлемента = АннотацияКолонка.Параметры.Найти("ТипЭлемента", "Имя");
Если ПараметрТипЭлемента = Неопределено Тогда
ТипЭлемента = ЗначениеПоУмолчанию;
Иначе
ТипЭлемента = Тип(ПараметрТипЭлемента.Значение);
КонецЕсли;
КонецЕсли;
ДанныеОКолонке.ТипЭлемента = ТипЭлемента;
КонецПроцедуры
Процедура ЗаполнитьКаскадноеЧтение(ДанныеОКолонке, АннотацияКолонка)
ЗначениеПоУмолчанию = Ложь;
Если АннотацияКолонка = Неопределено ИЛИ АннотацияКолонка.Параметры = Неопределено Тогда
КаскадноеЧтение = ЗначениеПоУмолчанию;
ИначеЕсли НЕ ТипыКолонок.ЭтоСсылочныйТип(ДанныеОКолонке.ТипЭлемента) Тогда
КаскадноеЧтение = ЗначениеПоУмолчанию;
Иначе
ПараметрКаскадноеЧтение = АннотацияКолонка.Параметры.Найти("КаскадноеЧтение", "Имя");
Если ПараметрКаскадноеЧтение = Неопределено Тогда
КаскадноеЧтение = ЗначениеПоУмолчанию;
Иначе
КаскадноеЧтение = ПараметрКаскадноеЧтение.Значение;
КонецЕсли;
КонецЕсли;
ДанныеОКолонке.КаскадноеЧтение = КаскадноеЧтение;
КонецПроцедуры
Функция СоответствиеТиповМоделиОписанийТипов()
Перем Карта;
Карта = Новый Соответствие;
Карта.Вставить(ТипыКолонок.Целое, Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла( , 0)));
Карта.Вставить(ТипыКолонок.Дробное, Новый ОписаниеТипов("Число"));
Карта.Вставить(ТипыКолонок.Булево, Новый ОписаниеТипов("Булево"));
Карта.Вставить(ТипыКолонок.Строка, Новый ОписаниеТипов("Строка"));
Карта.Вставить(ТипыКолонок.Дата, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Дата)));
Карта.Вставить(ТипыКолонок.Время, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.Время)));
Карта.Вставить(ТипыКолонок.ДатаВремя, Новый ОписаниеТипов("Дата", , , Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)));
Карта.Вставить(ТипыКолонок.ДвоичныеДанные, Новый ОписаниеТипов("ДвоичныеДанные"));
Возврат Карта;
КонецФункции
Функция ВыполнитьПриведениеЗначения(Колонка, Значение)
// Если тип колонки и значение - двоичные данные, то приводить не нужно.
// по крайней мере пока oscript не научится приводить тип двоичных данных
// https://github.com/EvilBeaver/OneScript/issues/1327
Если Колонка.ТипКолонки = ТипыКолонок.ДвоичныеДанные
И ТипЗнч(Значение) = Тип("ДвоичныеДанные") Тогда
Возврат Значение;
КонецЕсли;
ОбработанноеЗначение = Значение;
КартаОписанийТипов = СоответствиеТиповМоделиОписанийТипов();
ОписаниеТипов = КартаОписанийТипов.Получить(Колонка.ТипКолонки);
Если ОписаниеТипов = Неопределено Тогда
ВызватьИсключение "Неизвестный тип колонки " + Колонка.ИмяКолонки;
КонецЕсли;
// Некоторые коннекторы возвращают дату/время в виде строки в формате ISO.
Если ТипЗнч(ОбработанноеЗначение) = Тип("Строка") Тогда
Если Колонка.ТипКолонки = ТипыКолонок.Дата Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.Дата);
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.ДатаВремя Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.ДатаВремя);
ИначеЕсли Колонка.ТипКолонки = ТипыКолонок.Время Тогда
ОбработанноеЗначение = СтроковыеФункции.СтрокаВДату(ОбработанноеЗначение, ЧастиДаты.Время);
Иначе
// no-op
КонецЕсли;
КонецЕсли;
Возврат ОписаниеТипов.ПривестиЗначение(ОбработанноеЗначение);
КонецФункции