@aiaiai-pt/frankctl 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +11 -6
- package/dist/index.js +208 -197
- package/dist/template-packs/cira/01_organization.yaml +68 -0
- package/dist/template-packs/cira/02_freguesia.yaml +73 -0
- package/dist/template-packs/cira/03_transit_route.yaml +70 -0
- package/dist/template-packs/cira/04_transit_stop.yaml +57 -0
- package/dist/template-packs/cira/05_air_quality_station.yaml +83 -0
- package/dist/template-packs/cira/06_air_quality_observed.yaml +99 -0
- package/dist/template-packs/cira/07_transit_trip.yaml +106 -0
- package/dist/template-packs/cira/08_vehicle_position.yaml +81 -0
- package/dist/template-packs/cira/09_transdev_aveirobus_gtfs.yaml +709 -0
- package/dist/template-packs/cira/10_ciclope_emergency.yaml +526 -0
- package/dist/template-packs/cira/cityfy_agenda_events.yaml +156 -0
- package/dist/template-packs/cira/template-pack.yaml +109 -0
- package/package.json +2 -1
- package/skills/frank-cli/SKILL.md +33 -12
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Stage 01: 11 transport municipalities plus the Busway operator.
|
|
2
|
+
# Expected complete cardinality from the live source profile: 12.
|
|
3
|
+
|
|
4
|
+
apiVersion: frank.platform/v1
|
|
5
|
+
kind: Pipeline
|
|
6
|
+
metadata:
|
|
7
|
+
name: cira_transport_organization
|
|
8
|
+
spec:
|
|
9
|
+
name: cira_transport_organization
|
|
10
|
+
description: Canonical CIRA transport municipalities and operator organizations.
|
|
11
|
+
source_ids:
|
|
12
|
+
- cira-bdtransportes-rede
|
|
13
|
+
schedule_config:
|
|
14
|
+
type: manual
|
|
15
|
+
steps:
|
|
16
|
+
- name: organization_rows
|
|
17
|
+
kind: custom_sql
|
|
18
|
+
params:
|
|
19
|
+
sql: |-
|
|
20
|
+
SELECT concat('municipality:',cast(cast(fid AS bigint) AS varchar)) code,
|
|
21
|
+
municipio name,
|
|
22
|
+
CAST(NULL AS varchar) email,
|
|
23
|
+
CASE WHEN geometry_wkt IS NOT NULL THEN
|
|
24
|
+
concat(
|
|
25
|
+
'{"type":"MultiPolygon","coordinates":[',
|
|
26
|
+
json_format(json_extract(json_parse(to_geojson_geometry(ST_GeometryFromText(geometry_wkt))), '$.coordinates')),
|
|
27
|
+
']}'
|
|
28
|
+
)
|
|
29
|
+
END boundary_geojson
|
|
30
|
+
FROM tenant_00000000_cira_bdtransportes_rede.municipios
|
|
31
|
+
UNION ALL
|
|
32
|
+
SELECT DISTINCT concat('operator:',cast(cast(id_operador_estrutura AS bigint) AS varchar)) code,
|
|
33
|
+
nome name,
|
|
34
|
+
CAST(NULL AS varchar) email,
|
|
35
|
+
CAST(NULL AS varchar) boundary_geojson
|
|
36
|
+
FROM tenant_00000000_cira_bdtransportes_rede.carreirastotal
|
|
37
|
+
depends_on: []
|
|
38
|
+
emits_to: backing_dataset
|
|
39
|
+
config:
|
|
40
|
+
output_layer: silver
|
|
41
|
+
---
|
|
42
|
+
apiVersion: frank.platform/v1
|
|
43
|
+
kind: BackingDataset
|
|
44
|
+
metadata:
|
|
45
|
+
name: cira_transport_organization
|
|
46
|
+
spec:
|
|
47
|
+
entity_type_id: organization
|
|
48
|
+
entity_type_name: Organization
|
|
49
|
+
ontology_tenant_id: cira
|
|
50
|
+
pipeline: cira_transport_organization
|
|
51
|
+
sync_mode: manual
|
|
52
|
+
primary_key_column: code
|
|
53
|
+
title_key_column: name
|
|
54
|
+
property_mappings:
|
|
55
|
+
- column: code
|
|
56
|
+
property: code
|
|
57
|
+
type: varchar
|
|
58
|
+
is_primary_key: true
|
|
59
|
+
- column: name
|
|
60
|
+
property: name
|
|
61
|
+
type: varchar
|
|
62
|
+
- column: email
|
|
63
|
+
property: email
|
|
64
|
+
type: varchar
|
|
65
|
+
- column: boundary_geojson
|
|
66
|
+
property: boundary
|
|
67
|
+
type: varchar
|
|
68
|
+
sql_transform_id: json_parse
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Stage 02: CIRA transport freguesias. Run after stage 01 so every
|
|
2
|
+
# organization relationship resolves through organization.code.
|
|
3
|
+
# Expected complete cardinality from the live source profile: 74.
|
|
4
|
+
|
|
5
|
+
apiVersion: frank.platform/v1
|
|
6
|
+
kind: Pipeline
|
|
7
|
+
metadata:
|
|
8
|
+
name: cira_transport_freguesia
|
|
9
|
+
spec:
|
|
10
|
+
name: cira_transport_freguesia
|
|
11
|
+
description: Canonical CIRA transport freguesias with municipality ownership.
|
|
12
|
+
source_ids:
|
|
13
|
+
- cira-bdtransportes-rede
|
|
14
|
+
schedule_config:
|
|
15
|
+
type: manual
|
|
16
|
+
steps:
|
|
17
|
+
- name: freguesia_rows
|
|
18
|
+
kind: custom_sql
|
|
19
|
+
params:
|
|
20
|
+
sql: |-
|
|
21
|
+
SELECT dicofre code,
|
|
22
|
+
freguesia name,
|
|
23
|
+
concat('municipality:',cast(cast(idmunicipio AS bigint) AS varchar)) municipality_code,
|
|
24
|
+
concat('municipality:',cast(cast(idmunicipio AS bigint) AS varchar)) organization_code,
|
|
25
|
+
CASE WHEN geometry_wkt IS NOT NULL THEN
|
|
26
|
+
concat(
|
|
27
|
+
'{"type":"MultiPolygon","coordinates":[',
|
|
28
|
+
json_format(json_extract(json_parse(to_geojson_geometry(ST_GeometryFromText(geometry_wkt))), '$.coordinates')),
|
|
29
|
+
']}'
|
|
30
|
+
)
|
|
31
|
+
END geometry_geojson
|
|
32
|
+
FROM tenant_00000000_cira_bdtransportes_rede.freguesias
|
|
33
|
+
WHERE dicofre IS NOT NULL
|
|
34
|
+
depends_on: []
|
|
35
|
+
emits_to: backing_dataset
|
|
36
|
+
config:
|
|
37
|
+
output_layer: silver
|
|
38
|
+
---
|
|
39
|
+
apiVersion: frank.platform/v1
|
|
40
|
+
kind: BackingDataset
|
|
41
|
+
metadata:
|
|
42
|
+
name: cira_transport_freguesia
|
|
43
|
+
dependsOn:
|
|
44
|
+
- entityTypeId: organization
|
|
45
|
+
ontologyTenantId: cira
|
|
46
|
+
spec:
|
|
47
|
+
entity_type_id: freguesia
|
|
48
|
+
entity_type_name: Freguesia
|
|
49
|
+
ontology_tenant_id: cira
|
|
50
|
+
pipeline: cira_transport_freguesia
|
|
51
|
+
sync_mode: manual
|
|
52
|
+
primary_key_column: code
|
|
53
|
+
title_key_column: name
|
|
54
|
+
property_mappings:
|
|
55
|
+
- column: code
|
|
56
|
+
property: code
|
|
57
|
+
type: varchar
|
|
58
|
+
is_primary_key: true
|
|
59
|
+
- column: name
|
|
60
|
+
property: name
|
|
61
|
+
type: varchar
|
|
62
|
+
- column: municipality_code
|
|
63
|
+
property: municipality_code
|
|
64
|
+
type: varchar
|
|
65
|
+
- column: geometry_geojson
|
|
66
|
+
property: geometry
|
|
67
|
+
type: varchar
|
|
68
|
+
sql_transform_id: json_parse
|
|
69
|
+
- column: organization_code
|
|
70
|
+
property: organization
|
|
71
|
+
is_relationship: true
|
|
72
|
+
target_type: organization
|
|
73
|
+
target_key: code
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Stage 03: complete CIRA route projection. Run after stage 01 so every
|
|
2
|
+
# operator relationship resolves through organization.code.
|
|
3
|
+
# Expected complete cardinality from the live source profile: 8,964.
|
|
4
|
+
|
|
5
|
+
apiVersion: frank.platform/v1
|
|
6
|
+
kind: Pipeline
|
|
7
|
+
metadata:
|
|
8
|
+
name: cira_transport_routes
|
|
9
|
+
spec:
|
|
10
|
+
name: cira_transport_routes
|
|
11
|
+
description: Canonical CIRA public-transport routes and their operator.
|
|
12
|
+
source_ids:
|
|
13
|
+
- cira-bdtransportes-rede
|
|
14
|
+
schedule_config:
|
|
15
|
+
type: manual
|
|
16
|
+
steps:
|
|
17
|
+
- name: transit_route_rows
|
|
18
|
+
kind: custom_sql
|
|
19
|
+
params:
|
|
20
|
+
sql: |-
|
|
21
|
+
SELECT coda route_key,
|
|
22
|
+
designacao long_name,
|
|
23
|
+
'bus' route_type,
|
|
24
|
+
nullif(regexp_replace(color_hex,'^#',''),'') color,
|
|
25
|
+
concat_ws(' · ',nullif(cod_car_operador,''),nullif(origem,''),nullif(destino,''),nullif(sentido,''),nullif(tipo,''),nullif(classificacao,'')) description,
|
|
26
|
+
concat('operator:',cast(cast(id_operador_estrutura AS bigint) AS varchar)) operator_code
|
|
27
|
+
FROM tenant_00000000_cira_bdtransportes_rede.carreirastotal
|
|
28
|
+
WHERE coda IS NOT NULL
|
|
29
|
+
depends_on: []
|
|
30
|
+
emits_to: backing_dataset
|
|
31
|
+
config:
|
|
32
|
+
output_layer: silver
|
|
33
|
+
---
|
|
34
|
+
apiVersion: frank.platform/v1
|
|
35
|
+
kind: BackingDataset
|
|
36
|
+
metadata:
|
|
37
|
+
name: cira_transport_routes
|
|
38
|
+
dependsOn:
|
|
39
|
+
- entityTypeId: organization
|
|
40
|
+
ontologyTenantId: cira
|
|
41
|
+
spec:
|
|
42
|
+
entity_type_id: transit_route
|
|
43
|
+
entity_type_name: Transit Route
|
|
44
|
+
ontology_tenant_id: cira
|
|
45
|
+
pipeline: cira_transport_routes
|
|
46
|
+
sync_mode: manual
|
|
47
|
+
primary_key_column: route_key
|
|
48
|
+
title_key_column: long_name
|
|
49
|
+
property_mappings:
|
|
50
|
+
- column: route_key
|
|
51
|
+
property: short_name
|
|
52
|
+
type: varchar
|
|
53
|
+
is_primary_key: true
|
|
54
|
+
- column: long_name
|
|
55
|
+
property: long_name
|
|
56
|
+
type: varchar
|
|
57
|
+
- column: route_type
|
|
58
|
+
property: route_type
|
|
59
|
+
type: varchar
|
|
60
|
+
- column: color
|
|
61
|
+
property: color
|
|
62
|
+
type: varchar
|
|
63
|
+
- column: description
|
|
64
|
+
property: description
|
|
65
|
+
type: varchar
|
|
66
|
+
- column: operator_code
|
|
67
|
+
property: operator
|
|
68
|
+
is_relationship: true
|
|
69
|
+
target_type: organization
|
|
70
|
+
target_key: code
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Stage 04: complete CIRA public-stop projection.
|
|
2
|
+
# Expected complete cardinality from the live source profile: 2,411.
|
|
3
|
+
|
|
4
|
+
apiVersion: frank.platform/v1
|
|
5
|
+
kind: Pipeline
|
|
6
|
+
metadata:
|
|
7
|
+
name: cira_transport_stops
|
|
8
|
+
spec:
|
|
9
|
+
name: cira_transport_stops
|
|
10
|
+
description: Canonical CIRA public-transport stops with GeoJSON locations.
|
|
11
|
+
source_ids:
|
|
12
|
+
- cira-bdtransportes-rede
|
|
13
|
+
schedule_config:
|
|
14
|
+
type: manual
|
|
15
|
+
steps:
|
|
16
|
+
- name: transit_stop_rows
|
|
17
|
+
kind: custom_sql
|
|
18
|
+
params:
|
|
19
|
+
sql: |-
|
|
20
|
+
SELECT concat('stop:',cast(cast(id_paragem AS bigint) AS varchar)) stop_key,
|
|
21
|
+
designacao_paragem name,
|
|
22
|
+
nullif(trim(municipio),'') zone,
|
|
23
|
+
CASE WHEN geometry_wkt IS NOT NULL THEN to_geojson_geometry(ST_GeometryFromText(geometry_wkt)) END location_geojson
|
|
24
|
+
FROM tenant_00000000_cira_bdtransportes_rede.paragenspublicogeral
|
|
25
|
+
WHERE id_paragem IS NOT NULL
|
|
26
|
+
depends_on: []
|
|
27
|
+
emits_to: backing_dataset
|
|
28
|
+
config:
|
|
29
|
+
output_layer: silver
|
|
30
|
+
---
|
|
31
|
+
apiVersion: frank.platform/v1
|
|
32
|
+
kind: BackingDataset
|
|
33
|
+
metadata:
|
|
34
|
+
name: cira_transport_stops
|
|
35
|
+
spec:
|
|
36
|
+
entity_type_id: transit_stop
|
|
37
|
+
entity_type_name: Transit Stop
|
|
38
|
+
ontology_tenant_id: cira
|
|
39
|
+
pipeline: cira_transport_stops
|
|
40
|
+
sync_mode: manual
|
|
41
|
+
primary_key_column: stop_key
|
|
42
|
+
title_key_column: name
|
|
43
|
+
property_mappings:
|
|
44
|
+
- column: stop_key
|
|
45
|
+
property: code
|
|
46
|
+
type: varchar
|
|
47
|
+
is_primary_key: true
|
|
48
|
+
- column: name
|
|
49
|
+
property: name
|
|
50
|
+
type: varchar
|
|
51
|
+
- column: zone
|
|
52
|
+
property: zone
|
|
53
|
+
type: varchar
|
|
54
|
+
- column: location_geojson
|
|
55
|
+
property: location
|
|
56
|
+
type: varchar
|
|
57
|
+
sql_transform_id: json_parse
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Stage 05: station natural keys from the raw Kunak and VDL tables.
|
|
2
|
+
# This deliberately avoids the existing duplicate-name Silver projection.
|
|
3
|
+
# Expected complete cardinality from the live source profile: 13 unique names.
|
|
4
|
+
|
|
5
|
+
apiVersion: frank.platform/v1
|
|
6
|
+
kind: Pipeline
|
|
7
|
+
metadata:
|
|
8
|
+
name: cira_air_quality_stations
|
|
9
|
+
spec:
|
|
10
|
+
name: cira_air_quality_stations
|
|
11
|
+
description: Canonical unique CIRA air-quality stations from Kunak and VDL.
|
|
12
|
+
source_ids:
|
|
13
|
+
- Kunak Cloud - Ubiwhere
|
|
14
|
+
- VDL - AirQuality - Monitar
|
|
15
|
+
schedule_config:
|
|
16
|
+
type: manual
|
|
17
|
+
steps:
|
|
18
|
+
- name: air_quality_station_rows
|
|
19
|
+
kind: custom_sql
|
|
20
|
+
params:
|
|
21
|
+
sql: |-
|
|
22
|
+
WITH kunak AS (
|
|
23
|
+
SELECT serial_number,
|
|
24
|
+
max(tag) label,
|
|
25
|
+
max(try_cast(coalesce(nullif(trim(location__latitude),''),try(json_extract_scalar(location,'$.latitude'))) AS double)) latitude,
|
|
26
|
+
max(try_cast(coalesce(nullif(trim(location__longitude),''),try(json_extract_scalar(location,'$.longitude'))) AS double)) longitude
|
|
27
|
+
FROM tenant_00000000_kunak_cloud_ubiwhere.kunak_stations
|
|
28
|
+
WHERE serial_number IS NOT NULL
|
|
29
|
+
GROUP BY serial_number
|
|
30
|
+
), vdl AS (
|
|
31
|
+
SELECT system
|
|
32
|
+
FROM tenant_00000000_vdl_airquality_monitar.sensors
|
|
33
|
+
WHERE system IS NOT NULL
|
|
34
|
+
GROUP BY system
|
|
35
|
+
)
|
|
36
|
+
SELECT concat('kunak:',serial_number) station_key,
|
|
37
|
+
label alternate_name,
|
|
38
|
+
'Kunak' data_provider,
|
|
39
|
+
'kunak_cloud_ubiwhere' source,
|
|
40
|
+
CASE WHEN latitude IS NOT NULL AND longitude IS NOT NULL THEN to_geojson_geometry(ST_GeometryFromText(format('POINT (%s %s)',longitude,latitude))) END location_geojson
|
|
41
|
+
FROM kunak
|
|
42
|
+
UNION ALL
|
|
43
|
+
SELECT concat('vdl:',system),
|
|
44
|
+
system,
|
|
45
|
+
'Monitar',
|
|
46
|
+
'vdl_airquality_monitar',
|
|
47
|
+
CAST(NULL AS varchar)
|
|
48
|
+
FROM vdl
|
|
49
|
+
depends_on: []
|
|
50
|
+
emits_to: backing_dataset
|
|
51
|
+
config:
|
|
52
|
+
output_layer: silver
|
|
53
|
+
---
|
|
54
|
+
apiVersion: frank.platform/v1
|
|
55
|
+
kind: BackingDataset
|
|
56
|
+
metadata:
|
|
57
|
+
name: cira_air_quality_stations
|
|
58
|
+
spec:
|
|
59
|
+
entity_type_id: air_quality_station
|
|
60
|
+
entity_type_name: Air Quality Station
|
|
61
|
+
ontology_tenant_id: cira
|
|
62
|
+
pipeline: cira_air_quality_stations
|
|
63
|
+
sync_mode: manual
|
|
64
|
+
primary_key_column: station_key
|
|
65
|
+
title_key_column: station_key
|
|
66
|
+
property_mappings:
|
|
67
|
+
- column: station_key
|
|
68
|
+
property: name
|
|
69
|
+
type: varchar
|
|
70
|
+
is_primary_key: true
|
|
71
|
+
- column: alternate_name
|
|
72
|
+
property: alternate_name
|
|
73
|
+
type: varchar
|
|
74
|
+
- column: data_provider
|
|
75
|
+
property: data_provider
|
|
76
|
+
type: varchar
|
|
77
|
+
- column: source
|
|
78
|
+
property: source
|
|
79
|
+
type: varchar
|
|
80
|
+
- column: location_geojson
|
|
81
|
+
property: location
|
|
82
|
+
type: varchar
|
|
83
|
+
sql_transform_id: json_parse
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Stage 06: the complete publishable Kunak observation subset for the five
|
|
2
|
+
# source pollutant tags supported by the target schema. Run after stage 05 so
|
|
3
|
+
# ref_station resolves.
|
|
4
|
+
#
|
|
5
|
+
# Live raw profile (2026-03-23 through 2026-06-22): 3,169,139 raw measurement rows
|
|
6
|
+
# across 115,665 raw timestamps. The five-tag predicate retains 542,406
|
|
7
|
+
# pollutant-tag rows and 26,216 canonical observation timestamps. Keeping this
|
|
8
|
+
# predicate prevents publishing 89,449 timestamp entities whose every mapped
|
|
9
|
+
# pollutant would be null. Pressure, temperature, humidity, and battery are not
|
|
10
|
+
# target fields; other target pollutant fields are absent from this Kunak tag set.
|
|
11
|
+
|
|
12
|
+
apiVersion: frank.platform/v1
|
|
13
|
+
kind: Pipeline
|
|
14
|
+
metadata:
|
|
15
|
+
name: cira_air_quality_observed
|
|
16
|
+
spec:
|
|
17
|
+
name: cira_air_quality_observed
|
|
18
|
+
description: Complete Kunak air-quality observations linked to canonical stations.
|
|
19
|
+
source_ids:
|
|
20
|
+
- Kunak Cloud - Ubiwhere
|
|
21
|
+
schedule_config:
|
|
22
|
+
type: manual
|
|
23
|
+
steps:
|
|
24
|
+
- name: air_quality_observed_rows
|
|
25
|
+
kind: custom_sql
|
|
26
|
+
params:
|
|
27
|
+
sql: |-
|
|
28
|
+
SELECT concat('kunak:0425100035:',cast(ts AS varchar)) observation_key,
|
|
29
|
+
from_unixtime(cast(ts AS double)/1000.0) date_observed,
|
|
30
|
+
'Kunak' data_provider,
|
|
31
|
+
'kunak_cloud_ubiwhere' source,
|
|
32
|
+
'kunak:0425100035' station_name,
|
|
33
|
+
'kunak:0425100035' ref_station_key,
|
|
34
|
+
max(CASE WHEN sensor_tag='PM1' THEN try_cast(value AS double) END) pm1,
|
|
35
|
+
max(CASE WHEN sensor_tag='PM2.5' THEN try_cast(value AS double) END) pm25,
|
|
36
|
+
max(CASE WHEN sensor_tag='PM10' THEN try_cast(value AS double) END) pm10,
|
|
37
|
+
max(CASE WHEN sensor_tag='NO2 GCc' THEN try_cast(value AS double) END) no2,
|
|
38
|
+
max(CASE WHEN sensor_tag='CO GCc' THEN try_cast(value AS double) END) co
|
|
39
|
+
FROM tenant_00000000_kunak_cloud_ubiwhere.device_0425100035
|
|
40
|
+
WHERE ts IS NOT NULL
|
|
41
|
+
AND sensor_tag IN ('PM1','PM2.5','PM10','NO2 GCc','CO GCc')
|
|
42
|
+
GROUP BY ts
|
|
43
|
+
depends_on: []
|
|
44
|
+
emits_to: backing_dataset
|
|
45
|
+
config:
|
|
46
|
+
output_layer: silver
|
|
47
|
+
---
|
|
48
|
+
apiVersion: frank.platform/v1
|
|
49
|
+
kind: BackingDataset
|
|
50
|
+
metadata:
|
|
51
|
+
name: cira_air_quality_observed
|
|
52
|
+
dependsOn:
|
|
53
|
+
- entityTypeId: air_quality_station
|
|
54
|
+
ontologyTenantId: cira
|
|
55
|
+
spec:
|
|
56
|
+
entity_type_id: air_quality_observed
|
|
57
|
+
entity_type_name: Air Quality Observed
|
|
58
|
+
ontology_tenant_id: cira
|
|
59
|
+
pipeline: cira_air_quality_observed
|
|
60
|
+
sync_mode: manual
|
|
61
|
+
primary_key_column: observation_key
|
|
62
|
+
title_key_column: observation_key
|
|
63
|
+
property_mappings:
|
|
64
|
+
- column: observation_key
|
|
65
|
+
property: name
|
|
66
|
+
type: varchar
|
|
67
|
+
is_primary_key: true
|
|
68
|
+
- column: date_observed
|
|
69
|
+
property: date_observed
|
|
70
|
+
type: timestamp with time zone
|
|
71
|
+
- column: data_provider
|
|
72
|
+
property: data_provider
|
|
73
|
+
type: varchar
|
|
74
|
+
- column: source
|
|
75
|
+
property: source
|
|
76
|
+
type: varchar
|
|
77
|
+
- column: station_name
|
|
78
|
+
property: station_name
|
|
79
|
+
type: varchar
|
|
80
|
+
- column: ref_station_key
|
|
81
|
+
property: ref_station
|
|
82
|
+
is_relationship: true
|
|
83
|
+
target_type: air_quality_station
|
|
84
|
+
target_key: name
|
|
85
|
+
- column: pm1
|
|
86
|
+
property: pm1
|
|
87
|
+
type: double
|
|
88
|
+
- column: pm25
|
|
89
|
+
property: pm25
|
|
90
|
+
type: double
|
|
91
|
+
- column: pm10
|
|
92
|
+
property: pm10
|
|
93
|
+
type: double
|
|
94
|
+
- column: no2
|
|
95
|
+
property: no2
|
|
96
|
+
type: double
|
|
97
|
+
- column: co
|
|
98
|
+
property: co
|
|
99
|
+
type: double
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Stage 07: complete CIRA trips after the repaired WFS iterator publishes the
|
|
2
|
+
# authoritative 237,808-row schedule snapshot. The point-in-time source profile
|
|
3
|
+
# has 8,964 unique, non-null trip IDs; the count is evidence, not a row limit.
|
|
4
|
+
|
|
5
|
+
apiVersion: frank.platform/v1
|
|
6
|
+
kind: Source
|
|
7
|
+
metadata:
|
|
8
|
+
name: cira-bdtransportes-horarios
|
|
9
|
+
spec:
|
|
10
|
+
name: cira-bdtransportes-horarios
|
|
11
|
+
pattern_id: geoserver_wfs
|
|
12
|
+
source_config:
|
|
13
|
+
base_url: https://transportes.regiaodeaveiro.pt/geoserver
|
|
14
|
+
workspace: cimo
|
|
15
|
+
resources:
|
|
16
|
+
- ParagensTotalSchedule
|
|
17
|
+
wfs_version: 2.0.0
|
|
18
|
+
srs_name: EPSG:4326
|
|
19
|
+
page_size: 10000
|
|
20
|
+
# Match one iterator activity to one WFS page. The 5k cluster default
|
|
21
|
+
# re-fetches every 10k page for its second half, which is correct but adds a
|
|
22
|
+
# slow duplicate sorted-offset request on this 237,808-row source.
|
|
23
|
+
max_items_per_chunk: 10000
|
|
24
|
+
schedule_type: manual
|
|
25
|
+
streams:
|
|
26
|
+
- name: ParagensTotalSchedule
|
|
27
|
+
sync_mode: full_refresh
|
|
28
|
+
write_disposition: replace
|
|
29
|
+
primary_key_path:
|
|
30
|
+
- trip_id
|
|
31
|
+
- Ordem
|
|
32
|
+
- IdParagem
|
|
33
|
+
is_enabled: true
|
|
34
|
+
---
|
|
35
|
+
apiVersion: frank.platform/v1
|
|
36
|
+
kind: Pipeline
|
|
37
|
+
metadata:
|
|
38
|
+
name: cira_transport_trips
|
|
39
|
+
spec:
|
|
40
|
+
name: cira_transport_trips
|
|
41
|
+
description: Complete CIRA transit trips with deterministic final-stop headsigns.
|
|
42
|
+
source_ids:
|
|
43
|
+
- cira-bdtransportes-horarios
|
|
44
|
+
schedule_config:
|
|
45
|
+
type: manual
|
|
46
|
+
steps:
|
|
47
|
+
- name: transit_trip_rows
|
|
48
|
+
kind: custom_sql
|
|
49
|
+
params:
|
|
50
|
+
sql: |-
|
|
51
|
+
WITH final_stop AS (
|
|
52
|
+
SELECT trip_id service_id,
|
|
53
|
+
try_cast(sentidoparagem AS integer) direction,
|
|
54
|
+
nullif(trim(paragem),'') headsign,
|
|
55
|
+
coda route_key,
|
|
56
|
+
row_number() OVER (
|
|
57
|
+
PARTITION BY trip_id
|
|
58
|
+
ORDER BY try_cast(ordem AS bigint) DESC NULLS LAST,
|
|
59
|
+
try_cast(id_paragem AS bigint) DESC NULLS LAST,
|
|
60
|
+
_feature_id DESC NULLS LAST
|
|
61
|
+
) stop_rank
|
|
62
|
+
FROM tenant_00000000_cira_bdtransportes_horarios.paragenstotalschedule
|
|
63
|
+
WHERE trip_id IS NOT NULL
|
|
64
|
+
)
|
|
65
|
+
SELECT service_id,
|
|
66
|
+
direction,
|
|
67
|
+
headsign,
|
|
68
|
+
route_key
|
|
69
|
+
FROM final_stop
|
|
70
|
+
WHERE stop_rank=1
|
|
71
|
+
depends_on: []
|
|
72
|
+
emits_to: backing_dataset
|
|
73
|
+
config:
|
|
74
|
+
output_layer: silver
|
|
75
|
+
---
|
|
76
|
+
apiVersion: frank.platform/v1
|
|
77
|
+
kind: BackingDataset
|
|
78
|
+
metadata:
|
|
79
|
+
name: cira_transport_trips
|
|
80
|
+
dependsOn:
|
|
81
|
+
- entityTypeId: transit_route
|
|
82
|
+
ontologyTenantId: cira
|
|
83
|
+
spec:
|
|
84
|
+
entity_type_id: transit_trip
|
|
85
|
+
entity_type_name: Transit Trip
|
|
86
|
+
ontology_tenant_id: cira
|
|
87
|
+
pipeline: cira_transport_trips
|
|
88
|
+
sync_mode: manual
|
|
89
|
+
primary_key_column: service_id
|
|
90
|
+
title_key_column: service_id
|
|
91
|
+
property_mappings:
|
|
92
|
+
- column: service_id
|
|
93
|
+
property: service_id
|
|
94
|
+
type: varchar
|
|
95
|
+
is_primary_key: true
|
|
96
|
+
- column: direction
|
|
97
|
+
property: direction
|
|
98
|
+
type: integer
|
|
99
|
+
- column: headsign
|
|
100
|
+
property: headsign
|
|
101
|
+
type: varchar
|
|
102
|
+
- column: route_key
|
|
103
|
+
property: route
|
|
104
|
+
is_relationship: true
|
|
105
|
+
target_type: transit_route
|
|
106
|
+
target_key: short_name
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Stage 08: the current CIRA AVL snapshot. The upstream point-in-time profile
|
|
2
|
+
# at 2026-07-21 20:11 UTC contained 405 rows with 405 unique, non-null partition
|
|
3
|
+
# IDs (up from 403 minutes earlier). Every full refresh replaces that evidence
|
|
4
|
+
# point with the then-current set.
|
|
5
|
+
|
|
6
|
+
apiVersion: frank.platform/v1
|
|
7
|
+
kind: Source
|
|
8
|
+
metadata:
|
|
9
|
+
name: cira-bdtransportes-avl
|
|
10
|
+
spec:
|
|
11
|
+
name: cira-bdtransportes-avl
|
|
12
|
+
pattern_id: geoserver_wfs
|
|
13
|
+
source_config:
|
|
14
|
+
base_url: https://transportes.regiaodeaveiro.pt/geoserver
|
|
15
|
+
workspace: cimo
|
|
16
|
+
resources:
|
|
17
|
+
- carreirasae_ultimaposicao
|
|
18
|
+
wfs_version: 2.0.0
|
|
19
|
+
srs_name: EPSG:4326
|
|
20
|
+
page_size: 5000
|
|
21
|
+
primary_keys:
|
|
22
|
+
- partition_id
|
|
23
|
+
schedule_type: manual
|
|
24
|
+
streams:
|
|
25
|
+
- name: carreirasae_ultimaposicao
|
|
26
|
+
sync_mode: full_refresh
|
|
27
|
+
write_disposition: replace
|
|
28
|
+
primary_key_path:
|
|
29
|
+
- partition_id
|
|
30
|
+
is_enabled: true
|
|
31
|
+
---
|
|
32
|
+
apiVersion: frank.platform/v1
|
|
33
|
+
kind: Pipeline
|
|
34
|
+
metadata:
|
|
35
|
+
name: cira_transport_vehicle_positions
|
|
36
|
+
spec:
|
|
37
|
+
name: cira_transport_vehicle_positions
|
|
38
|
+
description: Current CIRA vehicle positions without an unproven trip relationship.
|
|
39
|
+
source_ids:
|
|
40
|
+
- cira-bdtransportes-avl
|
|
41
|
+
schedule_config:
|
|
42
|
+
type: manual
|
|
43
|
+
steps:
|
|
44
|
+
- name: vehicle_position_rows
|
|
45
|
+
kind: custom_sql
|
|
46
|
+
params:
|
|
47
|
+
sql: |-
|
|
48
|
+
SELECT partition_id label,
|
|
49
|
+
CASE WHEN geometry_wkt IS NOT NULL THEN to_geojson_geometry(ST_GeometryFromText(geometry_wkt)) END location_geojson,
|
|
50
|
+
try_cast(data AS timestamp) recorded_at
|
|
51
|
+
FROM tenant_00000000_cira_bdtransportes_avl.carreirasae_ultimaposicao
|
|
52
|
+
WHERE partition_id IS NOT NULL
|
|
53
|
+
depends_on: []
|
|
54
|
+
emits_to: backing_dataset
|
|
55
|
+
config:
|
|
56
|
+
output_layer: silver
|
|
57
|
+
---
|
|
58
|
+
apiVersion: frank.platform/v1
|
|
59
|
+
kind: BackingDataset
|
|
60
|
+
metadata:
|
|
61
|
+
name: cira_transport_vehicle_positions
|
|
62
|
+
spec:
|
|
63
|
+
entity_type_id: vehicle_position
|
|
64
|
+
entity_type_name: Vehicle Position
|
|
65
|
+
ontology_tenant_id: cira
|
|
66
|
+
pipeline: cira_transport_vehicle_positions
|
|
67
|
+
sync_mode: manual
|
|
68
|
+
primary_key_column: label
|
|
69
|
+
title_key_column: label
|
|
70
|
+
property_mappings:
|
|
71
|
+
- column: label
|
|
72
|
+
property: label
|
|
73
|
+
type: varchar
|
|
74
|
+
is_primary_key: true
|
|
75
|
+
- column: location_geojson
|
|
76
|
+
property: location
|
|
77
|
+
type: varchar
|
|
78
|
+
sql_transform_id: json_parse
|
|
79
|
+
- column: recorded_at
|
|
80
|
+
property: recorded_at
|
|
81
|
+
type: timestamp
|