letopis 0.13.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +98 -0
- package/README.md +362 -199
- package/dist/chain.d.ts +44 -16
- package/dist/chain.js +197 -26
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/schema.js +96 -4
- package/dist/sql.d.ts +23 -3
- package/dist/sql.js +71 -24
- package/dist/types.d.ts +40 -4
- package/dist/uuid.d.ts +6 -0
- package/dist/uuid.js +32 -0
- package/dist/write.d.ts +12 -5
- package/dist/write.js +213 -95
- package/package.json +1 -1
- package/sql/ddl.sql +53 -11
- package/sql/seed.booking.sql +21 -16
package/sql/seed.booking.sql
CHANGED
|
@@ -1,64 +1,69 @@
|
|
|
1
1
|
-- =============================================================================
|
|
2
2
|
-- Сид таблицы Schema из schema.booking.v2.json (источник правды — JSON).
|
|
3
|
-
-- Файл
|
|
3
|
+
-- Файл сгенерирован: node lib/scripts/gen-seed.mjs — не редактировать вручную.
|
|
4
|
+
-- Идемпотентен (ON CONFLICT). Концы связей — Schema.links v2 (JSON-объекты в text[]).
|
|
4
5
|
-- =============================================================================
|
|
5
6
|
|
|
6
7
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
7
|
-
('entity', 'Entity', 'Сущность', 'HUB', NULL, '{"id":"
|
|
8
|
+
('entity', 'Entity', 'Сущность', 'HUB', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"description":"Абстрактный корень всех сущностей"}'::jsonb, '[]'::jsonb, 100, ARRAY['Entity']::text[])
|
|
8
9
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
9
10
|
|
|
10
11
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
11
|
-
('entity', 'Org', 'Организация', 'HUB', 'Entity', '{"
|
|
12
|
+
('entity', 'Org', 'Организация', 'HUB', 'Entity', '{"name":"string","timezone":{"type":"string","default":"Europe/Moscow"},"address":"string|optional","phone":"string|optional","active":{"type":"boolean","default":true},"settings":{"type":"object","optional":true,"strict":true,"props":{"booking":{"type":"object","optional":true,"strict":true,"props":{"deposit":{"type":"object","optional":true,"strict":true,"props":{"amount":"number|integer|min:0|default:0","currency":{"type":"enum","values":["RUB","USD","EUR","AED"],"default":"RUB"}}},"autoconfirm":"boolean|default:false"}}}}}'::jsonb, '{"abstract":false,"description":"Организация / точка / филиал — владелец каталога и расписаний; settings — вложенные настройки (пример структуры глубины 4)"}'::jsonb, '[]'::jsonb, 200, ARRAY['Org', 'Entity']::text[])
|
|
12
13
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
13
14
|
|
|
14
15
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
15
|
-
('entity', 'Staff', 'Сотрудник', 'HUB', 'Entity', '{"
|
|
16
|
+
('entity', 'Staff', 'Сотрудник', 'HUB', 'Entity', '{"name":"string","roles":{"type":"array","items":{"type":"enum","values":["owner","administrator","manager","master"]},"default":["master"]},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Человек: роли совмещаются (owner+master). Бронируемый ⇔ master ∈ roles. Владелец = первый сотрудник с owner."}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 300, ARRAY['Staff', 'Entity']::text[])
|
|
16
17
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
17
18
|
|
|
18
19
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
19
|
-
('entity', 'Folder', 'Папка', 'HUB', 'Entity', '{"
|
|
20
|
+
('entity', 'Folder', 'Папка', 'HUB', 'Entity', '{"name":"string","kind":{"type":"enum","values":["services","masters"],"default":"services"}}'::jsonb, '{"abstract":false,"description":"Папка-категория; вложенность — ссылкой на родительскую Папку в links"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 400, ARRAY['Folder', 'Entity']::text[])
|
|
20
21
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
21
22
|
|
|
22
23
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
23
|
-
('entity', 'Service', 'Услуга', 'HUB', 'Entity', '{"id":"uuid","name":"string","description":"string|optional","duration":"number|integer|positive","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","default":{"RUB":0}},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Услуга: длительность (мин) + цена; занимает столько подряд окон, сколько покрывает duration"}'::jsonb, '{"Org","Folder"}'::
|
|
24
|
+
('entity', 'Service', 'Услуга', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Org","name"]},"name":"string","description":"string|optional","duration":"number|integer|positive","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","default":{"RUB":0}},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Услуга: длительность (мин) + цена; занимает столько подряд окон, сколько покрывает duration"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 500, ARRAY['Service', 'Entity']::text[])
|
|
24
25
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
25
26
|
|
|
26
27
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
27
|
-
('entity', 'Complex', 'Комплекс', 'HUB', 'Entity', '{"id":"uuid","name":"string","description":"string|optional","duration":"number|integer|positive","discount":"number|integer|default:0","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","optional":true}}'::jsonb, '{"abstract":false,"description":"Комплекс: собственный duration; состав — позиция(Комплекс→Услуга); свободный текст цены — в description"}'::jsonb, '{"Org","Folder"}'::
|
|
28
|
+
('entity', 'Complex', 'Комплекс', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Org","name"]},"name":"string","description":"string|optional","duration":"number|integer|positive","discount":"number|integer|default:0","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","optional":true}}'::jsonb, '{"abstract":false,"description":"Комплекс: собственный duration; состав — позиция(Комплекс→Услуга); свободный текст цены — в description"}'::jsonb, '[{"class":"Org","cardinality":1},{"class":"Folder","optional":true,"cardinality":1}]'::jsonb, 600, ARRAY['Complex', 'Entity']::text[])
|
|
28
29
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
29
30
|
|
|
30
31
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
31
|
-
('entity', 'Customer', 'Клиент', 'HUB', 'Entity', '{"
|
|
32
|
+
('entity', 'Customer', 'Клиент', 'HUB', 'Entity', '{"name":"string|optional","contact":"string|optional","language":{"type":"enum","values":["ru","en"],"default":"ru"},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Клиент — записывается на услуги"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 700, ARRAY['Customer', 'Entity']::text[])
|
|
32
33
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
33
34
|
|
|
34
35
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
35
|
-
('entity', 'Schedule', 'Расписание', 'HUB', 'Entity', '{"
|
|
36
|
+
('entity', 'Schedule', 'Расписание', 'HUB', 'Entity', '{"start":{"type":"date","convert":true},"end":{"type":"date","convert":true},"active":{"type":"boolean","default":true}}'::jsonb, '{"abstract":false,"description":"Расписание — период организации, содержит непересекающиеся Окна (инвариант проверяет приложение)"}'::jsonb, '[{"class":"Org","cardinality":1}]'::jsonb, 800, ARRAY['Schedule', 'Entity']::text[])
|
|
36
37
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
37
38
|
|
|
38
39
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
39
|
-
('entity', 'Slot', 'Окно', 'HUB', 'Entity', '{"id":"uuid","start":{"type":"date","convert":true},"end":{"type":"date","convert":true}}'::jsonb, '{"abstract":false,"description":"Окно — общий таймлайн произвольной длины внутри Расписания; статуса нет — занятость мастера хранит LINK занятость"}'::jsonb, '{"Schedule"}'::
|
|
40
|
+
('entity', 'Slot', 'Окно', 'HUB', 'Entity', '{"id":{"type":"uuid","generate":5,"from":["Schedule","start"]},"start":{"type":"date","convert":true},"end":{"type":"date","convert":true}}'::jsonb, '{"abstract":false,"description":"Окно — общий таймлайн произвольной длины внутри Расписания; статуса нет — занятость мастера хранит LINK занятость"}'::jsonb, '[{"class":"Schedule","cardinality":1}]'::jsonb, 900, ARRAY['Slot', 'Entity']::text[])
|
|
40
41
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
41
42
|
|
|
42
43
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
43
|
-
('entity', 'Booking', 'Запись', 'HUB', 'Entity', '{"
|
|
44
|
+
('entity', 'Booking', 'Запись', 'HUB', 'Entity', '{"status":{"type":"enum","values":["created","confirmed","completed","cancelled","no_show"],"default":"created"},"source":{"type":"enum","values":["online","web","admin","telegram"],"default":"online"},"comment":"string|optional","total":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","default":{"RUB":0}}}'::jsonb, '{"abstract":false,"description":"Запись клиента. Без мастера (мульти-мастер): мастера — на занятости/позиции. Ручная бронь по имени: без Customer, имя в comment. Дата приёма = start первого окна брони. history: полный аудит версиями"}'::jsonb, '[{"class":"Customer","optional":true,"cardinality":1}]'::jsonb, 1000, ARRAY['Booking', 'Entity']::text[])
|
|
44
45
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
45
46
|
|
|
46
47
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
47
|
-
('entity', 'link', 'связь', 'LINK', NULL, '{"id":"
|
|
48
|
+
('entity', 'link', 'связь', 'LINK', NULL, '{"id":{"type":"uuid","generate":7}}'::jsonb, '{"abstract":true,"description":"Абстрактная связь; концы объявляются потомками в links (Schema.links v2: объекты-концы)"}'::jsonb, '[]'::jsonb, 100, ARRAY['link']::text[])
|
|
48
49
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
49
50
|
|
|
50
51
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
51
|
-
('entity', 'item', 'позиция', 'LINK', 'link', '{"
|
|
52
|
+
('entity', 'item', 'позиция', 'LINK', 'link', '{"qty":"number|integer|min:1|default:1","price":{"type":"record","key":{"type":"enum","values":["RUB","USD","EUR","AED"]},"value":"number|integer|min:0","optional":true}}'::jsonb, '{"abstract":false,"description":"Позиция заказа: Запись × предмет [Услуга|Комплекс] × Сотрудник?. Снимок цены в price. Состав комплекса — отдельный LINK «состав» (compo)"}'::jsonb, '[{"classes":["Booking"],"cardinality":1},{"classes":["Service","Complex"],"cardinality":1},{"class":"Staff","optional":true,"cardinality":1}]'::jsonb, 200, ARRAY['item', 'link']::text[])
|
|
52
53
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
53
54
|
|
|
54
55
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
55
|
-
('entity', '
|
|
56
|
+
('entity', 'compo', 'состав', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Complex","Service"]},"qty":"number|integer|min:1|default:1"}'::jsonb, '{"abstract":false,"description":"Состав комплекса: Комплекс ← Услуга (+qty). Раньше жил на позиции — вынесен отдельным классом"}'::jsonb, '[{"class":"Complex","cardinality":1},{"class":"Service","cardinality":1}]'::jsonb, 250, ARRAY['compo', 'link']::text[])
|
|
56
57
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
57
58
|
|
|
58
59
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
59
|
-
('entity', '
|
|
60
|
+
('entity', 'skill', 'навык', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Staff","Service|Complex"]}}'::jsonb, '{"abstract":false,"description":"Навык: Сотрудник умеет (Услуга|Комплекс); при записи проверяется"}'::jsonb, '[{"class":"Staff","cardinality":1},{"classes":["Service","Complex"],"cardinality":1}]'::jsonb, 300, ARRAY['skill', 'link']::text[])
|
|
60
61
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
61
62
|
|
|
62
63
|
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
63
|
-
('entity', '
|
|
64
|
+
('entity', 'shift', 'смена', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Schedule","Staff"]}}'::jsonb, '{"abstract":false,"description":"Ростер: сотрудник работает в расписании ⇒ по умолчанию доступен во всех его окнах"}'::jsonb, '[{"class":"Schedule","cardinality":1},{"class":"Staff","cardinality":1}]'::jsonb, 400, ARRAY['shift', 'link']::text[])
|
|
65
|
+
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|
|
66
|
+
|
|
67
|
+
INSERT INTO "<SCHEMA-NAME>"."Schema" (partition, id, alias, category, ancestor, attributes, meta, links, "order", ancestors) VALUES
|
|
68
|
+
('entity', 'busy', 'занятость', 'LINK', 'link', '{"id":{"type":"uuid","generate":5,"from":["Slot","Staff"]},"kind":{"type":"enum","values":["off","hold","booking"],"default":"booking"},"reason":"string|optional"}'::jsonb, '{"abstract":false,"description":"Негативная доступность: свободно = НЕТ живой занятости. off — мастер убран из окна; hold — оформление; booking — бронь (+ключ Запись в links). id = uuidv5(Окно, Сотрудник) — считает схема (attributes.id) — детерминирован против двойной брони"}'::jsonb, '[{"class":"Staff","cardinality":1},{"class":"Slot","cardinality":1},{"class":"Booking","optional":true,"cardinality":1}]'::jsonb, 500, ARRAY['busy', 'link']::text[])
|
|
64
69
|
ON CONFLICT (partition, id) DO UPDATE SET alias = EXCLUDED.alias, category = EXCLUDED.category, ancestor = EXCLUDED.ancestor, attributes = EXCLUDED.attributes, meta = EXCLUDED.meta, links = EXCLUDED.links, "order" = EXCLUDED."order", ancestors = EXCLUDED.ancestors;
|