This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
|
||||
import { isMaritimePort } from './maritime.js'
|
||||
|
||||
test('accepts curated coastal LOCODE ports', () => {
|
||||
assert.equal(isMaritimePort({ locode: 'NGLAG' }), true)
|
||||
assert.equal(isMaritimePort({ locode: 'CDBNW' }), true)
|
||||
})
|
||||
|
||||
test('rejects inland ports even when UN/LOCODE function 1 is present', () => {
|
||||
assert.equal(isMaritimePort({ locode: 'CMGOU', function_code: '1-34----' }), false)
|
||||
assert.equal(isMaritimePort({ locode: 'CGOYO', function_code: '1-3-----' }), false)
|
||||
})
|
||||
|
||||
test('accepts an explicitly curated database record', () => {
|
||||
assert.equal(isMaritimePort({ locode: 'CUSTOM', is_maritime_port: true }), true)
|
||||
})
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
import type { ArangoDoc } from './helpers.js'
|
||||
|
||||
// UN/LOCODE function 1 also includes inland waterway ports. This curated set
|
||||
// keeps the maritime planner on coastal and ocean-accessible terminals only.
|
||||
export const AFRICA_MARITIME_LOCODES = new Set([
|
||||
'BJPTN',
|
||||
'CDBNW',
|
||||
'CIASS',
|
||||
'CIBAO',
|
||||
'CIDAB',
|
||||
'CIFRE',
|
||||
'CIGLU',
|
||||
'CISPY',
|
||||
'CMLIM',
|
||||
'CMMOU',
|
||||
'CVMIN',
|
||||
'DJDMJ',
|
||||
'DJPOD',
|
||||
'DJDCT',
|
||||
'DZALG',
|
||||
'DZAZW',
|
||||
'DZCHE',
|
||||
'DZCOL',
|
||||
'DZDEL',
|
||||
'DZGHZ',
|
||||
'EGAGN',
|
||||
'EGADA',
|
||||
'EGAQU',
|
||||
'EGSUZ',
|
||||
'EGDOM',
|
||||
'EGDAM',
|
||||
'EGGUA',
|
||||
'EGGAL',
|
||||
'EGIKU',
|
||||
'EGEPP',
|
||||
'EGOPT',
|
||||
'EGGLB',
|
||||
'EGPSE',
|
||||
'EGMEA',
|
||||
'EGSBY',
|
||||
'ERASA',
|
||||
'ERMSW',
|
||||
'GNBEL',
|
||||
'GNBFA',
|
||||
'GNDPL',
|
||||
'GNPMT',
|
||||
'GNDKA',
|
||||
'GNKMC',
|
||||
'GWOXB',
|
||||
'GWBOL',
|
||||
'GWBQE',
|
||||
'GWCAC',
|
||||
'KESMN',
|
||||
'KMAJN',
|
||||
'LRHAR',
|
||||
'LRMLW',
|
||||
'LYKHO',
|
||||
'LYELK',
|
||||
'LYMEL',
|
||||
'MAANZ',
|
||||
'MABUJ',
|
||||
'MAELJ',
|
||||
'MAESS',
|
||||
'MARNA',
|
||||
'MGNOS',
|
||||
'MUPMA',
|
||||
'MZCOR',
|
||||
'MZMZB',
|
||||
'NGFLM',
|
||||
'NGLAG',
|
||||
'NGLKK',
|
||||
'NGONN',
|
||||
'SCVIC',
|
||||
'SLKSY',
|
||||
'SOELM',
|
||||
'SOGRC',
|
||||
'STTMS',
|
||||
'TNHMM',
|
||||
'TNTZE',
|
||||
'TNBJC',
|
||||
'TNCHB',
|
||||
'TNMAD',
|
||||
'TNRDS',
|
||||
'TNSLN',
|
||||
'TNZRZ',
|
||||
'TZDAR',
|
||||
'TZIKW',
|
||||
'ZACPT',
|
||||
'ZADUR',
|
||||
'ZAKOM',
|
||||
'ZAPNL',
|
||||
'ZAPED',
|
||||
'ZAJOH',
|
||||
'ZAZE4',
|
||||
'ZASMN',
|
||||
'ZASTD',
|
||||
])
|
||||
|
||||
export function isMaritimePort(document: ArangoDoc): boolean {
|
||||
return document.is_maritime_port === true
|
||||
|| AFRICA_MARITIME_LOCODES.has(String(document.locode ?? '').toUpperCase())
|
||||
}
|
||||
+8
-4
@@ -378,18 +378,18 @@ async function maritimeRoutesBetweenNodes(
|
||||
FOR port IN nodes
|
||||
FILTER port.node_type == 'logistics' OR port.node_type == null
|
||||
FILTER port.latitude != null AND port.longitude != null
|
||||
FILTER 'sea' IN port.transport_types
|
||||
FILTER port.is_maritime_port == true
|
||||
SORT DISTANCE(@source_lat, @source_lon, port.latitude, port.longitude) ASC
|
||||
LIMIT 8
|
||||
LIMIT 12
|
||||
RETURN port
|
||||
)
|
||||
LET destination_ports = (
|
||||
FOR port IN nodes
|
||||
FILTER port.node_type == 'logistics' OR port.node_type == null
|
||||
FILTER port.latitude != null AND port.longitude != null
|
||||
FILTER 'sea' IN port.transport_types
|
||||
FILTER port.is_maritime_port == true
|
||||
SORT DISTANCE(@destination_lat, @destination_lon, port.latitude, port.longitude) ASC
|
||||
LIMIT 8
|
||||
LIMIT 12
|
||||
RETURN port
|
||||
)
|
||||
FOR origin_port IN origin_ports
|
||||
@@ -398,6 +398,10 @@ async function maritimeRoutesBetweenNodes(
|
||||
LET first_mile = DISTANCE(@source_lat, @source_lon, origin_port.latitude, origin_port.longitude)
|
||||
LET sea_leg = DISTANCE(origin_port.latitude, origin_port.longitude, destination_port.latitude, destination_port.longitude)
|
||||
LET last_mile = DISTANCE(destination_port.latitude, destination_port.longitude, @destination_lat, @destination_lon)
|
||||
LET origin_to_destination = DISTANCE(@destination_lat, @destination_lon, origin_port.latitude, origin_port.longitude)
|
||||
LET destination_to_source = DISTANCE(@source_lat, @source_lon, destination_port.latitude, destination_port.longitude)
|
||||
FILTER first_mile < origin_to_destination
|
||||
FILTER last_mile < destination_to_source
|
||||
SORT first_mile + sea_leg + last_mile ASC
|
||||
LIMIT @limit
|
||||
RETURN { origin_port, destination_port }
|
||||
|
||||
Reference in New Issue
Block a user