@contember/engine-system-api 1.2.1 → 1.3.0-alpha.4

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.
Files changed (185) hide show
  1. package/dist/src/SystemContainer.d.ts +1 -12
  2. package/dist/src/SystemContainer.d.ts.map +1 -1
  3. package/dist/src/SystemContainer.js +1 -6
  4. package/dist/src/SystemContainer.js.map +1 -1
  5. package/dist/src/bin/runMigrations.d.ts +2 -0
  6. package/dist/src/bin/runMigrations.d.ts.map +1 -0
  7. package/dist/src/bin/runMigrations.js +31 -0
  8. package/dist/src/bin/runMigrations.js.map +1 -0
  9. package/dist/src/index.d.ts +1 -1
  10. package/dist/src/index.d.ts.map +1 -1
  11. package/dist/src/index.js +1 -3
  12. package/dist/src/index.js.map +1 -1
  13. package/dist/src/migrations/2018-08-04-102200-init.d.ts +3 -0
  14. package/dist/src/migrations/2018-08-04-102200-init.d.ts.map +1 -0
  15. package/dist/src/migrations/2018-08-04-102200-init.js +37 -0
  16. package/dist/src/migrations/2018-08-04-102200-init.js.map +1 -0
  17. package/dist/src/migrations/2018-08-05-130501-trigger-event-function.d.ts +3 -0
  18. package/dist/src/migrations/2018-08-05-130501-trigger-event-function.d.ts.map +1 -0
  19. package/dist/src/migrations/2018-08-05-130501-trigger-event-function.js +99 -0
  20. package/dist/src/migrations/2018-08-05-130501-trigger-event-function.js.map +1 -0
  21. package/dist/src/migrations/2019-01-14-143432-event-trx-id.d.ts +3 -0
  22. package/dist/src/migrations/2019-01-14-143432-event-trx-id.d.ts.map +1 -0
  23. package/dist/src/migrations/2019-01-14-143432-event-trx-id.js +17 -0
  24. package/dist/src/migrations/2019-01-14-143432-event-trx-id.js.map +1 -0
  25. package/dist/src/migrations/2019-02-04-154500-event-rebase.d.ts +3 -0
  26. package/dist/src/migrations/2019-02-04-154500-event-rebase.d.ts.map +1 -0
  27. package/dist/src/migrations/2019-02-04-154500-event-rebase.js +59 -0
  28. package/dist/src/migrations/2019-02-04-154500-event-rebase.js.map +1 -0
  29. package/dist/src/migrations/2019-03-18-104147-event-run-migration-struct.d.ts +3 -0
  30. package/dist/src/migrations/2019-03-18-104147-event-run-migration-struct.d.ts.map +1 -0
  31. package/dist/src/migrations/2019-03-18-104147-event-run-migration-struct.js +12 -0
  32. package/dist/src/migrations/2019-03-18-104147-event-run-migration-struct.js.map +1 -0
  33. package/dist/src/migrations/2019-07-29-103000-trigger-event-function-fix.d.ts +3 -0
  34. package/dist/src/migrations/2019-07-29-103000-trigger-event-function-fix.d.ts.map +1 -0
  35. package/dist/src/migrations/2019-07-29-103000-trigger-event-function-fix.js +66 -0
  36. package/dist/src/migrations/2019-07-29-103000-trigger-event-function-fix.js.map +1 -0
  37. package/dist/src/migrations/2019-11-28-100000-missing-setting-fallback.d.ts +3 -0
  38. package/dist/src/migrations/2019-11-28-100000-missing-setting-fallback.d.ts.map +1 -0
  39. package/dist/src/migrations/2019-11-28-100000-missing-setting-fallback.js +21 -0
  40. package/dist/src/migrations/2019-11-28-100000-missing-setting-fallback.js.map +1 -0
  41. package/dist/src/migrations/2021-03-23-110000-timestamp-fix.d.ts +3 -0
  42. package/dist/src/migrations/2021-03-23-110000-timestamp-fix.d.ts.map +1 -0
  43. package/dist/src/migrations/2021-03-23-110000-timestamp-fix.js +15 -0
  44. package/dist/src/migrations/2021-03-23-110000-timestamp-fix.js.map +1 -0
  45. package/dist/src/migrations/2021-05-07-155800-event-log-rework.js +2 -2
  46. package/dist/src/migrations/2021-12-21-155500-events-up.d.ts +3 -0
  47. package/dist/src/migrations/2021-12-21-155500-events-up.d.ts.map +1 -0
  48. package/dist/src/migrations/2021-12-21-155500-events-up.js +15 -0
  49. package/dist/src/migrations/2021-12-21-155500-events-up.js.map +1 -0
  50. package/dist/src/migrations/2022-02-08-132600-fn-search-path.d.ts +3 -0
  51. package/dist/src/migrations/2022-02-08-132600-fn-search-path.d.ts.map +1 -0
  52. package/dist/src/migrations/2022-02-08-132600-fn-search-path.js +16 -0
  53. package/dist/src/migrations/2022-02-08-132600-fn-search-path.js.map +1 -0
  54. package/dist/src/migrations/2022-02-08-140500-drop-deadcode.d.ts +3 -0
  55. package/dist/src/migrations/2022-02-08-140500-drop-deadcode.d.ts.map +1 -0
  56. package/dist/src/migrations/2022-02-08-140500-drop-deadcode.js +11 -0
  57. package/dist/src/migrations/2022-02-08-140500-drop-deadcode.js.map +1 -0
  58. package/dist/src/migrations/2022-02-08-144400-dynamic-stage-schema.d.ts +3 -0
  59. package/dist/src/migrations/2022-02-08-144400-dynamic-stage-schema.d.ts.map +1 -0
  60. package/dist/src/migrations/2022-02-08-144400-dynamic-stage-schema.js +50 -0
  61. package/dist/src/migrations/2022-02-08-144400-dynamic-stage-schema.js.map +1 -0
  62. package/dist/src/migrations/2022-10-03-110000-table-on-delete.d.ts +4 -0
  63. package/dist/src/migrations/2022-10-03-110000-table-on-delete.d.ts.map +1 -0
  64. package/dist/src/migrations/2022-10-03-110000-table-on-delete.js +56 -0
  65. package/dist/src/migrations/2022-10-03-110000-table-on-delete.js.map +1 -0
  66. package/dist/src/migrations/runner.d.ts +16 -3
  67. package/dist/src/migrations/runner.d.ts.map +1 -1
  68. package/dist/src/migrations/runner.js +64 -10
  69. package/dist/src/migrations/runner.js.map +1 -1
  70. package/dist/src/migrations/snapshot-factory.d.ts +6 -0
  71. package/dist/src/migrations/snapshot-factory.d.ts.map +1 -0
  72. package/dist/src/migrations/snapshot-factory.js +46 -0
  73. package/dist/src/migrations/snapshot-factory.js.map +1 -0
  74. package/dist/src/migrations/snapshot.d.ts +3 -0
  75. package/dist/src/migrations/snapshot.d.ts.map +1 -0
  76. package/dist/src/migrations/snapshot.js +172 -0
  77. package/dist/src/migrations/snapshot.js.map +1 -0
  78. package/dist/src/model/ProjectInitializer.d.ts +6 -10
  79. package/dist/src/model/ProjectInitializer.d.ts.map +1 -1
  80. package/dist/src/model/ProjectInitializer.js +11 -29
  81. package/dist/src/model/ProjectInitializer.js.map +1 -1
  82. package/dist/src/model/commands/Command.d.ts +1 -5
  83. package/dist/src/model/commands/Command.d.ts.map +1 -1
  84. package/dist/src/model/database/DatabaseContext.d.ts +5 -4
  85. package/dist/src/model/database/DatabaseContext.d.ts.map +1 -1
  86. package/dist/src/model/database/DatabaseContext.js +7 -7
  87. package/dist/src/model/database/DatabaseContext.js.map +1 -1
  88. package/dist/src/model/dtos/ExecutedMigration.d.ts +2 -1
  89. package/dist/src/model/dtos/ExecutedMigration.d.ts.map +1 -1
  90. package/dist/src/model/dtos/ExecutedMigration.js +2 -1
  91. package/dist/src/model/dtos/ExecutedMigration.js.map +1 -1
  92. package/dist/src/model/events/EventResponseBuilder.d.ts +2 -2
  93. package/dist/src/model/events/EventResponseBuilder.d.ts.map +1 -1
  94. package/dist/src/model/events/EventResponseBuilder.js +10 -10
  95. package/dist/src/model/events/EventResponseBuilder.js.map +1 -1
  96. package/dist/src/model/events/EventResponseHelper.d.ts +1 -1
  97. package/dist/src/model/events/EventResponseHelper.d.ts.map +1 -1
  98. package/dist/src/model/events/index.d.ts +1 -0
  99. package/dist/src/model/events/index.d.ts.map +1 -1
  100. package/dist/src/model/events/index.js +1 -0
  101. package/dist/src/model/events/index.js.map +1 -1
  102. package/dist/src/model/events/types.d.ts +56 -0
  103. package/dist/src/model/events/types.d.ts.map +1 -0
  104. package/dist/src/model/events/types.js +51 -0
  105. package/dist/src/model/events/types.js.map +1 -0
  106. package/dist/src/model/helpers/index.d.ts +0 -1
  107. package/dist/src/model/helpers/index.d.ts.map +1 -1
  108. package/dist/src/model/helpers/index.js +0 -1
  109. package/dist/src/model/helpers/index.js.map +1 -1
  110. package/dist/src/model/migrations/ProjectMigrator.js +1 -1
  111. package/dist/src/model/migrations/ProjectMigrator.js.map +1 -1
  112. package/dist/src/model/migrations/SchemaVersionBuilder.d.ts +20 -0
  113. package/dist/src/model/migrations/SchemaVersionBuilder.d.ts.map +1 -1
  114. package/dist/src/model/migrations/SchemaVersionBuilder.js +5 -4
  115. package/dist/src/model/migrations/SchemaVersionBuilder.js.map +1 -1
  116. package/dist/src/model/queries/events/EventQueryHelpers.d.ts +2 -2
  117. package/dist/src/model/queries/events/EventQueryHelpers.d.ts.map +1 -1
  118. package/dist/src/model/queries/events/EventQueryHelpers.js +7 -7
  119. package/dist/src/model/queries/events/EventQueryHelpers.js.map +1 -1
  120. package/dist/src/model/queries/events/EventsQuery.d.ts +2 -2
  121. package/dist/src/model/queries/events/EventsQuery.d.ts.map +1 -1
  122. package/dist/src/model/queries/events/EventsQuery.js.map +1 -1
  123. package/dist/src/model/queries/migrations/ExecutedMigrationsQueryHelper.d.ts +1 -0
  124. package/dist/src/model/queries/migrations/ExecutedMigrationsQueryHelper.d.ts.map +1 -1
  125. package/dist/src/model/queries/migrations/ExecutedMigrationsQueryHelper.js +2 -1
  126. package/dist/src/model/queries/migrations/ExecutedMigrationsQueryHelper.js.map +1 -1
  127. package/dist/src/tsconfig.tsbuildinfo +1 -1
  128. package/dist/tests/cases/migrations/2022-10-03-110000-table-on-delete.test.d.ts +2 -0
  129. package/dist/tests/cases/migrations/2022-10-03-110000-table-on-delete.test.d.ts.map +1 -0
  130. package/dist/tests/cases/migrations/2022-10-03-110000-table-on-delete.test.js +40 -0
  131. package/dist/tests/cases/migrations/2022-10-03-110000-table-on-delete.test.js.map +1 -0
  132. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  133. package/package.json +13 -14
  134. package/src/SystemContainer.ts +0 -15
  135. package/src/bin/runMigrations.ts +35 -0
  136. package/src/index.ts +1 -2
  137. package/src/migrations/{2018-08-04-102200-init.sql → 2018-08-04-102200-init.ts} +8 -0
  138. package/src/migrations/{2018-08-05-130501-trigger-event-function.sql → 2018-08-05-130501-trigger-event-function.ts} +8 -0
  139. package/src/migrations/{2019-01-14-143432-event-trx-id.sql → 2019-01-14-143432-event-trx-id.ts} +8 -0
  140. package/src/migrations/{2019-02-04-154500-event-rebase.sql → 2019-02-04-154500-event-rebase.ts} +9 -0
  141. package/src/migrations/2019-03-18-104147-event-run-migration-struct.ts +11 -0
  142. package/src/migrations/{2019-07-29-103000-trigger-event-function-fix.sql → 2019-07-29-103000-trigger-event-function-fix.ts} +8 -0
  143. package/src/migrations/{2019-11-28-100000-missing-setting-fallback.sql → 2019-11-28-100000-missing-setting-fallback.ts} +8 -0
  144. package/src/migrations/{2021-03-23-110000-timestamp-fix.sql → 2021-03-23-110000-timestamp-fix.ts} +8 -0
  145. package/src/migrations/2021-05-07-155800-event-log-rework.ts +2 -2
  146. package/src/migrations/{2021-12-21-155500-events-up.sql → 2021-12-21-155500-events-up.ts} +8 -0
  147. package/src/migrations/{2022-02-08-132600-fn-search-path.sql → 2022-02-08-132600-fn-search-path.ts} +8 -0
  148. package/src/migrations/2022-02-08-140500-drop-deadcode.ts +10 -0
  149. package/src/migrations/{2022-02-08-144400-dynamic-stage-schema.sql → 2022-02-08-144400-dynamic-stage-schema.ts} +8 -0
  150. package/src/migrations/2022-10-03-110000-table-on-delete.ts +66 -0
  151. package/src/migrations/runner.ts +79 -15
  152. package/src/migrations/snapshot-factory.ts +45 -0
  153. package/src/migrations/snapshot-template-end.txt +1 -0
  154. package/src/migrations/snapshot-template-start.txt +2 -0
  155. package/src/migrations/snapshot.ts +169 -0
  156. package/src/model/ProjectInitializer.ts +15 -50
  157. package/src/model/commands/Command.ts +1 -1
  158. package/src/model/database/DatabaseContext.ts +12 -8
  159. package/src/model/dtos/ExecutedMigration.ts +1 -0
  160. package/src/model/events/EventResponseBuilder.ts +3 -3
  161. package/src/model/events/EventResponseHelper.ts +1 -1
  162. package/src/model/events/index.ts +1 -0
  163. package/src/model/events/types.ts +63 -0
  164. package/src/model/helpers/index.ts +0 -1
  165. package/src/model/migrations/ProjectMigrator.ts +1 -1
  166. package/src/model/migrations/SchemaVersionBuilder.ts +3 -2
  167. package/src/model/queries/events/EventQueryHelpers.ts +2 -2
  168. package/src/model/queries/events/EventsQuery.ts +2 -2
  169. package/src/model/queries/migrations/ExecutedMigrationsQueryHelper.ts +3 -1
  170. package/src/tsconfig.json +10 -33
  171. package/tests/cases/migrations/2022-10-03-110000-table-on-delete.test.ts +42 -0
  172. package/tests/tsconfig.json +2 -6
  173. package/tsconfig.json +2 -6
  174. package/dist/src/model/helpers/SystemVariablesSetupHelper.d.ts +0 -5
  175. package/dist/src/model/helpers/SystemVariablesSetupHelper.d.ts.map +0 -1
  176. package/dist/src/model/helpers/SystemVariablesSetupHelper.js +0 -15
  177. package/dist/src/model/helpers/SystemVariablesSetupHelper.js.map +0 -1
  178. package/dist/tests/cases/integration/systemApi/projectInitializer.test.d.ts +0 -2
  179. package/dist/tests/cases/integration/systemApi/projectInitializer.test.d.ts.map +0 -1
  180. package/dist/tests/cases/integration/systemApi/projectInitializer.test.js +0 -26
  181. package/dist/tests/cases/integration/systemApi/projectInitializer.test.js.map +0 -1
  182. package/src/migrations/2019-03-18-104147-event-run-migration-struct.sql +0 -3
  183. package/src/migrations/2022-02-08-140500-drop-deadcode.sql +0 -2
  184. package/src/model/helpers/SystemVariablesSetupHelper.ts +0 -14
  185. package/tests/cases/integration/systemApi/projectInitializer.test.ts +0 -31
@@ -0,0 +1,169 @@
1
+ import { snapshotMigration } from './snapshot-factory'
2
+ export default snapshotMigration(({ randomUuidFn }) => `
3
+ CREATE DOMAIN "event_data_type" AS "text"
4
+ CONSTRAINT "event_data_type_check" CHECK ((VALUE = ANY (ARRAY['create'::"text", 'update'::"text", 'delete'::"text"])));
5
+ CREATE DOMAIN "event_type" AS "text"
6
+ CONSTRAINT "event_type_check" CHECK ((VALUE = ANY (ARRAY['init'::"text", 'create'::"text", 'update'::"text", 'delete'::"text", 'run_migration'::"text"])));
7
+ CREATE FUNCTION "trigger_event"() RETURNS "trigger"
8
+ LANGUAGE "plpgsql"
9
+ AS $$
10
+ DECLARE new_event_type TEXT;
11
+ DECLARE table_name TEXT;
12
+ DECLARE values JSONB;
13
+ DECLARE update_diff JSONB;
14
+ DECLARE primary_values JSONB;
15
+ DECLARE old_row JSONB;
16
+ DECLARE new_row JSONB;
17
+ BEGIN
18
+ old_row := CASE WHEN TG_OP = 'DELETE' OR TG_OP = 'UPDATE' THEN TO_JSONB(old) ELSE NULL END;
19
+ new_row := CASE WHEN TG_OP = 'INSERT' OR TG_OP = 'UPDATE' THEN TO_JSONB(new) ELSE NULL END;
20
+ primary_values := (
21
+ SELECT JSONB_AGG(value ORDER BY array_position(TG_ARGV, key))
22
+ FROM JSONB_EACH(COALESCE(old_row, new_row))
23
+ WHERE key = ANY (TG_ARGV)
24
+ );
25
+ table_name := tg_table_name;
26
+ CASE TG_OP
27
+ WHEN 'INSERT' THEN BEGIN
28
+ new_event_type := 'create';
29
+ values := COALESCE(
30
+ (
31
+ SELECT JSONB_OBJECT_AGG(key, value)
32
+ FROM JSONB_EACH(new_row)
33
+ WHERE NOT (key = ANY (TG_ARGV))
34
+ ),
35
+ JSONB_BUILD_OBJECT()
36
+ );
37
+ END;
38
+ WHEN 'UPDATE' THEN BEGIN
39
+ update_diff := (
40
+ SELECT JSONB_OBJECT_AGG(COALESCE(n.key, o.key), n.value)
41
+ FROM JSONB_EACH(old_row) o
42
+ FULL OUTER JOIN JSONB_EACH(new_row) n ON n.key = o.key
43
+ WHERE n.value IS DISTINCT FROM o.value
44
+ );
45
+ IF (SELECT COUNT(*) FROM JSONB_OBJECT_KEYS(update_diff)) = 0 THEN
46
+ RETURN NULL;
47
+ END IF;
48
+ new_event_type := 'update';
49
+ values := update_diff;
50
+ END;
51
+ WHEN 'DELETE' THEN BEGIN
52
+ new_event_type := 'delete';
53
+ END;
54
+ ELSE RAISE
55
+ EXCEPTION 'Unknown TG_OP value %', TG_OP;
56
+ END CASE;
57
+ CASE WHEN NULLIF(CURRENT_SETTING('system.schema_id', true), '') IS NULL THEN
58
+ PERFORM SET_CONFIG('system.schema_id', (select MAX("id")::TEXT from schema_migration), TRUE);
59
+ ELSE
60
+ -- do nothing
61
+ END CASE;
62
+ INSERT INTO "event_data" ("id", "type", "table_name", "row_ids", "values", "created_at", schema_id, identity_id)
63
+ VALUES (
64
+ "${randomUuidFn}"(),
65
+ new_event_type,
66
+ table_name,
67
+ primary_values,
68
+ values,
69
+ CLOCK_TIMESTAMP(),
70
+ CURRENT_SETTING('system.schema_id')::INT,
71
+ COALESCE(
72
+ CURRENT_SETTING('tenant.identity_id'::TEXT, TRUE)::UUID,
73
+ '00000000-0000-0000-0000-000000000000'::UUID)
74
+ );
75
+ RETURN NULL;
76
+ END;
77
+ $$;
78
+ CREATE FUNCTION "trigger_event_commit"() RETURNS "trigger"
79
+ LANGUAGE "plpgsql"
80
+ AS $$
81
+ BEGIN
82
+ PERFORM PG_ADVISORY_XACT_LOCK(5218230332970456493); -- well-known random number
83
+ CASE WHEN
84
+ NULLIF(CURRENT_SETTING('system.transaction_id', TRUE), '') IS NOT NULL
85
+ AND NULLIF(CURRENT_SETTING('system.transaction_inserted', TRUE), '') IS NULL
86
+ THEN
87
+ INSERT INTO stage_transaction(transaction_id, stage_id, applied_at)
88
+ VALUES (CURRENT_SETTING('system.transaction_id')::UUID,
89
+ (
90
+ SELECT id
91
+ FROM stage
92
+ WHERE schema = TG_TABLE_SCHEMA
93
+ ),
94
+ CLOCK_TIMESTAMP())
95
+ ON CONFLICT DO NOTHING;
96
+ PERFORM SET_CONFIG('system.transaction_inserted', '1', TRUE);
97
+ ELSE
98
+ -- do nothing
99
+ END CASE;
100
+ RETURN NULL;
101
+ END
102
+ $$;
103
+ CREATE TABLE "event_data" (
104
+ "id" "uuid" NOT NULL,
105
+ "type" "event_data_type" NOT NULL,
106
+ "table_name" "text" NOT NULL,
107
+ "row_ids" "jsonb" NOT NULL,
108
+ "values" "jsonb",
109
+ "created_at" timestamp with time zone DEFAULT "clock_timestamp"() NOT NULL,
110
+ "schema_id" integer NOT NULL,
111
+ "identity_id" "uuid" NOT NULL,
112
+ "transaction_id" "uuid" DEFAULT COALESCE((NULLIF("current_setting"('system.transaction_id'::"text", true), ''::"text"))::"uuid", ("set_config"('system.transaction_id'::"text", ("${randomUuidFn}"())::"text", true))::"uuid") NOT NULL
113
+ );
114
+ CREATE TABLE "schema_migration" (
115
+ "id" integer NOT NULL,
116
+ "version" character varying(20) NOT NULL,
117
+ "name" character varying(255) NOT NULL,
118
+ "migration" "json" NOT NULL,
119
+ "checksum" character(32) NOT NULL,
120
+ "executed_at" timestamp with time zone DEFAULT "now"() NOT NULL
121
+ );
122
+ CREATE SEQUENCE "schema_migration_id_seq"
123
+ AS integer
124
+ START WITH 1
125
+ INCREMENT BY 1
126
+ NO MINVALUE
127
+ NO MAXVALUE
128
+ CACHE 1;
129
+ ALTER SEQUENCE "schema_migration_id_seq" OWNED BY "schema_migration"."id";
130
+ CREATE TABLE "stage" (
131
+ "id" "uuid" NOT NULL,
132
+ "name" "text" NOT NULL,
133
+ "slug" "text" NOT NULL,
134
+ "schema" "text" NOT NULL
135
+ );
136
+ CREATE TABLE "stage_transaction" (
137
+ "transaction_id" "uuid" NOT NULL,
138
+ "stage_id" "uuid" NOT NULL,
139
+ "applied_at" timestamp with time zone NOT NULL
140
+ );
141
+ ALTER TABLE ONLY "schema_migration" ALTER COLUMN "id" SET DEFAULT "nextval"('"schema_migration_id_seq"'::"regclass");
142
+ ALTER TABLE ONLY "event_data"
143
+ ADD CONSTRAINT "event_data_pkey" PRIMARY KEY ("id");
144
+ ALTER TABLE ONLY "schema_migration"
145
+ ADD CONSTRAINT "schema_migration_name_key" UNIQUE ("name");
146
+ ALTER TABLE ONLY "schema_migration"
147
+ ADD CONSTRAINT "schema_migration_pkey" PRIMARY KEY ("id");
148
+ ALTER TABLE ONLY "schema_migration"
149
+ ADD CONSTRAINT "schema_migration_version_key" UNIQUE ("version");
150
+ ALTER TABLE ONLY "stage"
151
+ ADD CONSTRAINT "stage_pkey" PRIMARY KEY ("id");
152
+ ALTER TABLE ONLY "stage"
153
+ ADD CONSTRAINT "stage_schema_key" UNIQUE ("schema");
154
+ ALTER TABLE ONLY "stage"
155
+ ADD CONSTRAINT "stage_slug_key" UNIQUE ("slug");
156
+ ALTER TABLE ONLY "stage_transaction"
157
+ ADD CONSTRAINT "stage_transaction_pkey" PRIMARY KEY ("transaction_id", "stage_id");
158
+ CREATE INDEX "event_data_created" ON "event_data" USING "btree" ("created_at");
159
+ CREATE INDEX "system_event2_table_name" ON "event_data" USING "btree" ("table_name");
160
+ CREATE INDEX "system_event2_transaction" ON "event_data" USING "btree" ("transaction_id");
161
+ CREATE INDEX "system_event2_type" ON "event_data" USING "btree" ("type");
162
+ CREATE INDEX "system_event_row_id" ON "event_data" USING "btree" ("row_ids");
163
+ CREATE INDEX "system_schema_migration_version" ON "schema_migration" USING "btree" ("version");
164
+ CREATE INDEX "transaction_applied" ON "stage_transaction" USING "btree" ("applied_at");
165
+ ALTER TABLE ONLY "event_data"
166
+ ADD CONSTRAINT "event_data_schema_id_fkey" FOREIGN KEY ("schema_id") REFERENCES "schema_migration"("id");
167
+ ALTER TABLE ONLY "stage_transaction"
168
+ ADD CONSTRAINT "stage_transaction_stage_id_fkey" FOREIGN KEY ("stage_id") REFERENCES "stage"("id") ON DELETE CASCADE;
169
+ `)
@@ -1,63 +1,28 @@
1
1
  import { ProjectConfig } from '../types'
2
- import { ProjectMigrator, SchemaVersionBuilder } from './migrations'
3
2
  import { StageCreator } from './stages'
4
3
  import { DatabaseContext, DatabaseContextFactory } from './database'
5
- import { SystemDbMigrationsRunnerFactory } from '../SystemContainer'
6
- import {
7
- Client,
8
- Connection,
9
- createDatabaseIfNotExists,
10
- DatabaseConfig,
11
- EventManager,
12
- retryTransaction,
13
- } from '@contember/database'
4
+ import { Connection, retryTransaction } from '@contember/database'
14
5
  import { FingerCrossedLoggerHandler, Logger } from '@contember/logger'
6
+ import { SystemMigrationsRunner } from '../migrations'
15
7
 
16
8
  export class ProjectInitializer {
17
9
  constructor(
18
- private readonly projectMigrator: ProjectMigrator,
19
10
  private readonly stageCreator: StageCreator,
20
- private readonly systemDbMigrationsRunnerFactory: SystemDbMigrationsRunnerFactory,
21
- private readonly schemaVersionBuilder: SchemaVersionBuilder,
11
+ private readonly migrationsRunner: SystemMigrationsRunner,
12
+ private readonly databaseContextFactory: DatabaseContextFactory,
13
+ private readonly project: ProjectConfig,
22
14
  ) {}
23
15
 
24
- public async initialize(
25
- databaseContextFactory: DatabaseContextFactory,
26
- project: ProjectConfig & { db?: DatabaseConfig },
27
- logger: Logger,
28
- ) {
29
- const dbContext = databaseContextFactory.create()
16
+ public async initialize(logger: Logger) {
30
17
  return await logger.scope(async initLogger => {
31
- if (project.db) {
32
- // todo: use dbContext
33
- initLogger.debug('Executing system schema migrations')
34
- await createDatabaseIfNotExists(project.db, message => typeof message === 'string' ? initLogger.warn(message) : initLogger.error(message))
35
- const singleConnection = Connection.createSingle(project.db, err => initLogger.error(err, { message: 'Database client error' }))
36
-
37
- await singleConnection.scope(async connection => {
38
- const systemSchema = dbContext.client.schema
39
-
40
- const schemaResolver = (connection: Connection.ConnectionLike) => {
41
- const dbContextMigrations = databaseContextFactory
42
- .withClient(new Client(connection, systemSchema, { module: 'system' }))
43
- .create()
44
- return this.schemaVersionBuilder.buildSchema(dbContextMigrations)
45
- }
46
- await this.systemDbMigrationsRunnerFactory(connection, systemSchema).migrate(
47
- message => initLogger.warn(message),
48
- {
49
- schemaResolver,
50
- project,
51
- },
52
- )
53
- })
54
- await singleConnection.end()
55
- }
56
- await retryTransaction(() =>
57
- dbContext.transaction(async trx => {
58
- await this.initStages(trx, project, initLogger)
18
+ initLogger.debug('Executing system schema migrations')
19
+ await this.migrationsRunner.run(initLogger)
20
+ const dbContext = this.databaseContextFactory.create()
21
+ await retryTransaction(
22
+ () => dbContext.transaction(async trx => {
23
+ await this.initStages(trx, logger)
59
24
  }),
60
- message => initLogger.warn(message),
25
+ message => initLogger.warn(message),
61
26
  )
62
27
  if (dbContext.client.connection instanceof Connection) {
63
28
  await dbContext.client.connection.clearPool()
@@ -65,9 +30,9 @@ export class ProjectInitializer {
65
30
  }, {}, { handler: FingerCrossedLoggerHandler.factory() })
66
31
  }
67
32
 
68
- private async initStages(db: DatabaseContext<Connection.TransactionLike>, project: ProjectConfig, logger: Logger) {
33
+ private async initStages(db: DatabaseContext<Connection.TransactionLike>, logger: Logger) {
69
34
  logger.debug(`Creating stages`)
70
- for (const stage of project.stages) {
35
+ for (const stage of this.project.stages) {
71
36
  const created = await this.stageCreator.createStage(db, stage)
72
37
  if (created) {
73
38
  logger.warn(`Created stage ${stage.slug}`, { stage: stage.slug })
@@ -3,7 +3,7 @@ import { CommandBus } from './CommandBus'
3
3
  import { Providers } from '../../utils'
4
4
 
5
5
  interface Command<Result> {
6
- execute(args: { db: Client; providers: Providers; bus: CommandBus }): Promise<Result>
6
+ execute(args: Command.Args): Promise<Result>
7
7
  }
8
8
 
9
9
  namespace Command {
@@ -1,4 +1,4 @@
1
- import { Client, Connection, DatabaseQueryable, withDatabaseAdvisoryLock } from '@contember/database'
1
+ import { Client, Connection, DatabaseQueryable } from '@contember/database'
2
2
  import { QueryHandler } from '@contember/queryable'
3
3
  import { UuidProvider } from '../../utils'
4
4
  import { CommandBus } from '../commands'
@@ -7,19 +7,21 @@ export interface DatabaseContext<ConnectionType extends Connection.ConnectionLik
7
7
  client: Client<ConnectionType>
8
8
  queryHandler: QueryHandler<DatabaseQueryable>
9
9
  transaction: <T>(cb: (db: DatabaseContext<Connection.TransactionLike>) => Promise<T> | T) => Promise<T>
10
+ scope: <T>(cb: (db: DatabaseContext<ConnectionType & Connection.AcquiredConnectionLike>) => Promise<T> | T) => Promise<T>
10
11
  locked: <T>(lock: number, cb: (db: DatabaseContext<Connection.ConnectionLike>) => Promise<T> | T) => Promise<T>
11
12
  commandBus: CommandBus
12
13
  }
13
14
 
14
15
  export class DatabaseContextFactory {
15
- constructor(private readonly client: Client, private readonly providers: UuidProvider) {}
16
+ constructor(
17
+ public readonly schemaName: string,
18
+ private readonly connection: Connection,
19
+ private readonly providers: UuidProvider,
20
+ ) {}
16
21
 
17
- public create(): DatabaseContext {
18
- return createDatabaseContext(this.client, this.providers)
19
- }
20
-
21
- public withClient(client: Client) {
22
- return new DatabaseContextFactory(client, this.providers)
22
+ public create(connection?: Connection.ConnectionLike): DatabaseContext {
23
+ const client = new Client(connection ?? this.connection, this.schemaName, { module: 'system' })
24
+ return createDatabaseContext(client, this.providers)
23
25
  }
24
26
  }
25
27
 
@@ -34,6 +36,8 @@ const createDatabaseContext = <ConnectionType extends Connection.ConnectionLike
34
36
  await client.query(Connection.REPEATABLE_READ)
35
37
  return cb(createDatabaseContext(client, providers))
36
38
  }),
39
+ scope: cb =>
40
+ client.scope(client => cb(createDatabaseContext(client, providers))),
37
41
  commandBus: new CommandBus(client, providers),
38
42
  locked: (lock, cb) => client.locked(lock, client => cb(createDatabaseContext(client, providers))),
39
43
  })
@@ -4,6 +4,7 @@ export class ExecutedMigration implements Migration {
4
4
  public readonly version: string
5
5
 
6
6
  constructor(
7
+ public readonly id: number,
7
8
  public readonly name: string,
8
9
  public readonly formatVersion: number,
9
10
  public readonly modifications: Migration.Modification[],
@@ -1,4 +1,4 @@
1
- import { AnyEvent, EventType } from '@contember/engine-common'
1
+ import { ContentEvent, EventType } from './types'
2
2
  import { CreateEvent, DeleteEvent, EventType as ApiEventType, UpdateEvent } from '../../schema'
3
3
  import { assertNever } from '../../utils'
4
4
  import { IdentityFetcher } from '../dependencies'
@@ -8,7 +8,7 @@ import { appendCreateSpecificData, appendDeleteSpecificData, appendUpdateSpecifi
8
8
  export class EventResponseBuilder {
9
9
  constructor(private readonly identityFetcher: IdentityFetcher) {}
10
10
 
11
- public async buildResponse(events: AnyEvent[]): Promise<(CreateEvent | DeleteEvent | UpdateEvent)[]> {
11
+ public async buildResponse(events: ContentEvent[]): Promise<(CreateEvent | DeleteEvent | UpdateEvent)[]> {
12
12
  const apiEventTypeMapping = {
13
13
  [EventType.create]: ApiEventType.Create,
14
14
  [EventType.update]: ApiEventType.Update,
@@ -41,7 +41,7 @@ export class EventResponseBuilder {
41
41
  })
42
42
  }
43
43
 
44
- private formatDescription(event: AnyEvent): string {
44
+ private formatDescription(event: ContentEvent): string {
45
45
  switch (event.type) {
46
46
  case EventType.create:
47
47
  return `Creating ${event.tableName}#${event.rowId.join(';')}`
@@ -1,4 +1,4 @@
1
- import { AnyEvent, ContentEvent, CreateEvent, DeleteEvent, UpdateEvent } from '@contember/engine-common'
1
+ import { CreateEvent, DeleteEvent, UpdateEvent } from './types'
2
2
 
3
3
  export const appendUpdateSpecificData = <T>(commonData: T, event: UpdateEvent) => ({
4
4
  ...commonData,
@@ -1 +1,2 @@
1
1
  export * from './EventResponseBuilder'
2
+ export * from './types'
@@ -0,0 +1,63 @@
1
+ export enum EventType {
2
+ delete = 'delete',
3
+ update = 'update',
4
+ create = 'create',
5
+ }
6
+
7
+ export type ContentEvent = UpdateEvent | CreateEvent | DeleteEvent
8
+
9
+ export interface Event {
10
+ readonly type: EventType
11
+ readonly id: string
12
+ readonly createdAt: Date
13
+ readonly transactionId: string
14
+ // readonly errors?: string[]
15
+ }
16
+
17
+ export class UpdateEvent implements Event {
18
+ public readonly type = EventType.update
19
+
20
+ constructor(
21
+ public readonly id: string,
22
+ public readonly createdAt: Date,
23
+ public readonly appliedAt: Date,
24
+ public readonly identityId: string,
25
+ public readonly transactionId: string,
26
+ public readonly rowId: string[],
27
+ public readonly tableName: string,
28
+ public readonly values: { [column: string]: any },
29
+ ) {
30
+ }
31
+ }
32
+
33
+ export class CreateEvent implements Event {
34
+ public readonly type = EventType.create
35
+
36
+ constructor(
37
+ public readonly id: string,
38
+ public readonly createdAt: Date,
39
+ public readonly appliedAt: Date,
40
+ public readonly identityId: string,
41
+ public readonly transactionId: string,
42
+ public readonly rowId: string[],
43
+ public readonly tableName: string,
44
+ public readonly values: { [column: string]: any },
45
+ ) {
46
+ }
47
+ }
48
+
49
+ export class DeleteEvent implements Event {
50
+ public readonly type = EventType.delete
51
+
52
+ constructor(
53
+ public readonly id: string,
54
+ public readonly createdAt: Date,
55
+ public readonly appliedAt: Date,
56
+ public readonly identityId: string,
57
+ public readonly transactionId: string,
58
+ public readonly rowId: string[],
59
+ public readonly tableName: string,
60
+ ) {
61
+ }
62
+ }
63
+
@@ -1,3 +1,2 @@
1
1
  export * from './stageHelpers'
2
- export * from './SystemVariablesSetupHelper'
3
2
  export * from './modelHelpers'
@@ -29,7 +29,7 @@ export class ProjectMigrator {
29
29
  if (migrationsToExecute.length === 0) {
30
30
  return
31
31
  }
32
- let { version, notNormalized, ...schema } = await this.schemaVersionBuilder.buildSchema(db)
32
+ let { version, notNormalized, id, ...schema } = await this.schemaVersionBuilder.buildSchema(db)
33
33
  const validated = await this.validateMigrations(db, schema, version, migrationsToExecute, { ignoreOrder, skipExecuted })
34
34
 
35
35
  const sorted = [...validated].sort((a, b) => a.version.localeCompare(b.version))
@@ -5,9 +5,9 @@ import { ExecutedMigrationsResolver } from './ExecutedMigrationsResolver'
5
5
  import { DatabaseContext } from '../database'
6
6
  import { normalizeSchema } from '@contember/schema-utils'
7
7
 
8
- export type VersionedSchema = Schema & { version: string; notNormalized: Schema & { version: string } }
8
+ export type VersionedSchema = Schema & { version: string; id: number; notNormalized: Schema & { version: string; id: number } }
9
9
 
10
- const emptyVersionedSchema = { ...normalizeSchema(emptySchema), version: '', notNormalized: { ...emptySchema, version: '' } }
10
+ export const emptyVersionedSchema = { ...normalizeSchema(emptySchema), version: '', id: -1, notNormalized: { ...emptySchema, version: '', id: -1 } }
11
11
 
12
12
  export class SchemaVersionBuilder {
13
13
  constructor(
@@ -25,6 +25,7 @@ export class SchemaVersionBuilder {
25
25
  (schema, migration) => ({
26
26
  ...this.schemaMigrator.applyModifications(schema, migration.modifications, migration.formatVersion),
27
27
  version: migration.version,
28
+ id: migration.id,
28
29
  }),
29
30
  after?.notNormalized ?? emptyVersionedSchema.notNormalized,
30
31
  )
@@ -1,4 +1,4 @@
1
- import { AnyEvent, CreateEvent, DeleteEvent, EventType, UpdateEvent } from '@contember/engine-common'
1
+ import { ContentEvent, CreateEvent, DeleteEvent, EventType, UpdateEvent } from '../../events'
2
2
  import { assertNever } from '../../../utils'
3
3
 
4
4
  export type EventRow = {
@@ -13,7 +13,7 @@ export type EventRow = {
13
13
  transaction_id: string
14
14
  }
15
15
 
16
- export const createEventsFromRows = (rows: EventRow[]): AnyEvent[] => {
16
+ export const createEventsFromRows = (rows: EventRow[]): ContentEvent[] => {
17
17
  return rows.map(event => {
18
18
  switch (event.type) {
19
19
  case EventType.create:
@@ -6,11 +6,11 @@ import {
6
6
  SelectBuilder,
7
7
  SelectBuilderSpecification, Value,
8
8
  } from '@contember/database'
9
- import { AnyEvent, ContentEvent } from '@contember/engine-common'
9
+ import { ContentEvent } from '../../events'
10
10
  import { EventsFilter, EventsFilterDate, EventsOrder } from '../../../schema'
11
11
  import { createEventsFromRows, EventRow } from './EventQueryHelpers'
12
12
 
13
- export class EventsQuery extends DatabaseQuery<AnyEvent[]> {
13
+ export class EventsQuery extends DatabaseQuery<ContentEvent[]> {
14
14
  constructor(
15
15
  private readonly filter: EventsFilter,
16
16
  private readonly order: EventsOrder,
@@ -2,9 +2,10 @@ import { SelectBuilder } from '@contember/database'
2
2
  import { ExecutedMigration } from '../../dtos'
3
3
  import { VERSION_INITIAL } from '@contember/schema-migrations'
4
4
 
5
- type ExecutedMigrationRow = { name: string; migration: any; checksum: string; executed_at: Date }
5
+ type ExecutedMigrationRow = { id: number; name: string; migration: any; checksum: string; executed_at: Date }
6
6
  export const createExecutedMigrationQueryBuilder = () =>
7
7
  SelectBuilder.create<ExecutedMigrationRow>()
8
+ .select('id')
8
9
  .select('name')
9
10
  .select('migration')
10
11
  .select('checksum')
@@ -14,6 +15,7 @@ export const createExecutedMigrationQueryBuilder = () =>
14
15
 
15
16
  export const createExecutedMigrationDto = (row: ExecutedMigrationRow) =>
16
17
  new ExecutedMigration(
18
+ row.id,
17
19
  row.name,
18
20
  row.migration.formatVersion || VERSION_INITIAL,
19
21
  row.migration.modifications,
package/src/tsconfig.json CHANGED
@@ -5,38 +5,15 @@
5
5
  "esModuleInterop": true
6
6
  },
7
7
  "references": [
8
- {
9
- "path": "../../authorization/src"
10
- },
11
- {
12
- "path": "../../database/src"
13
- },
14
- {
15
- "path": "../../database-migrations/src"
16
- },
17
- {
18
- "path": "../../engine-common/src"
19
- },
20
- {
21
- "path": "../../graphql-utils/src"
22
- },
23
- {
24
- "path": "../../logger/src"
25
- },
26
- {
27
- "path": "../../queryable/src"
28
- },
29
- {
30
- "path": "../../schema/src"
31
- },
32
- {
33
- "path": "../../schema-utils/src"
34
- },
35
- {
36
- "path": "../../schema-migrations/src"
37
- },
38
- {
39
- "path": "../../dic/src"
40
- }
8
+ { "path": "../../authorization/src" },
9
+ { "path": "../../database/src" },
10
+ { "path": "../../database-migrations/src" },
11
+ { "path": "../../graphql-utils/src" },
12
+ { "path": "../../logger/src" },
13
+ { "path": "../../queryable/src" },
14
+ { "path": "../../schema/src" },
15
+ { "path": "../../schema-utils/src" },
16
+ { "path": "../../schema-migrations/src" },
17
+ { "path": "../../dic/src" }
41
18
  ]
42
19
  }
@@ -0,0 +1,42 @@
1
+ import migration from '../../../src/migrations/2022-10-03-110000-table-on-delete'
2
+ import { createMigrationBuilder } from '@contember/database-migrations'
3
+ import { assert, test } from 'vitest'
4
+ import { SchemaBuilder } from '@contember/schema-definition'
5
+ import { emptySchema } from '@contember/schema-utils'
6
+ import { Model } from '@contember/schema'
7
+ import { createConnectionMock } from '@contember/database-tester'
8
+
9
+
10
+ test('table-on-delete test', async () => {
11
+ const builder = createMigrationBuilder()
12
+ const connection = createConnectionMock([{
13
+ sql: 'select schema from stage',
14
+ response: { rows: [{ schema: 'stage_live' }] },
15
+ }])
16
+ await migration(builder, {
17
+ connection: connection,
18
+ schemaResolver: () => Promise.resolve(({ ...emptySchema, model: new SchemaBuilder()
19
+ .entity('Post', entity =>
20
+ entity.manyHasOne('author', relation => relation.target('Author').onDelete(Model.OnDelete.setNull)),
21
+ )
22
+ .entity('Author', entity => entity)
23
+ .buildSchema() })),
24
+ project: {
25
+ slug: 'test',
26
+ stages: [
27
+ {
28
+ slug: 'prod',
29
+ name: 'prod',
30
+ },
31
+ ],
32
+ },
33
+ })
34
+ assert.equal(
35
+ builder.getSql(),
36
+ `ALTER TABLE "stage_live"."post" DROP CONSTRAINT "fk_post_author_id_87ef9a";
37
+ ALTER TABLE "stage_live"."post"
38
+ ADD CONSTRAINT "fk_post_author_id_87ef9a" FOREIGN KEY ("author_id") REFERENCES "stage_live"."author"("id") ON DELETE SET NULL DEFERRABLE INITIALLY IMMEDIATE;
39
+ `,
40
+ )
41
+ })
42
+
@@ -5,11 +5,7 @@
5
5
  "esModuleInterop": true
6
6
  },
7
7
  "references": [
8
- {
9
- "path": "../src"
10
- },
11
- {
12
- "path": "../../engine-api-tester/src"
13
- }
8
+ { "path": "../src" },
9
+ { "path": "../../engine-api-tester/src" }
14
10
  ]
15
11
  }
package/tsconfig.json CHANGED
@@ -2,11 +2,7 @@
2
2
  "files": [],
3
3
  "include": [],
4
4
  "references": [
5
- {
6
- "path": "./src"
7
- },
8
- {
9
- "path": "./tests"
10
- }
5
+ { "path": "./src" },
6
+ { "path": "./tests" }
11
7
  ]
12
8
  }
@@ -1,5 +0,0 @@
1
- import { Client } from '@contember/database';
2
- import { UuidProvider } from '../../utils';
3
- export declare const unnamedIdentity = "00000000-0000-0000-0000-000000000000";
4
- export declare function setupSystemVariables(db: Client, identityId: string, providers: UuidProvider): Promise<void>;
5
- //# sourceMappingURL=SystemVariablesSetupHelper.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SystemVariablesSetupHelper.d.ts","sourceRoot":"","sources":["../../../../src/model/helpers/SystemVariablesSetupHelper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,eAAO,MAAM,eAAe,yCAAyC,CAAA;AAErE,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,iBAQjG"}
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setupSystemVariables = exports.unnamedIdentity = void 0;
4
- exports.unnamedIdentity = '00000000-0000-0000-0000-000000000000';
5
- async function setupSystemVariables(db, identityId, providers) {
6
- await Promise.all([
7
- await db.query('SELECT set_config(?, ?, false)', [
8
- 'tenant.identity_id',
9
- identityId,
10
- ]),
11
- await db.query('SELECT set_config(?, ?, false)', ['system.transaction_id', providers.uuid()]),
12
- ]);
13
- }
14
- exports.setupSystemVariables = setupSystemVariables;
15
- //# sourceMappingURL=SystemVariablesSetupHelper.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"SystemVariablesSetupHelper.js","sourceRoot":"","sources":["../../../../src/model/helpers/SystemVariablesSetupHelper.ts"],"names":[],"mappings":";;;AAGa,QAAA,eAAe,GAAG,sCAAsC,CAAA;AAE9D,KAAK,UAAU,oBAAoB,CAAC,EAAU,EAAE,UAAkB,EAAE,SAAuB;IACjG,MAAM,OAAO,CAAC,GAAG,CAAC;QACjB,MAAM,EAAE,CAAC,KAAK,CAAC,gCAAgC,EAAE;YAChD,oBAAoB;YACpB,UAAU;SACV,CAAC;QACF,MAAM,EAAE,CAAC,KAAK,CAAC,gCAAgC,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;KAC7F,CAAC,CAAA;AACH,CAAC;AARD,oDAQC"}