@socialgouv/matomo-postgres 2.2.5 â 2.3.1
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/README.md +39 -8
- package/dist/__tests__/run.test.js +3 -2
- package/dist/config.js +1 -0
- package/dist/db.js +17 -8
- package/dist/importDate.js +4 -1
- package/dist/importEvent.js +4 -1
- package/dist/index.js +11 -2
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -44,14 +44,15 @@ yarn add @socialgouv/matomo-postgres
|
|
|
44
44
|
|
|
45
45
|
### Optional Environment Variables
|
|
46
46
|
|
|
47
|
-
| Variable | Default | Description
|
|
48
|
-
| ------------------------------- | -------------------- |
|
|
49
|
-
| `DESTINATION_TABLE` | `matomo` | Selects which table to write to (normal or partitioned)
|
|
50
|
-
| `MATOMO_TABLE_NAME` | `matomo` | Name for the standard table
|
|
51
|
-
| `PARTITIONED_MATOMO_TABLE_NAME` | `matomo_partitioned` | Name for the partitioned table
|
|
52
|
-
| `STARTDATE` | Auto-detected | Override start date for initial import (YYYY-MM-DD)
|
|
53
|
-
| `
|
|
54
|
-
| `
|
|
47
|
+
| Variable | Default | Description |
|
|
48
|
+
| ------------------------------- | -------------------- | ------------------------------------------------------------------- |
|
|
49
|
+
| `DESTINATION_TABLE` | `matomo` | Selects which table to write to (normal or partitioned) |
|
|
50
|
+
| `MATOMO_TABLE_NAME` | `matomo` | Name for the standard table |
|
|
51
|
+
| `PARTITIONED_MATOMO_TABLE_NAME` | `matomo_partitioned` | Name for the partitioned table |
|
|
52
|
+
| `STARTDATE` | Auto-detected | Override start date for initial import (YYYY-MM-DD) |
|
|
53
|
+
| `FORCE_STARTDATE` | `false` | When `true`, skip database lookup and use STARTDATE unconditionally |
|
|
54
|
+
| `RESULTPERPAGE` | `500` | API pagination size (max results per request) |
|
|
55
|
+
| `INITIAL_OFFSET` | `3` | Days to look back on first run |
|
|
55
56
|
|
|
56
57
|
## đī¸ Table Architecture
|
|
57
58
|
|
|
@@ -90,6 +91,36 @@ Consider using partitioned tables when:
|
|
|
90
91
|
|
|
91
92
|
Both tables share the same schema structure, ensuring compatibility regardless of your choice.
|
|
92
93
|
|
|
94
|
+
### Forcing Start Date Override
|
|
95
|
+
|
|
96
|
+
When you need to temporarily override the automatic date detection (e.g., to re-import specific data or recover from errors):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
export FORCE_STARTDATE=true
|
|
100
|
+
export STARTDATE=2024-01-01
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This configuration will:
|
|
104
|
+
- Skip checking the database for the last event
|
|
105
|
+
- Use the specified `STARTDATE` unconditionally
|
|
106
|
+
- Useful for one-time re-imports or data recovery scenarios
|
|
107
|
+
|
|
108
|
+
**Important:** Remember to unset `FORCE_STARTDATE` after your one-time import to restore normal automatic detection behavior.
|
|
109
|
+
|
|
110
|
+
**Cronjob Example:**
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Temporarily add to your cronjob environment variables:
|
|
114
|
+
FORCE_STARTDATE=true
|
|
115
|
+
STARTDATE=2024-10-15
|
|
116
|
+
MATOMO_URL=https://analytics.example.com/
|
|
117
|
+
MATOMO_SITE=1
|
|
118
|
+
MATOMO_KEY=your_api_token
|
|
119
|
+
PGDATABASE=postgresql://user:pass@host:5432/db
|
|
120
|
+
|
|
121
|
+
# After import completes, remove FORCE_STARTDATE to resume normal operation
|
|
122
|
+
```
|
|
123
|
+
|
|
93
124
|
## đī¸ Architecture
|
|
94
125
|
|
|
95
126
|
The tool follows a systematic ETL process:
|
|
@@ -85,6 +85,7 @@ test('run: should run SQL queries', () => __awaiter(void 0, void 0, void 0, func
|
|
|
85
85
|
yield run();
|
|
86
86
|
expect(queries).toMatchSnapshot();
|
|
87
87
|
// Updated expectation based on actual behavior with INITIAL_OFFSET=3 (5 days total: 3 days before + today + 1 day after)
|
|
88
|
-
// 5 days * (6 events per day + 1 count query per day)
|
|
89
|
-
|
|
88
|
+
// 5 days * (6 events per day + 1 count query per day)
|
|
89
|
+
// Note: The initial findLastEventInMatomo query is not captured in the test mock environment
|
|
90
|
+
expect(queries.length).toEqual(5 * (6 + 1));
|
|
90
91
|
}));
|
package/dist/config.js
CHANGED
|
@@ -4,6 +4,7 @@ export const MATOMO_SITE = process.env.MATOMO_SITE || 0;
|
|
|
4
4
|
export const PGDATABASE = process.env.PGDATABASE || '';
|
|
5
5
|
export const INITIAL_OFFSET = process.env.INITIAL_OFFSET || '3';
|
|
6
6
|
export const RESULTPERPAGE = process.env.RESULTPERPAGE || '500';
|
|
7
|
+
export const FORCE_STARTDATE = process.env.FORCE_STARTDATE === 'true';
|
|
7
8
|
// We will create both a normal and a partitioned table (MATOMO_TABLE_NAME and PARTITIONED_MATOMO_TABLE_NAME)
|
|
8
9
|
// and use DESTINATION_TABLE to determine which one to write to.
|
|
9
10
|
export const DESTINATION_TABLE = process.env.DESTINATION_TABLE || 'matomo';
|
package/dist/db.js
CHANGED
|
@@ -4,19 +4,28 @@ import pkg from 'pg';
|
|
|
4
4
|
const { Pool } = pkg;
|
|
5
5
|
import { PGDATABASE } from './config.js';
|
|
6
6
|
startDebug('db');
|
|
7
|
+
export const pool = new Pool({
|
|
8
|
+
connectionString: PGDATABASE,
|
|
9
|
+
ssl: {
|
|
10
|
+
rejectUnauthorized: false
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
// Validate pool is properly initialized
|
|
14
|
+
if (!pool || typeof pool.connect !== 'function') {
|
|
15
|
+
throw new Error('Failed to initialize PostgreSQL connection pool');
|
|
16
|
+
}
|
|
7
17
|
export const db = new Kysely({
|
|
8
18
|
dialect: new PostgresDialect({
|
|
9
|
-
pool:
|
|
10
|
-
connectionString: PGDATABASE,
|
|
11
|
-
ssl: {
|
|
12
|
-
rejectUnauthorized: false
|
|
13
|
-
}
|
|
14
|
-
})
|
|
19
|
+
pool: pool
|
|
15
20
|
}),
|
|
16
21
|
log(event) {
|
|
17
22
|
if (event.level === 'query') {
|
|
18
|
-
// debug(event.query.sql)
|
|
19
|
-
// debug(event.query.parameters)
|
|
23
|
+
// debug(event.query.sql)
|
|
24
|
+
// debug(event.query.parameters)
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
});
|
|
28
|
+
// Validate the Kysely instance
|
|
29
|
+
if (!db) {
|
|
30
|
+
throw new Error('Failed to initialize Kysely database instance');
|
|
31
|
+
}
|
package/dist/importDate.js
CHANGED
|
@@ -12,13 +12,16 @@ import startDebug from 'debug';
|
|
|
12
12
|
import { sql } from 'kysely';
|
|
13
13
|
import pAll from 'p-all';
|
|
14
14
|
import { DESTINATION_TABLE, MATOMO_SITE, RESULTPERPAGE } from './config.js';
|
|
15
|
-
import { db } from './db.js';
|
|
15
|
+
import { db, pool } from './db.js';
|
|
16
16
|
import { getEventsFromMatomoVisit, importEvent } from './importEvent.js';
|
|
17
17
|
const debug = startDebug('importDate');
|
|
18
18
|
/** return date as ISO yyyy-mm-dd */
|
|
19
19
|
const isoDate = (date) => formatISO(date, { representation: 'date' });
|
|
20
20
|
/** check how many visits complete for a given date */
|
|
21
21
|
const getRecordsCount = (date) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
if (!pool || typeof pool.connect !== 'function') {
|
|
23
|
+
throw new Error('Database connection pool is invalid or undefined in getRecordsCount');
|
|
24
|
+
}
|
|
22
25
|
const result = yield db
|
|
23
26
|
.selectFrom(DESTINATION_TABLE)
|
|
24
27
|
.select(db.fn.count('idvisit').distinct().as('count'))
|
package/dist/importEvent.js
CHANGED
|
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
});
|
|
9
9
|
};
|
|
10
10
|
import { sql } from 'kysely';
|
|
11
|
-
import { db } from './db.js';
|
|
11
|
+
import { db, pool } from './db.js';
|
|
12
12
|
/**
|
|
13
13
|
*
|
|
14
14
|
* @param {Client} client
|
|
@@ -78,6 +78,9 @@ export const importEvent = (event) => __awaiter(void 0, void 0, void 0, function
|
|
|
78
78
|
throw new Error('importEvent(): action_timestamp is invalid');
|
|
79
79
|
}
|
|
80
80
|
try {
|
|
81
|
+
if (!pool || typeof pool.connect !== 'function') {
|
|
82
|
+
throw new Error('Database connection pool is invalid or undefined');
|
|
83
|
+
}
|
|
81
84
|
// Keep the stored procedure but centralize mapping to avoid parameter mis-ordering
|
|
82
85
|
yield sql `
|
|
83
86
|
SELECT insert_into_matomo_partitioned(
|
package/dist/index.js
CHANGED
|
@@ -27,15 +27,23 @@ function run(date) {
|
|
|
27
27
|
console.log(`đ
Determining reference date for import...`);
|
|
28
28
|
// priority:
|
|
29
29
|
// - optional parameter date
|
|
30
|
+
// - STARTDATE (if FORCE_STARTDATE is true)
|
|
30
31
|
// - last event in the table
|
|
31
|
-
// -
|
|
32
|
+
// - STARTDATE (if FORCE_STARTDATE is false)
|
|
32
33
|
// - today
|
|
33
34
|
let referenceDate;
|
|
34
35
|
if (!referenceDate && date) {
|
|
35
36
|
referenceDate = new Date(date);
|
|
36
37
|
console.log(`â
Using provided date parameter: ${referenceDate.toISOString()}`);
|
|
37
38
|
}
|
|
38
|
-
|
|
39
|
+
// Check FORCE_STARTDATE mode first
|
|
40
|
+
const forceStartDate = process.env.FORCE_STARTDATE === 'true';
|
|
41
|
+
if (!referenceDate && forceStartDate && process.env.STARTDATE) {
|
|
42
|
+
referenceDate = new Date(process.env.STARTDATE);
|
|
43
|
+
console.log(`â
FORCE_STARTDATE enabled - Using STARTDATE environment variable: ${referenceDate.toISOString()}`);
|
|
44
|
+
}
|
|
45
|
+
// Only query database if not forcing STARTDATE
|
|
46
|
+
if (!referenceDate && !forceStartDate) {
|
|
39
47
|
console.log(`đ Looking for last event in database...`);
|
|
40
48
|
referenceDate = yield findLastEventInMatomo(db);
|
|
41
49
|
if (referenceDate) {
|
|
@@ -45,6 +53,7 @@ function run(date) {
|
|
|
45
53
|
console.log(`âšī¸ No previous events found in database`);
|
|
46
54
|
}
|
|
47
55
|
}
|
|
56
|
+
// Fallback to STARTDATE if database had no results
|
|
48
57
|
if (!referenceDate && process.env.STARTDATE) {
|
|
49
58
|
referenceDate = new Date(process.env.STARTDATE);
|
|
50
59
|
console.log(`â
Using STARTDATE environment variable: ${referenceDate.toISOString()}`);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socialgouv/matomo-postgres",
|
|
3
3
|
"description": "Extract visitor events from Matomo API and push to Postgres",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.1",
|
|
5
5
|
"types": "types/index.d.ts",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"main": "dist/index.js",
|
|
@@ -10,15 +10,13 @@
|
|
|
10
10
|
"access": "public"
|
|
11
11
|
},
|
|
12
12
|
"type": "module",
|
|
13
|
-
"bin":
|
|
14
|
-
"matomo-postgres": "./bin/index.js"
|
|
15
|
-
},
|
|
13
|
+
"bin": "./bin/index.js",
|
|
16
14
|
"files": [
|
|
17
15
|
"bin",
|
|
18
16
|
"dist"
|
|
19
17
|
],
|
|
20
18
|
"scripts": {
|
|
21
|
-
"start": "yarn migrate && node ./
|
|
19
|
+
"start": "yarn migrate && node ./bin/index.js",
|
|
22
20
|
"build": "tsc",
|
|
23
21
|
"prepublish": "yarn build",
|
|
24
22
|
"migrate": "node ./dist/migrate-latest.js",
|