You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
58 lines
2.3 KiB
SQL
58 lines
2.3 KiB
SQL
-- Realtime GPS telemetry storage
|
|
CREATE TABLE IF NOT EXISTS telemetry_samples (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
vehicle_id INTEGER REFERENCES vehicles(id) ON DELETE SET NULL,
|
|
route_id INTEGER REFERENCES routes(id) ON DELETE SET NULL,
|
|
source_type VARCHAR(30) NOT NULL DEFAULT 'manual',
|
|
source_ref VARCHAR(120),
|
|
location GEOGRAPHY(Point, 4326) NOT NULL,
|
|
speed_kmh NUMERIC(6, 2),
|
|
heading NUMERIC(6, 2),
|
|
accuracy_meters NUMERIC(6, 2),
|
|
recorded_at TIMESTAMP NOT NULL,
|
|
received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
is_valid BOOLEAN DEFAULT true,
|
|
raw_payload JSONB DEFAULT '{}'::jsonb
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_telemetry_samples_vehicle_id ON telemetry_samples(vehicle_id);
|
|
CREATE INDEX IF NOT EXISTS idx_telemetry_samples_route_id ON telemetry_samples(route_id);
|
|
CREATE INDEX IF NOT EXISTS idx_telemetry_samples_recorded_at ON telemetry_samples(recorded_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_telemetry_samples_location ON telemetry_samples USING GIST(location);
|
|
|
|
-- Latest live position for each vehicle
|
|
CREATE TABLE IF NOT EXISTS vehicle_live_state (
|
|
vehicle_id INTEGER PRIMARY KEY REFERENCES vehicles(id) ON DELETE CASCADE,
|
|
route_id INTEGER NOT NULL REFERENCES routes(id) ON DELETE CASCADE,
|
|
location GEOGRAPHY(Point, 4326) NOT NULL,
|
|
speed_kmh NUMERIC(6, 2),
|
|
heading NUMERIC(6, 2),
|
|
accuracy_meters NUMERIC(6, 2),
|
|
source_type VARCHAR(30) NOT NULL DEFAULT 'manual',
|
|
source_ref VARCHAR(120),
|
|
last_seen_at TIMESTAMP NOT NULL,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_vehicle_live_state_route_id ON vehicle_live_state(route_id);
|
|
CREATE INDEX IF NOT EXISTS idx_vehicle_live_state_last_seen_at ON vehicle_live_state(last_seen_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_vehicle_live_state_location ON vehicle_live_state USING GIST(location);
|
|
|
|
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM pg_proc
|
|
WHERE proname = 'update_updated_at_column'
|
|
) AND NOT EXISTS (
|
|
SELECT 1
|
|
FROM pg_trigger
|
|
WHERE tgname = 'update_vehicle_live_state_updated_at'
|
|
) THEN
|
|
CREATE TRIGGER update_vehicle_live_state_updated_at
|
|
BEFORE UPDATE ON vehicle_live_state
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION update_updated_at_column();
|
|
END IF;
|
|
END $$;
|