@golemio/chmu 1.1.1-dev.2637274244 → 1.1.1-dev.2644315801

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 (55) hide show
  1. package/dist/integration-engine/data-access/MeasurementsRepository.d.ts +1 -1
  2. package/dist/integration-engine/data-access/MeasurementsRepository.js +3 -4
  3. package/dist/integration-engine/data-access/MeasurementsRepository.js.map +1 -1
  4. package/dist/integration-engine/datasources/ChmuDatasource.js +1 -1
  5. package/dist/integration-engine/datasources/ChmuDatasource.js.map +1 -1
  6. package/dist/integration-engine/ioc/Di.js +4 -12
  7. package/dist/integration-engine/ioc/Di.js.map +1 -1
  8. package/dist/integration-engine/ioc/ModuleContainerToken.d.ts +0 -4
  9. package/dist/integration-engine/ioc/ModuleContainerToken.js +0 -5
  10. package/dist/integration-engine/ioc/ModuleContainerToken.js.map +1 -1
  11. package/dist/integration-engine/transformations/MeasurementsTransformation.d.ts +2 -2
  12. package/dist/integration-engine/transformations/MeasurementsTransformation.js +5 -20
  13. package/dist/integration-engine/transformations/MeasurementsTransformation.js.map +1 -1
  14. package/dist/integration-engine/workers/ChmuWorker.js +2 -3
  15. package/dist/integration-engine/workers/ChmuWorker.js.map +1 -1
  16. package/dist/integration-engine/workers/tasks/DownloadMeasurementsTask.d.ts +3 -3
  17. package/dist/integration-engine/workers/tasks/DownloadMeasurementsTask.js +6 -6
  18. package/dist/integration-engine/workers/tasks/DownloadMeasurementsTask.js.map +1 -1
  19. package/dist/schema-definitions/definitions/interfaces/IMeasurementDto.d.ts +0 -18
  20. package/dist/schema-definitions/definitions/models/MeasurementModel.d.ts +1 -19
  21. package/dist/schema-definitions/definitions/models/MeasurementModel.js +1 -37
  22. package/dist/schema-definitions/definitions/models/MeasurementModel.js.map +1 -1
  23. package/docs/asyncapi.yaml +3 -35
  24. package/docs/implementation_documentation.md +23 -81
  25. package/package.json +9 -25
  26. package/db/migrations/postgresql/20260619120000-opendata-columns.js +0 -49
  27. package/db/migrations/postgresql/sqls/20260619120000-opendata-columns-down.sql +0 -36
  28. package/db/migrations/postgresql/sqls/20260619120000-opendata-columns-up.sql +0 -40
  29. package/dist/integration-engine/data-access/StationsRepository.d.ts +0 -8
  30. package/dist/integration-engine/data-access/StationsRepository.js +0 -57
  31. package/dist/integration-engine/data-access/StationsRepository.js.map +0 -1
  32. package/dist/integration-engine/datasources/OpendataDatasource.d.ts +0 -30
  33. package/dist/integration-engine/datasources/OpendataDatasource.js +0 -80
  34. package/dist/integration-engine/datasources/OpendataDatasource.js.map +0 -1
  35. package/dist/integration-engine/transformations/OpendataMeasurementsTransformation.d.ts +0 -15
  36. package/dist/integration-engine/transformations/OpendataMeasurementsTransformation.js +0 -128
  37. package/dist/integration-engine/transformations/OpendataMeasurementsTransformation.js.map +0 -1
  38. package/dist/integration-engine/workers/interfaces/IDownloadOpendataMessage.d.ts +0 -8
  39. package/dist/integration-engine/workers/interfaces/IDownloadOpendataMessage.js +0 -3
  40. package/dist/integration-engine/workers/interfaces/IDownloadOpendataMessage.js.map +0 -1
  41. package/dist/integration-engine/workers/tasks/DownloadOpendataMeasurementsTask.d.ts +0 -22
  42. package/dist/integration-engine/workers/tasks/DownloadOpendataMeasurementsTask.js +0 -112
  43. package/dist/integration-engine/workers/tasks/DownloadOpendataMeasurementsTask.js.map +0 -1
  44. package/dist/integration-engine/workers/tasks/DownloadOpendataMessageSchema.d.ts +0 -6
  45. package/dist/integration-engine/workers/tasks/DownloadOpendataMessageSchema.js +0 -33
  46. package/dist/integration-engine/workers/tasks/DownloadOpendataMessageSchema.js.map +0 -1
  47. package/dist/schema-definitions/datasources/OpendataSchemaProvider.d.ts +0 -55
  48. package/dist/schema-definitions/datasources/OpendataSchemaProvider.js +0 -47
  49. package/dist/schema-definitions/datasources/OpendataSchemaProvider.js.map +0 -1
  50. package/dist/schema-definitions/datasources/interfaces/IInputOpendataRecord.d.ts +0 -15
  51. package/dist/schema-definitions/datasources/interfaces/IInputOpendataRecord.js +0 -3
  52. package/dist/schema-definitions/datasources/interfaces/IInputOpendataRecord.js.map +0 -1
  53. package/dist/schema-definitions/index.d.ts +0 -1
  54. package/dist/schema-definitions/index.js +0 -19
  55. package/dist/schema-definitions/index.js.map +0 -1
@@ -2,120 +2,62 @@
2
2
 
3
3
  ## Záměr
4
4
 
5
- Modul slouží ke stažení ČHMÚ meteorologických dat ze dvou zdrojů:
6
-
7
- - **FTP pipeline** - hodinová CSV data z interního FTP (`data_source = 'ftp'`)
8
- - **Opendata pipeline** - desetiminutová JSON data z veřejného ČHMÚ opendata API (`data_source = 'opendata'`)
9
-
10
- Data z obou zdrojů se ukládají do stejné tabulky `chmu.measurements` pomocí UPSERT (PK: `measured_at`, `station_id`, `data_source`).
5
+ Modul slouží ke stažení chmu dat z ftp agregovaných po hodině do csv souborů.
11
6
 
12
7
  ## Vstupní data
13
8
 
14
9
  ### Data aktivně stahujeme
15
10
 
16
- #### *ChmuDatasource* (FTP)
11
+ Popis dat, jak je pomocí cronu a integration-engine stahujeme. Pokud jsou data stahována z více zdrojů, každý zdroj je popsán zvlášť.
12
+
13
+ #### *ChmuDatasource*
17
14
 
18
15
  - zdroj dat
19
- - golemio FTP
16
+ - golemio ftp
20
17
  - formát dat
21
- - CSV soubor, oddělovač `;`, kódování UTF-8
22
- - [validační schéma](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/schema-definitions/datasources/ChmuSchemaProvider.ts)
18
+ - csv soubor
19
+ - [validační schéma: ](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/schema-definitions/datasources/ChmuSchemaProvider.ts)
23
20
  - [příklad vstupních dat](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/test/data/6443_2023020215.txt)
24
21
  - frekvence stahování
25
22
  - jednou za hodinu
26
- - název RabbitMQ fronty
23
+ - název rabbitmq fronty
27
24
  - `chmu.downloadMeasurementsTask`
28
25
 
29
- #### *OpendataDatasource* (opendata)
30
-
31
- - zdroj dat
32
- - ČHMÚ opendata
33
- - URL: `https://opendata.chmi.cz/meteorology/climate/now/data/10m-{WSI}-{YYYYMMDD}.json`
34
- - soubor pokrývá celý den; každou hodinu přibývají nové záznamy za uplynulou hodinu
35
- - formát dat
36
- - JSON, long-format záznamy: `[STATION, ELEMENT, DT, VAL, FLAG, QUALITY]`
37
- - FLAG: kód podmínky pro zvláštní meteorologické situace (např. `"V"`, `"A"`); typicky `""`
38
- - QUALITY: `0.0` = dobrá, `1.0` = podezřelá, `2.0` = nízká kvalita, `3.0` = odhadnutá, `4.0` = chybějící, `5.0` = neznámá
39
- - VAL: číselná hodnota, nebo `""` při chybějícím měření (QUALITY = 4.0)
40
- - DT ve formátu ISO 8601 UTC (`2026-06-25T10:00:00Z`)
41
- - frekvence stahování
42
- - jednou denně (soubor pokrývá celý předchozí den)
43
- - název RabbitMQ fronty
44
- - `chmu.downloadOpendataMeasurementsTask`
45
- - poznámka
46
- - Zpracovány jsou pouze stanice s vyplněným sloupcem `wsi` v `chmu.stations`; ostatní jsou přeskočeny.
47
-
48
26
  ## Zpracování dat / transformace
49
27
 
28
+ Popis transformace a případného obohacení dat. Zaměřeno hlavně na workery a jejich metody.
29
+
50
30
  ### *ChmuWorker*
51
31
 
52
- #### *DownloadMeasurementsTask* (FTP)
32
+ Stručný popis workeru.
53
33
 
54
- - vstupní RabbitMQ fronta
55
- - `chmu.downloadMeasurementsTask`
56
- - parametry `from` a `to` - volitelné ISO 8601 timestampy; bez parametrů stáhne aktuální hodinu; s rozsahem generuje subtasky po hodinách
34
+ #### *DownloadMeasurementsTask*
35
+
36
+ - vstupní rabbitmq fronta
37
+ - název `chmu.downloadMeasurementsTask`
38
+ - parametry `from` and `to` volitelné parametry v iso formátu
57
39
  - datové zdroje
58
- - `ChmuDatasource` - stáhne hodinový CSV soubor z FTP
40
+ - `ChmuDatasource`
59
41
  - transformace
60
- - [MeasurementsTransformation](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/integration-engine/transformations/MeasurementsTransformation.ts)
61
- - mapování CSV polí na DB sloupce, převod desetinné čárky, `data_source = 'ftp'`
42
+ - odkaz na transformaci dat, případně stručný popis tranformace
43
+ - [transformace dat](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/integration-engine/transformations/MeasurementsTransformation.ts)
62
44
  - data modely
63
45
  - [MeasurementModel](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/schema-definitions/definitions/models/MeasurementModel.ts)
64
46
 
65
- #### *DownloadOpendataMeasurementsTask* (opendata)
66
-
67
- - vstupní RabbitMQ fronta
68
- - `chmu.downloadOpendataMeasurementsTask`
69
- - parametr `date` - volitelný ISO 8601 datum; bez parametru stáhne aktuální den
70
- - tok zpracování
71
- 1. `StationsRepository` - načte stanice s vyplněným WSI z `chmu.stations`
72
- 2. `OpendataDatasource` - pro každou stanici stáhne denní 10m JSON soubor
73
- 3. Přiřazení `station_id` dle WSI -> `station_id` mappingu
74
- 4. `OpendataMeasurementsTransformation` - pivot long->wide; skupinování dle `(station_id, DT)`; `data_source = 'opendata'`
75
- 5. `MeasurementsRepository` - UPSERT do `chmu.measurements`
76
- - mapování ELEMENT -> DB sloupec
77
-
78
- | ELEMENT | DB sloupec | Poznámka |
79
- |---------|-----------|---------|
80
- | T | air_temp | |
81
- | H | air_hum | |
82
- | P | air_pressure | |
83
- | F | wind_speed | |
84
- | D | wind_dir | |
85
- | SRA10M | precip | |
86
- | SSV10M | sunlight | ÷ 360 (s -> desetinné hodiny) |
87
- | TMA | air_temp_max | |
88
- | TMI | air_temp_min | |
89
- | TPM | air_temp_ground | |
90
- | Fprum | wind_speed_avg | |
91
- | Dprum | wind_dir_avg | |
92
- | Fmax | wind_gust | |
93
- | Dmax | wind_gust_dir | |
94
- | Casmax | wind_gust_time | |
95
- | SCEa | snow_depth | |
96
- | SVHa | snow_water | |
97
- | RGLB10 | radiation_glob | |
98
- | REUV10 / REUV25 | radiation_uv | |
99
- | T05–T100 | soil_temp_5cm–soil_temp_100cm | |
100
47
 
101
- - data modely
102
- - [MeasurementModel](https://gitlab.com/operator-ict/golemio/code/modules/chmu/-/blob/development/src/schema-definitions/definitions/models/MeasurementModel.ts)
103
48
 
104
49
  ## Uložení dat
105
50
 
51
+ Popis ukládání dat.
52
+
106
53
  ### Obecné
107
54
 
108
55
  - typ databáze
109
- - PostgreSQL
110
- - databázové schéma
56
+ - PSQL
57
+ - datábázové schéma
111
58
  - schéma: `chmu`
112
59
  ![chmu er diagram](assets/chmu.erd.png)
113
60
  - retence dat
114
61
  - data jsou zachována
115
62
  - AsyncApi dokumentace
116
63
  - [AsyncApi](./asyncapi.yaml)
117
-
118
- ### Poznámky k datové kvalitě
119
-
120
- - Sloupce `soil_hum_0_10`, `soil_hum_10_50`, `soil_hum_50_100` zůstávají v DB, ale opendata zdroj půdní vlhkost neobsahuje - všechny záznamy s `data_source = 'opendata'` mají tyto sloupce `NULL`.
121
- - Timezone: DT z opendata přichází jako UTC a je převedeno do Europe/Prague pro výpočet zobrazovacích polí (`time`, `year`, `month`, `day`).
package/package.json CHANGED
@@ -1,33 +1,15 @@
1
1
  {
2
2
  "name": "@golemio/chmu",
3
- "version": "1.1.1-dev.2637274244",
3
+ "version": "1.1.1-dev.2644315801",
4
4
  "description": "Golemio CHMU module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "imports": {
8
- "#ie": {
9
- "development": "./src/integration-engine/index.ts",
10
- "default": "./dist/integration-engine/index.js"
11
- },
12
- "#ie/*": {
13
- "development": "./src/integration-engine/*.ts",
14
- "default": "./dist/integration-engine/*.js"
15
- },
16
- "#sch": {
17
- "development": "./src/schema-definitions/index.ts",
18
- "default": "./dist/schema-definitions/index.js"
19
- },
20
- "#sch/*": {
21
- "development": "./src/schema-definitions/*.ts",
22
- "default": "./dist/schema-definitions/*.js"
23
- }
24
- },
25
7
  "scripts": {
26
- "build": "rimraf ./dist && tsc -p ./tsconfig.build.json",
8
+ "build": "rimraf ./dist && tspc -p ./tsconfig.build.json",
27
9
  "build-minimal": "run-s 'build -- --sourceMap false --declaration false'",
28
10
  "build-watch": "run-s 'build -- --watch --preserveWatchOutput'",
29
11
  "prepare-db": "golemio import-db-data --postgres",
30
- "test:only": "cross-env NODE_ENV=test NODE_OPTIONS=\"--conditions=development --import=tsx\" mocha --exit --check-leaks --timeout 120000 -r dotenv/config --file 'test/setup.ts' 'test/**/*.test.ts'",
12
+ "test:only": "cross-env NODE_ENV=test mocha --exit --check-leaks --timeout 120000 -r ts-node/register -r tsconfig-paths/register -r dotenv/config --file 'test/setup.ts' 'test/**/*.test.ts'",
31
13
  "test": "run-s prepare-db test:only",
32
14
  "test-debug": "run-s 'test -- --inspect-brk=9230'",
33
15
  "coverage:only": "nyc --reporter=text --reporter=lcov npm run test:only -- -r source-map-support/register",
@@ -53,10 +35,9 @@
53
35
  "@commitlint/cli": "^11.0.0",
54
36
  "@commitlint/config-conventional": "^11.0.0",
55
37
  "@golemio/cli": "1.11.2",
56
- "@golemio/core": "3.2.2-dev.2622707631",
38
+ "@golemio/core": "3.1.1",
57
39
  "@golemio/db-common": "1.2.2",
58
40
  "@golemio/eslint-config": "1.1.4",
59
- "@swc/core": "^1.15.33",
60
41
  "@types/chai": "^5.2.3",
61
42
  "@types/chai-as-promised": "^8.0.2",
62
43
  "@types/mocha": "^10.0.10",
@@ -78,9 +59,12 @@
78
59
  "sinon": "^21.0.1",
79
60
  "source-map-support": "0.5.21",
80
61
  "supertest": "^7.1.4",
81
- "tsx": "^4.20.6",
62
+ "ts-node": "^10.9.1",
63
+ "ts-patch": "3.0.0-beta3",
64
+ "tsconfig-paths": "^4.2.0",
82
65
  "typedoc": "^0.24.8",
83
- "typescript": "6.0.3"
66
+ "typescript": "5.1.3",
67
+ "typescript-transform-paths": "^3.4.6"
84
68
  },
85
69
  "peerDependencies": {
86
70
  "@golemio/core": ">=1.7.0"
@@ -1,49 +0,0 @@
1
- 'use strict';
2
-
3
- var dbm;
4
- var type;
5
- var seed;
6
- var fs = require('fs');
7
- var path = require('path');
8
- var Promise;
9
-
10
- exports.setup = function(options, seedLink) {
11
- dbm = options.dbmigrate;
12
- type = dbm.dataType;
13
- seed = seedLink;
14
- Promise = options.Promise;
15
- };
16
-
17
- exports.up = function(db) {
18
- var filePath = path.join(__dirname, 'sqls', '20260619120000-opendata-columns-up.sql');
19
- return new Promise( function( resolve, reject ) {
20
- fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
21
- if (err) return reject(err);
22
- console.log('received data: ' + data);
23
-
24
- resolve(data);
25
- });
26
- })
27
- .then(function(data) {
28
- return db.runSql(data);
29
- });
30
- };
31
-
32
- exports.down = function(db) {
33
- var filePath = path.join(__dirname, 'sqls', '20260619120000-opendata-columns-down.sql');
34
- return new Promise( function( resolve, reject ) {
35
- fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
36
- if (err) return reject(err);
37
- console.log('received data: ' + data);
38
-
39
- resolve(data);
40
- });
41
- })
42
- .then(function(data) {
43
- return db.runSql(data);
44
- });
45
- };
46
-
47
- exports._meta = {
48
- "version": 1
49
- };
@@ -1,36 +0,0 @@
1
- ALTER TABLE measurements
2
- DROP CONSTRAINT measurements_pk,
3
- ADD CONSTRAINT measurements_pk PRIMARY KEY (measured_at, station_id);
4
-
5
- ALTER TABLE measurements
6
- DROP COLUMN IF EXISTS air_temp_max,
7
- DROP COLUMN IF EXISTS air_temp_min,
8
- DROP COLUMN IF EXISTS air_temp_ground,
9
- DROP COLUMN IF EXISTS wind_speed_avg,
10
- DROP COLUMN IF EXISTS wind_dir_avg,
11
- DROP COLUMN IF EXISTS wind_gust,
12
- DROP COLUMN IF EXISTS wind_gust_dir,
13
- DROP COLUMN IF EXISTS wind_gust_time,
14
- DROP COLUMN IF EXISTS snow_depth,
15
- DROP COLUMN IF EXISTS snow_water,
16
- DROP COLUMN IF EXISTS radiation_glob,
17
- DROP COLUMN IF EXISTS radiation_uv,
18
- DROP COLUMN IF EXISTS soil_temp_5cm,
19
- DROP COLUMN IF EXISTS soil_temp_10cm,
20
- DROP COLUMN IF EXISTS soil_temp_20cm,
21
- DROP COLUMN IF EXISTS soil_temp_50cm,
22
- DROP COLUMN IF EXISTS soil_temp_100cm,
23
- DROP COLUMN IF EXISTS data_source;
24
-
25
- ALTER TABLE stations
26
- DROP COLUMN IF EXISTS wsi,
27
- DROP COLUMN IF EXISTS air_temp_max,
28
- DROP COLUMN IF EXISTS air_temp_min,
29
- DROP COLUMN IF EXISTS air_temp_ground,
30
- DROP COLUMN IF EXISTS wind_speed_avg,
31
- DROP COLUMN IF EXISTS wind_gust,
32
- DROP COLUMN IF EXISTS snow_depth,
33
- DROP COLUMN IF EXISTS snow_water,
34
- DROP COLUMN IF EXISTS radiation_glob,
35
- DROP COLUMN IF EXISTS radiation_uv,
36
- DROP COLUMN IF EXISTS soil_temp;
@@ -1,40 +0,0 @@
1
- -- Add WSI identifier and boolean flags for new measurement elements to stations
2
- -- NOTE: Populate chmu.stations.wsi and the boolean flag columns (manually) before running the opendata pipeline.
3
- ALTER TABLE stations
4
- ADD COLUMN wsi varchar NULL,
5
- ADD COLUMN air_temp_max boolean NULL,
6
- ADD COLUMN air_temp_min boolean NULL,
7
- ADD COLUMN air_temp_ground boolean NULL,
8
- ADD COLUMN wind_speed_avg boolean NULL,
9
- ADD COLUMN wind_gust boolean NULL,
10
- ADD COLUMN snow_depth boolean NULL,
11
- ADD COLUMN snow_water boolean NULL,
12
- ADD COLUMN radiation_glob boolean NULL,
13
- ADD COLUMN radiation_uv boolean NULL,
14
- ADD COLUMN soil_temp boolean NULL;
15
-
16
- -- Add new measurement columns and data_source to measurements
17
- ALTER TABLE measurements
18
- ADD COLUMN air_temp_max double precision NULL,
19
- ADD COLUMN air_temp_min double precision NULL,
20
- ADD COLUMN air_temp_ground double precision NULL,
21
- ADD COLUMN wind_speed_avg double precision NULL,
22
- ADD COLUMN wind_dir_avg double precision NULL,
23
- ADD COLUMN wind_gust double precision NULL,
24
- ADD COLUMN wind_gust_dir double precision NULL,
25
- ADD COLUMN wind_gust_time integer NULL,
26
- ADD COLUMN snow_depth double precision NULL,
27
- ADD COLUMN snow_water double precision NULL,
28
- ADD COLUMN radiation_glob double precision NULL,
29
- ADD COLUMN radiation_uv double precision NULL,
30
- ADD COLUMN soil_temp_5cm double precision NULL,
31
- ADD COLUMN soil_temp_10cm double precision NULL,
32
- ADD COLUMN soil_temp_20cm double precision NULL,
33
- ADD COLUMN soil_temp_50cm double precision NULL,
34
- ADD COLUMN soil_temp_100cm double precision NULL,
35
- ADD COLUMN data_source varchar(10) NOT NULL DEFAULT 'ftp';
36
-
37
- -- Add data_source to PK to prevent FTP/opendata record collision at shared timestamps
38
- ALTER TABLE measurements
39
- DROP CONSTRAINT measurements_pk,
40
- ADD CONSTRAINT measurements_pk PRIMARY KEY (measured_at, station_id, data_source);
@@ -1,8 +0,0 @@
1
- import { IModel, PostgresModel } from "@golemio/core/dist/integration-engine";
2
- export declare class StationsRepository extends PostgresModel implements IModel {
3
- constructor();
4
- getStationsWithWsi: () => Promise<Array<{
5
- station_id: string;
6
- wsi: string;
7
- }>>;
8
- }
@@ -1,57 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.StationsRepository = void 0;
13
- const integration_engine_1 = require("@golemio/core/dist/integration-engine");
14
- const golemio_validator_1 = require("@golemio/core/dist/shared/golemio-validator");
15
- const sequelize_1 = require("@golemio/core/dist/shared/sequelize");
16
- const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe");
17
- const const_1 = require("../../const");
18
- class StationWsiModel extends sequelize_1.Model {
19
- }
20
- StationWsiModel.attributeModel = {
21
- station_id: { type: sequelize_1.DataTypes.STRING, primaryKey: true },
22
- wsi: { type: sequelize_1.DataTypes.STRING, allowNull: true },
23
- };
24
- let StationsRepository = class StationsRepository extends integration_engine_1.PostgresModel {
25
- constructor() {
26
- super("ChmuStationsRepository", {
27
- outputSequelizeAttributes: StationWsiModel.attributeModel,
28
- pgTableName: "stations",
29
- pgSchema: const_1.SCHEMA_NAME,
30
- savingType: "insertOrUpdate",
31
- }, new golemio_validator_1.JSONSchemaValidator("ChmuStationsValidator", {
32
- type: "array",
33
- items: {
34
- type: "object",
35
- properties: {
36
- station_id: { type: "string" },
37
- wsi: { oneOf: [{ type: "string" }, { type: "null", nullable: true }] },
38
- },
39
- required: ["station_id"],
40
- },
41
- }));
42
- this.getStationsWithWsi = async () => {
43
- const rows = await this.sequelizeModel.findAll({
44
- where: { wsi: { [sequelize_1.Op.not]: null } },
45
- attributes: ["station_id", "wsi"],
46
- raw: true,
47
- });
48
- return rows;
49
- };
50
- }
51
- };
52
- exports.StationsRepository = StationsRepository;
53
- exports.StationsRepository = StationsRepository = __decorate([
54
- (0, tsyringe_1.injectable)(),
55
- __metadata("design:paramtypes", [])
56
- ], StationsRepository);
57
- //# sourceMappingURL=StationsRepository.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"StationsRepository.js","sourceRoot":"","sources":["../../../src/integration-engine/data-access/StationsRepository.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8EAA8E;AAC9E,mFAAkF;AAClF,mEAA4F;AAC5F,iEAAgE;AAChE,uCAA0C;AAO1C,MAAM,eAAgB,SAAQ,iBAAkB;;AAI9B,8BAAc,GAAkD;IAC1E,UAAU,EAAE,EAAE,IAAI,EAAE,qBAAS,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE;IACxD,GAAG,EAAE,EAAE,IAAI,EAAE,qBAAS,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE;CACnD,CAAC;AAIC,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,kCAAa;IACjD;QACI,KAAK,CACD,wBAAwB,EACxB;YACI,yBAAyB,EAAE,eAAe,CAAC,cAAc;YACzD,WAAW,EAAE,UAAU;YACvB,QAAQ,EAAE,mBAAW;YACrB,UAAU,EAAE,gBAAgB;SAC/B,EACD,IAAI,uCAAmB,CAAC,uBAAuB,EAAE;YAC7C,IAAI,EAAE,OAAO;YACb,KAAK,EAAE;gBACH,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACR,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;oBAC9B,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE;iBACzE;gBACD,QAAQ,EAAE,CAAC,YAAY,CAAC;aAC3B;SACJ,CAAC,CACL,CAAC;QAGC,uBAAkB,GAAG,KAAK,IAAyD,EAAE;YACxF,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAkB;gBAC5D,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,cAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE;gBAClC,UAAU,EAAE,CAAC,YAAY,EAAE,KAAK,CAAC;gBACjC,GAAG,EAAE,IAAI;aACZ,CAAC,CAAC;YACH,OAAO,IAA6D,CAAC;QACzE,CAAC,CAAC;IATF,CAAC;CAUJ,CAAA;AAhCY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,qBAAU,GAAE;;GACA,kBAAkB,CAgC9B"}
@@ -1,30 +0,0 @@
1
- import { ISimpleConfig } from "@golemio/core/dist/helpers/configuration/ISimpleConfig";
2
- /** Raw record shape as returned by the ČHMÚ opendata API after unpacking values rows. */
3
- interface IRawOpendataRecord {
4
- STATION: string;
5
- ELEMENT: string;
6
- DT: string;
7
- VAL: number | "";
8
- FLAG: string;
9
- QUALITY: number;
10
- }
11
- export default class OpendataDatasource {
12
- name: string;
13
- private readonly responseValidator;
14
- private readonly recordValidator;
15
- private readonly baseUrl;
16
- constructor(config: ISimpleConfig);
17
- /**
18
- * Fetches the 10-minute JSON file for one station from ČHMÚ opendata.
19
- * Returns unpacked records with named fields (STATION = WSI).
20
- *
21
- * @param wsi Station WSI identifier (e.g. "0-20000-0-11520")
22
- * @param date Date for which to fetch data (defaults to today)
23
- */
24
- getData(wsi: string, date?: Date): Promise<IRawOpendataRecord[]>;
25
- private getDatasource;
26
- private parseHeader;
27
- private mapToRecords;
28
- private buildUrl;
29
- }
30
- export {};
@@ -1,80 +0,0 @@
1
- "use strict";
2
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
- return c > 3 && r && Object.defineProperty(target, key, r), r;
7
- };
8
- var __metadata = (this && this.__metadata) || function (k, v) {
9
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
- };
11
- var __param = (this && this.__param) || function (paramIndex, decorator) {
12
- return function (target, key) { decorator(target, key, paramIndex); }
13
- };
14
- var __importDefault = (this && this.__importDefault) || function (mod) {
15
- return (mod && mod.__esModule) ? mod : { "default": mod };
16
- };
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- const CoreToken_1 = require("@golemio/core/dist/helpers/ioc/CoreToken");
19
- const datasources_1 = require("@golemio/core/dist/integration-engine/datasources");
20
- const HTTPFetchProtocolStrategy_1 = require("@golemio/core/dist/integration-engine/datasources/protocol-strategy/HTTPFetchProtocolStrategy");
21
- const luxon_1 = require("@golemio/core/dist/shared/luxon");
22
- const golemio_validator_1 = require("@golemio/core/dist/shared/golemio-validator");
23
- const tsyringe_1 = require("@golemio/core/dist/shared/tsyringe");
24
- const OpendataSchemaProvider_1 = __importDefault(require("#sch/datasources/OpendataSchemaProvider"));
25
- const REQUIRED_COLUMNS = ["STATION", "ELEMENT", "DT", "VAL", "FLAG", "QUALITY"];
26
- let OpendataDatasource = class OpendataDatasource {
27
- constructor(config) {
28
- this.name = "OpendataDatasource";
29
- this.responseValidator = new golemio_validator_1.JSONSchemaValidator("OpendataResponseValidator", OpendataSchemaProvider_1.default.getResponseSchema());
30
- this.recordValidator = new golemio_validator_1.JSONSchemaValidator("OpendataRecordValidator", OpendataSchemaProvider_1.default.get());
31
- this.baseUrl = config.getValue("module.chmu.opendata.baseUrl");
32
- }
33
- /**
34
- * Fetches the 10-minute JSON file for one station from ČHMÚ opendata.
35
- * Returns unpacked records with named fields (STATION = WSI).
36
- *
37
- * @param wsi Station WSI identifier (e.g. "0-20000-0-11520")
38
- * @param date Date for which to fetch data (defaults to today)
39
- */
40
- async getData(wsi, date = new Date()) {
41
- const { header, values } = await this.getDatasource(this.buildUrl(wsi, date)).getAll();
42
- const colIndex = this.parseHeader(header);
43
- const records = this.mapToRecords(values, colIndex);
44
- await this.recordValidator.Validate(records);
45
- return records;
46
- }
47
- getDatasource(url) {
48
- return new datasources_1.DataSource("OpendataHttpDataSource", new HTTPFetchProtocolStrategy_1.HTTPFetchProtocolStrategy({ url, method: "GET", responseType: "json" }), new datasources_1.JSONDataTypeStrategy({ resultsPath: "data.data" }), this.responseValidator);
49
- }
50
- parseHeader(header) {
51
- const colIndex = Object.fromEntries(header.split(",").map((c, i) => [c, i]));
52
- const missing = REQUIRED_COLUMNS.filter((c) => colIndex[c] === undefined);
53
- if (missing.length > 0) {
54
- throw new Error(`OpendataDatasource: missing columns in header: ${missing.join(", ")}`);
55
- }
56
- return colIndex;
57
- }
58
- mapToRecords(values, colIndex) {
59
- return values.map((row) => ({
60
- STATION: row[colIndex["STATION"]],
61
- ELEMENT: row[colIndex["ELEMENT"]],
62
- DT: row[colIndex["DT"]],
63
- VAL: row[colIndex["VAL"]],
64
- FLAG: row[colIndex["FLAG"]],
65
- QUALITY: row[colIndex["QUALITY"]],
66
- }));
67
- }
68
- buildUrl(wsi, date) {
69
- const dt = luxon_1.DateTime.fromJSDate(date).setZone("Europe/Prague");
70
- const yyyymmdd = dt.toFormat("yyyyMMdd");
71
- return `${this.baseUrl}/10m-${wsi}-${yyyymmdd}.json`;
72
- }
73
- };
74
- OpendataDatasource = __decorate([
75
- (0, tsyringe_1.injectable)(),
76
- __param(0, (0, tsyringe_1.inject)(CoreToken_1.CoreToken.SimpleConfig)),
77
- __metadata("design:paramtypes", [Object])
78
- ], OpendataDatasource);
79
- exports.default = OpendataDatasource;
80
- //# sourceMappingURL=OpendataDatasource.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"OpendataDatasource.js","sourceRoot":"","sources":["../../../src/integration-engine/datasources/OpendataDatasource.ts"],"names":[],"mappings":"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"}
@@ -1,15 +0,0 @@
1
- import IInputOpendataRecord from "#sch/datasources/interfaces/IInputOpendataRecord";
2
- import { IMeasurementDto } from "#sch/definitions/interfaces/IMeasurementDto";
3
- import { ITransformation } from "@golemio/core/dist/integration-engine";
4
- import { AbstractTransformation } from "@golemio/core/dist/helpers/transformation/AbstractTransformation";
5
- export declare class OpendataMeasurementsTransformation extends AbstractTransformation<IInputOpendataRecord[], IMeasurementDto | null> implements ITransformation {
6
- name: string;
7
- /**
8
- * Pivots long-format opendata records into wide IMeasurementDto rows.
9
- * Groups by (station_id, DT) and maps each ELEMENT to its DB column.
10
- * DT is UTC ISO 8601; year/month/day/time are expressed in Europe/Prague local time.
11
- */
12
- transform(data: IInputOpendataRecord[]): Promise<IMeasurementDto[]>;
13
- protected transformInternal: (records: IInputOpendataRecord[]) => IMeasurementDto | null;
14
- private groupByStationAndDt;
15
- }