- address-search.js : expose searchAddressesRpc() → RPC Postgres `search_addresses` (pg_trgm), la MÊME recherche que l'autocomplete de disponibilité fibre. Trouve les rues que l'ilike manquait (générique géré par la colonne odonyme_recompose_long + phase 2 trigram), priorise les CP J0L/J0S (territoire). - geocodeRQA() (bridge) bascule de l'ilike vers la RPC. Garde-fou : la phase 2 trigram dérive quand le civique est absent du RQA (« 2245 René-Vinet » → « Rue Grenet, Montréal »). On n'accepte un résultat que si le civique concorde + un token de nom de rue correspond + (territoire J0L/J0S OU CP/ville legacy concordants). Vérifié sur les données réelles : accepte 494 Av Curry / 3055 Routhier / 228 Principale / 61 Jean-François ; rejette René-Vinet→Grenet/Panet, chemin Ridge→Ferme, rue West→Perras (bons faux positifs écartés). - Le faible compte RQA (8) = haute précision (l'ilike comptait 17 dont des faux positifs). Mapbox couvre le reste (rues neuves/civiques absents) ; ~109/125 (87 %) coordonnés ; les « aucune » = campings/villes mal écrites. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
66 lines
3.0 KiB
JavaScript
66 lines
3.0 KiB
JavaScript
'use strict'
|
|
const { httpRequest } = require('./helpers')
|
|
|
|
const SUPABASE_URL = 'https://rddrjzptzhypltuzmere.supabase.co'
|
|
const SUPABASE_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InJkZHJqenB0emh5cGx0dXptZXJlIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA4MTY4NTYsImV4cCI6MjA4NjM5Mjg1Nn0.EluFlKBze8BYM6AFx88G7kt21EvR18EI3uw1zgCXVzs'
|
|
|
|
function wordsToIlike (str) {
|
|
const words = str.split(/\s+/).filter(w => w.length >= 2)
|
|
if (!words.length) return ''
|
|
return '*' + words.map(w => encodeURIComponent(w)).join('*') + '*'
|
|
}
|
|
|
|
async function searchAddresses (term, limit = 8) {
|
|
const clean = term.trim()
|
|
if (clean.length < 3) return []
|
|
|
|
const numMatch = clean.match(/^\s*(\d+)\s*(.*)/)
|
|
const headers = { apikey: SUPABASE_KEY, Authorization: 'Bearer ' + SUPABASE_KEY }
|
|
const select = 'adresse_formatee,numero_municipal,numero_unite,code_postal,odonyme_recompose_normal,nom_municipalite,latitude,longitude,identifiant_unique_adresse'
|
|
const base = `${SUPABASE_URL}/rest/v1/addresses?select=${select}&limit=${limit}`
|
|
|
|
let results = []
|
|
|
|
if (numMatch) {
|
|
const num = numMatch[1]
|
|
const street = numMatch[2].trim()
|
|
let url = `${base}&numero_municipal=eq.${num}`
|
|
if (street) url += `&odonyme_recompose_normal=ilike.${wordsToIlike(street)}`
|
|
url += '&order=nom_municipalite'
|
|
const res = await httpRequest(url, '', { headers })
|
|
results = Array.isArray(res.data) ? res.data : []
|
|
|
|
if (!results.length && num.length >= 2) {
|
|
let url2 = `${base}&numero_municipal=like.${num}*`
|
|
if (street) url2 += `&odonyme_recompose_normal=ilike.${wordsToIlike(street)}`
|
|
url2 += '&order=nom_municipalite'
|
|
const res2 = await httpRequest(url2, '', { headers })
|
|
results = Array.isArray(res2.data) ? res2.data : []
|
|
}
|
|
} else {
|
|
const pattern = wordsToIlike(clean)
|
|
if (!pattern) return []
|
|
const url = `${base}&odonyme_recompose_normal=ilike.${pattern}&order=nom_municipalite`
|
|
const res = await httpRequest(url, '', { headers })
|
|
results = Array.isArray(res.data) ? res.data : []
|
|
}
|
|
|
|
return results.map(a => ({ ...a, fiber_available: false }))
|
|
}
|
|
|
|
// RECHERCHE TRIGRAM (RPC Postgres `search_addresses`) — bien plus robuste que l'ilike ci-dessus :
|
|
// phase 1 = numéro civique + mots de rue (sur odonyme normal/court/LONG[avec générique]/municipalité/CP),
|
|
// phase 2 = trigram complet (`%`, pg_trgm). Priorise les CP J0L/J0S (territoire). Renvoie aussi
|
|
// fiber_available/zone_tarifaire/max_speed/similarity_score. C'est ce qui propulse l'autocomplete de dispo.
|
|
async function searchAddressesRpc (term, limit = 8) {
|
|
const clean = (term || '').trim()
|
|
if (clean.length < 3) return []
|
|
const headers = { apikey: SUPABASE_KEY, Authorization: 'Bearer ' + SUPABASE_KEY, 'Content-Type': 'application/json' }
|
|
const res = await httpRequest(`${SUPABASE_URL}/rest/v1/rpc/search_addresses`, '', {
|
|
method: 'POST', body: JSON.stringify({ search_term: clean, result_limit: limit }), headers,
|
|
})
|
|
return Array.isArray(res.data) ? res.data : []
|
|
}
|
|
|
|
module.exports = { searchAddresses, searchAddressesRpc, wordsToIlike }
|