@socialgouv/matomo-postgres 2.3.2 → 2.3.11

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.
@@ -1,100 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { sql } from 'kysely';
11
- const MATOMO_TABLE_NAME = process.env.MATOMO_TABLE_NAME || 'matomo';
12
- const indexes = [
13
- {
14
- name: 'idx_action_eventaction_matomo',
15
- columns: ['action_eventaction']
16
- },
17
- {
18
- name: 'idx_action_eventcategory_matomo',
19
- columns: ['action_eventcategory']
20
- },
21
- {
22
- name: 'idx_action_id',
23
- columns: ['action_id']
24
- },
25
- {
26
- name: 'idx_action_timestamp_matomo',
27
- columns: ['action_timestamp']
28
- },
29
- {
30
- name: 'idx_action_type_matomo',
31
- columns: ['action_type']
32
- },
33
- {
34
- name: 'idx_actionurl',
35
- columns: ['action_url']
36
- },
37
- {
38
- name: 'idx_dimension1',
39
- columns: ['dimension1']
40
- },
41
- {
42
- name: 'idx_dimension2',
43
- columns: ['dimension2']
44
- },
45
- {
46
- name: 'idx_dimension3',
47
- columns: ['dimension3']
48
- },
49
- {
50
- name: 'idx_dimension4',
51
- columns: ['dimension4']
52
- },
53
- {
54
- name: 'idx_dimension5',
55
- columns: ['dimension5']
56
- },
57
- {
58
- name: 'idx_idvisit_matomo',
59
- columns: ['idvisit']
60
- },
61
- {
62
- name: 'idx_region',
63
- columns: ['region']
64
- },
65
- {
66
- name: 'idx_userid',
67
- columns: ['userid']
68
- },
69
- {
70
- name: 'idx_visitorid',
71
- columns: ['visitorid']
72
- }
73
- ];
74
- export function up(db) {
75
- return __awaiter(this, void 0, void 0, function* () {
76
- indexes.forEach((index) => __awaiter(this, void 0, void 0, function* () {
77
- yield db.schema
78
- .createIndex(index.name)
79
- .ifNotExists()
80
- .on(MATOMO_TABLE_NAME)
81
- .using('btree')
82
- .columns(index.columns)
83
- .execute();
84
- }));
85
- yield db.schema
86
- .createIndex('actions_day')
87
- .ifNotExists()
88
- .on(MATOMO_TABLE_NAME)
89
- .expression(sql `date(timezone('UTC', action_timestamp))`)
90
- .execute();
91
- });
92
- }
93
- export function down(db) {
94
- return __awaiter(this, void 0, void 0, function* () {
95
- indexes.forEach((index) => __awaiter(this, void 0, void 0, function* () {
96
- yield db.schema.dropIndex(index.name).execute();
97
- }));
98
- db.schema.dropIndex('actions_day').execute();
99
- });
100
- }
@@ -1,38 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { sql } from 'kysely';
11
- const MATOMO_TABLE_NAME = process.env.MATOMO_TABLE_NAME || 'matomo';
12
- export function up(db) {
13
- return __awaiter(this, void 0, void 0, function* () {
14
- // Check if the column already exists before trying to add it
15
- const columnExists = yield sql `
16
- SELECT EXISTS (
17
- SELECT 1
18
- FROM information_schema.columns
19
- WHERE table_name = ${MATOMO_TABLE_NAME}
20
- AND column_name = 'resolution'
21
- ) as exists
22
- `.execute(db);
23
- if (!columnExists.rows[0].exists) {
24
- yield db.schema
25
- .alterTable(MATOMO_TABLE_NAME)
26
- .addColumn('resolution', 'text')
27
- .execute();
28
- }
29
- });
30
- }
31
- export function down(db) {
32
- return __awaiter(this, void 0, void 0, function* () {
33
- yield db.schema
34
- .alterTable(MATOMO_TABLE_NAME)
35
- .dropColumn('resolution')
36
- .execute();
37
- });
38
- }
@@ -1,359 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { sql } from 'kysely';
11
- import { PARTITIONED_MATOMO_TABLE_NAME } from '../config.js';
12
- export function up(db) {
13
- return __awaiter(this, void 0, void 0, function* () {
14
- // First, create the partitioned table structure as a partitioned table
15
- yield sql `
16
- CREATE TABLE ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}`)} (
17
- action_id text NOT NULL,
18
- idsite text,
19
- idvisit text,
20
- actions text,
21
- country text,
22
- region text,
23
- city text,
24
- operatingsystemname text,
25
- devicemodel text,
26
- devicebrand text,
27
- visitduration text,
28
- dayssincefirstvisit text,
29
- visitortype text,
30
- sitename text,
31
- userid text,
32
- serverdateprettyfirstaction date,
33
- action_type text,
34
- action_eventcategory text,
35
- action_eventaction text,
36
- action_eventname text,
37
- action_eventvalue numeric,
38
- action_timespent text,
39
- action_timestamp timestamptz NOT NULL DEFAULT now(),
40
- usercustomproperties json,
41
- usercustomdimensions json,
42
- dimension1 text,
43
- dimension2 text,
44
- dimension3 text,
45
- dimension4 text,
46
- dimension5 text,
47
- dimension6 text,
48
- dimension7 text,
49
- dimension8 text,
50
- dimension9 text,
51
- dimension10 text,
52
- action_url text,
53
- sitesearchkeyword text,
54
- action_title text,
55
- visitorid text,
56
- referrertype text,
57
- referrername text,
58
- resolution text
59
- ) PARTITION BY RANGE (action_timestamp);
60
- `.execute(db);
61
- // Add unique constraint that includes partition key
62
- yield sql `
63
- ALTER TABLE ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}`)}
64
- ADD CONSTRAINT ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}_action_id_timestamp_unique`)}
65
- UNIQUE (action_id, action_timestamp)
66
- `.execute(db);
67
- // Create function for automatic weekly partition creation
68
- yield sql `
69
- CREATE OR REPLACE FUNCTION create_weekly_partition_if_not_exists(table_name text, partition_date timestamptz)
70
- RETURNS void AS $$
71
- DECLARE
72
- partition_name text;
73
- start_date timestamptz;
74
- end_date timestamptz;
75
- year_week text;
76
- BEGIN
77
- -- Calculate the start of the week (Monday)
78
- start_date := date_trunc('week', partition_date);
79
- end_date := start_date + interval '1 week';
80
-
81
- -- Generate partition name using ISO week format (YYYY-WW)
82
- year_week := to_char(start_date, 'IYYY') || 'w' || to_char(start_date, 'IW');
83
- partition_name := table_name || '_' || year_week;
84
-
85
- -- Check if partition already exists
86
- IF NOT EXISTS (
87
- SELECT 1 FROM pg_class c
88
- JOIN pg_namespace n ON n.oid = c.relnamespace
89
- WHERE c.relname = partition_name
90
- AND n.nspname = current_schema()
91
- ) THEN
92
- -- Create the partition
93
- EXECUTE format('CREATE TABLE %I PARTITION OF %I FOR VALUES FROM (%L) TO (%L)',
94
- partition_name, table_name, start_date, end_date);
95
-
96
- RAISE NOTICE 'Created partition % for range % to %', partition_name, start_date, end_date;
97
- END IF;
98
- END;
99
- $$ LANGUAGE plpgsql;
100
- `.execute(db);
101
- // Create trigger function that automatically creates partitions on insert
102
- yield sql `
103
- CREATE OR REPLACE FUNCTION ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}_partition_trigger`)}()
104
- RETURNS trigger AS $$
105
- BEGIN
106
- PERFORM create_weekly_partition_if_not_exists('${sql.raw(PARTITIONED_MATOMO_TABLE_NAME)}', NEW.action_timestamp);
107
- RETURN NEW;
108
- END;
109
- $$ LANGUAGE plpgsql;
110
- `.execute(db);
111
- // Create trigger that fires before insert
112
- yield sql `
113
- CREATE TRIGGER ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}_auto_partition`)}
114
- BEFORE INSERT ON ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}`)}
115
- FOR EACH ROW EXECUTE FUNCTION ${sql.id(`${PARTITIONED_MATOMO_TABLE_NAME}_partition_trigger`)}();
116
- `.execute(db);
117
- // Create stored procedure for safe insertion with automatic partition creation
118
- yield sql `
119
- CREATE OR REPLACE FUNCTION insert_into_matomo_partitioned(
120
- p_action_id text,
121
- p_action_timestamp timestamptz,
122
- p_idsite text DEFAULT '',
123
- p_idvisit text DEFAULT '',
124
- p_actions text DEFAULT NULL,
125
- p_country text DEFAULT NULL,
126
- p_region text DEFAULT NULL,
127
- p_city text DEFAULT NULL,
128
- p_operatingsystemname text DEFAULT NULL,
129
- p_devicemodel text DEFAULT NULL,
130
- p_devicebrand text DEFAULT NULL,
131
- p_visitduration text DEFAULT NULL,
132
- p_dayssincefirstvisit text DEFAULT NULL,
133
- p_visitortype text DEFAULT NULL,
134
- p_sitename text DEFAULT NULL,
135
- p_userid text DEFAULT NULL,
136
- p_serverdateprettyfirstaction date DEFAULT NULL,
137
- p_action_type text DEFAULT '',
138
- p_action_eventcategory text DEFAULT '',
139
- p_action_eventaction text DEFAULT '',
140
- p_action_eventname text DEFAULT '',
141
- p_action_eventvalue numeric DEFAULT 0,
142
- p_action_timespent text DEFAULT '0',
143
- p_usercustomproperties json DEFAULT NULL,
144
- p_usercustomdimensions json DEFAULT NULL,
145
- p_dimension1 text DEFAULT NULL,
146
- p_dimension2 text DEFAULT NULL,
147
- p_dimension3 text DEFAULT NULL,
148
- p_dimension4 text DEFAULT NULL,
149
- p_dimension5 text DEFAULT NULL,
150
- p_dimension6 text DEFAULT NULL,
151
- p_dimension7 text DEFAULT NULL,
152
- p_dimension8 text DEFAULT NULL,
153
- p_dimension9 text DEFAULT NULL,
154
- p_dimension10 text DEFAULT NULL,
155
- p_action_url text DEFAULT NULL,
156
- p_sitesearchkeyword text DEFAULT NULL,
157
- p_action_title text DEFAULT NULL,
158
- p_visitorid text DEFAULT NULL,
159
- p_referrertype text DEFAULT NULL,
160
- p_referrername text DEFAULT NULL,
161
- p_resolution text DEFAULT NULL
162
- )
163
- RETURNS void
164
- LANGUAGE plpgsql
165
- SECURITY INVOKER
166
- AS $$
167
- BEGIN
168
- -- Ensure partition exists for the given timestamp
169
- PERFORM create_weekly_partition_if_not_exists('${sql.raw(PARTITIONED_MATOMO_TABLE_NAME)}', p_action_timestamp);
170
-
171
- -- Insert the data with conflict handling
172
- INSERT INTO ${sql.id(PARTITIONED_MATOMO_TABLE_NAME)} (
173
- action_id,
174
- action_timestamp,
175
- idsite,
176
- idvisit,
177
- actions,
178
- country,
179
- region,
180
- city,
181
- operatingsystemname,
182
- devicemodel,
183
- devicebrand,
184
- visitduration,
185
- dayssincefirstvisit,
186
- visitortype,
187
- sitename,
188
- userid,
189
- serverdateprettyfirstaction,
190
- action_type,
191
- action_eventcategory,
192
- action_eventaction,
193
- action_eventname,
194
- action_eventvalue,
195
- action_timespent,
196
- usercustomproperties,
197
- usercustomdimensions,
198
- dimension1,
199
- dimension2,
200
- dimension3,
201
- dimension4,
202
- dimension5,
203
- dimension6,
204
- dimension7,
205
- dimension8,
206
- dimension9,
207
- dimension10,
208
- action_url,
209
- sitesearchkeyword,
210
- action_title,
211
- visitorid,
212
- referrertype,
213
- referrername,
214
- resolution
215
- ) VALUES (
216
- p_action_id,
217
- p_action_timestamp,
218
- p_idsite,
219
- p_idvisit,
220
- p_actions,
221
- p_country,
222
- p_region,
223
- p_city,
224
- p_operatingsystemname,
225
- p_devicemodel,
226
- p_devicebrand,
227
- p_visitduration,
228
- p_dayssincefirstvisit,
229
- p_visitortype,
230
- p_sitename,
231
- p_userid,
232
- p_serverdateprettyfirstaction,
233
- p_action_type,
234
- p_action_eventcategory,
235
- p_action_eventaction,
236
- p_action_eventname,
237
- p_action_eventvalue,
238
- p_action_timespent,
239
- p_usercustomproperties,
240
- p_usercustomdimensions,
241
- p_dimension1,
242
- p_dimension2,
243
- p_dimension3,
244
- p_dimension4,
245
- p_dimension5,
246
- p_dimension6,
247
- p_dimension7,
248
- p_dimension8,
249
- p_dimension9,
250
- p_dimension10,
251
- p_action_url,
252
- p_sitesearchkeyword,
253
- p_action_title,
254
- p_visitorid,
255
- p_referrertype,
256
- p_referrername,
257
- p_resolution
258
- )
259
- ON CONFLICT (action_id, action_timestamp) DO NOTHING;
260
- END;
261
- $$;
262
- `.execute(db);
263
- // Create indexes on the partitioned table
264
- const indexes = [
265
- {
266
- name: `idx_action_eventaction_${PARTITIONED_MATOMO_TABLE_NAME}`,
267
- columns: ['action_eventaction']
268
- },
269
- {
270
- name: `idx_action_eventcategory_${PARTITIONED_MATOMO_TABLE_NAME}`,
271
- columns: ['action_eventcategory']
272
- },
273
- {
274
- name: `idx_action_id_${PARTITIONED_MATOMO_TABLE_NAME}`,
275
- columns: ['action_id']
276
- },
277
- {
278
- name: `idx_action_timestamp_${PARTITIONED_MATOMO_TABLE_NAME}`,
279
- columns: ['action_timestamp']
280
- },
281
- {
282
- name: `idx_action_type_${PARTITIONED_MATOMO_TABLE_NAME}`,
283
- columns: ['action_type']
284
- },
285
- {
286
- name: `idx_actionurl_${PARTITIONED_MATOMO_TABLE_NAME}`,
287
- columns: ['action_url']
288
- },
289
- {
290
- name: `idx_dimension1_${PARTITIONED_MATOMO_TABLE_NAME}`,
291
- columns: ['dimension1']
292
- },
293
- {
294
- name: `idx_dimension2_${PARTITIONED_MATOMO_TABLE_NAME}`,
295
- columns: ['dimension2']
296
- },
297
- {
298
- name: `idx_dimension3_${PARTITIONED_MATOMO_TABLE_NAME}`,
299
- columns: ['dimension3']
300
- },
301
- {
302
- name: `idx_dimension4_${PARTITIONED_MATOMO_TABLE_NAME}`,
303
- columns: ['dimension4']
304
- },
305
- {
306
- name: `idx_dimension5_${PARTITIONED_MATOMO_TABLE_NAME}`,
307
- columns: ['dimension5']
308
- },
309
- {
310
- name: `idx_idvisit_${PARTITIONED_MATOMO_TABLE_NAME}`,
311
- columns: ['idvisit']
312
- },
313
- {
314
- name: `idx_region_${PARTITIONED_MATOMO_TABLE_NAME}`,
315
- columns: ['region']
316
- },
317
- {
318
- name: `idx_userid_${PARTITIONED_MATOMO_TABLE_NAME}`,
319
- columns: ['userid']
320
- },
321
- {
322
- name: `idx_visitorid_${PARTITIONED_MATOMO_TABLE_NAME}`,
323
- columns: ['visitorid']
324
- },
325
- {
326
- name: `idx_category_timestamp_${PARTITIONED_MATOMO_TABLE_NAME}`,
327
- columns: ['action_eventcategory', 'action_timestamp']
328
- }
329
- ];
330
- // Create indexes
331
- for (const index of indexes) {
332
- yield db.schema
333
- .createIndex(index.name)
334
- .on(PARTITIONED_MATOMO_TABLE_NAME)
335
- .using('btree')
336
- .columns(index.columns)
337
- .execute();
338
- }
339
- // Create the date-based index
340
- yield db.schema
341
- .createIndex(`actions_day_${PARTITIONED_MATOMO_TABLE_NAME}`)
342
- .on(PARTITIONED_MATOMO_TABLE_NAME)
343
- .expression(sql `date(timezone('UTC', action_timestamp))`)
344
- .execute();
345
- });
346
- }
347
- export function down(db) {
348
- return __awaiter(this, void 0, void 0, function* () {
349
- // Drop trigger and function
350
- const trigger_name = `${PARTITIONED_MATOMO_TABLE_NAME}_auto_partition`;
351
- yield sql `DROP TRIGGER IF EXISTS ${sql.id(trigger_name)} ON ${sql.id(PARTITIONED_MATOMO_TABLE_NAME)}`.execute(db);
352
- const function_name = `${PARTITIONED_MATOMO_TABLE_NAME}_partition_trigger`;
353
- yield sql `DROP FUNCTION IF EXISTS ${sql.id(function_name)}()`.execute(db);
354
- yield sql `DROP FUNCTION IF EXISTS create_weekly_partition_if_not_exists(text, timestamptz)`.execute(db);
355
- yield sql `DROP FUNCTION IF EXISTS insert_into_matomo_partitioned`.execute(db);
356
- // Drop the partitioned table (this will also drop all partitions)
357
- yield db.schema.dropTable(PARTITIONED_MATOMO_TABLE_NAME).ifExists().execute();
358
- });
359
- }
@@ -1,29 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { sql } from 'kysely';
11
- const PARTITIONED_MATOMO_TABLE_NAME = process.env.PARTITIONED_MATOMO_TABLE_NAME || 'matomo_partitioned';
12
- export function up(db) {
13
- return __awaiter(this, void 0, void 0, function* () {
14
- // Create conditional index for convention collective analysis
15
- yield sql `
16
- CREATE INDEX IF NOT EXISTS idx_convention_analysis_matomo_partitioned
17
- ON ${sql.id(PARTITIONED_MATOMO_TABLE_NAME)} (action_type, action_url, action_timestamp)
18
- WHERE action_url LIKE 'https://code.travail.gouv.fr/convention-collective/%'
19
- `.execute(db);
20
- });
21
- }
22
- export function down(db) {
23
- return __awaiter(this, void 0, void 0, function* () {
24
- // Drop the conditional index
25
- yield sql `
26
- DROP INDEX IF EXISTS idx_convention_analysis_matomo_partitioned
27
- `.execute(db);
28
- });
29
- }