From 751a80f3c25a51020436d2b24ce54d15ff13c4e9 Mon Sep 17 00:00:00 2001 From: Ludovic Delhomme Date: Fri, 17 Jan 2025 18:37:49 +0100 Subject: [PATCH 1/4] wip sql --- .../DistributionRepositoryProvider.ts | 73 +++------ .../providers/FluxRepositoryProvider.ts | 152 +++++++----------- 2 files changed, 87 insertions(+), 138 deletions(-) diff --git a/api/src/pdc/services/observatory/providers/DistributionRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/DistributionRepositoryProvider.ts index 8fcd723a60..05961ddbf4 100644 --- a/api/src/pdc/services/observatory/providers/DistributionRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/DistributionRepositoryProvider.ts @@ -1,5 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { DistributionRepositoryInterface, @@ -13,8 +14,7 @@ import { @provider({ identifier: DistributionRepositoryInterfaceResolver, }) -export class DistributionRepositoryProvider - implements DistributionRepositoryInterface { +export class DistributionRepositoryProvider implements DistributionRepositoryInterface { private readonly table = ( params: | JourneysByHoursParamsInterface @@ -29,41 +29,30 @@ export class DistributionRepositoryProvider params: JourneysByHoursParamsInterface, ): Promise { const tableName = this.table(params); - const conditions = [ - `year = $1`, - `type = $2`, - `code = $3`, - ]; - const queryValues = [ - params.year, - params.type, - params.code, + const filters = [ + sql`year = ${params.year}`, + sql`type = ${params.type}`, + sql`code = ${params.code}`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $4`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $4`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $4`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT code, libelle, direction, hours - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } @@ -71,43 +60,31 @@ export class DistributionRepositoryProvider params: JourneysByDistancesParamsInterface, ): Promise { const tableName = this.table(params); - const conditions = [ - `year = $1`, - `type = $2`, - `code = $3`, - `direction = $4`, - ]; - const queryValues = [ - params.year, - params.type, - params.code, - params.direction, + const filters = [ + sql`year = ${params.year}`, + sql`type = ${params.type}`, + sql`code = ${params.code}`, + sql`direction = ${params.direction}`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $5`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $5`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $5`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT code, libelle, direction, distances - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } diff --git a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts index 0b16b551ee..b66102813b 100644 --- a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts @@ -1,9 +1,7 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; -import { - checkIndicParam, - checkTerritoryParam, -} from "@/pdc/services/observatory/helpers/checkParams.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; +import { checkIndicParam, checkTerritoryParam } from "@/pdc/services/observatory/helpers/checkParams.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { FluxRepositoryInterface, @@ -35,58 +33,47 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { params: GetFluxParamsInterface, ): Promise { const tableName = this.table(params); - const observeParam = checkTerritoryParam(params.observe); - const typeParam = checkTerritoryParam(params.type); + const observeParam = sql`${checkTerritoryParam(params.observe)}`; + const typeParam = sql`${checkTerritoryParam(params.type)}`; - const perimTableQuery = ` + const perimTableQuery = sql` SELECT ${observeParam} FROM ( SELECT com, epci, aom, dep, reg, country - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime_or($1::smallint) + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = $2 + WHERE ${typeParam} = ${params.code} `; - const conditions = [ - `type = $3`, - `(distance / journeys) <= 80`, - `(territory_1 IN (${perimTableQuery}) OR territory_2 IN (${perimTableQuery}))`, - `territory_1 <> territory_2`, - `year = $1`, - ]; - - const queryValues = [ - params.year, - params.code, - observeParam, + const filters = [ + sql`type = ${observeParam}`, + sql`(distance / journeys) <= 80`, + sql`(territory_1 IN (${perimTableQuery}) OR territory_2 IN (${perimTableQuery}))`, + sql`territory_1 <> territory_2`, + sql`year = ${params.year}`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $4`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $4`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $4`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT l_territory_1 AS ter_1, lng_1, lat_1, l_territory_2 AS ter_2, lng_2, lat_2, passengers, distance, duration - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + console.log(query); + const response = await this.pg.getClient().query(query); return response.rows; } @@ -101,47 +88,43 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { "distance", "duration", ]; - const indicParam = checkIndicParam(params.indic, indics, "journeys"); - const typeParam = checkTerritoryParam(params.type); - const limit = params.past ? Number(params.past) * 12 + 1 : 25; - const queryValues = [typeParam, params.code, limit]; + const indicParam = sql`${checkIndicParam(params.indic, indics, "journeys")}`; + const typeParam = sql`${checkTerritoryParam(params.type)}`; + const limit = sql`${params.past ? Number(params.past) * 12 + 1 : 25}`; const selectedVar = [ - "year", - `sum(${indicParam}) AS ${indicParam}`, + sql`year`, + sql`sum(${indicParam}) AS ${indicParam}`, ]; - const conditions = [ - `type = $1`, - `(territory_1 = $2 OR territory_2 = $2)`, + const filters = [ + sql`type = ${typeParam}`, + sql`(territory_1 = '${params.code}' OR territory_2 = '${params.code}')`, ]; const groupBy = [ - "year", + sql`year`, ]; if (params.month) { - selectedVar.push("month"); - groupBy.push("month"); + selectedVar.push(sql`month`); + groupBy.push(sql`month`); } if (params.trimester) { - selectedVar.push("trimester"); - groupBy.push("trimester"); + selectedVar.push(sql`trimester`); + groupBy.push(sql`trimester`); } if (params.semester) { - selectedVar.push("semester"); - groupBy.push("semester"); + selectedVar.push(sql`semester`); + groupBy.push(sql`semester`); } - const queryText = ` - SELECT ${selectedVar.join(", ")} - ${indicParam == "distance" ? ", sum(journeys) AS journeys" : ""} - FROM ${tableName} - WHERE ${conditions.join(" AND ")} - GROUP BY ${groupBy.join(", ")} - ORDER BY (${groupBy.join(", ")}) DESC - LIMIT $3; + const query = sql` + SELECT ${join(selectedVar, ", ")} + ${indicParam == sql`distance` ? sql`, sum(journeys) AS journeys` : ""} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} + GROUP BY ${join(groupBy, ", ")} + ORDER BY (${join(groupBy, ", ")}) DESC + LIMIT ${limit}; `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } @@ -150,48 +133,37 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { params: GetBestFluxParamsInterface, ): Promise { const tableName = this.table(params); - const typeParam = checkTerritoryParam(params.type); - const perimTableQuery = ` + const typeParam = sql`${checkTerritoryParam(params.type)}`; + const perimTableQuery = sql` SELECT com FROM ( SELECT com, epci, aom, dep, reg, country - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime_or($1::smallint) + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = $2 + WHERE ${typeParam} = ${params.code} `; - const conditions = [ - `year = $1`, - `(territory_1 IN (${perimTableQuery}) OR territory_2 IN (${perimTableQuery}))`, - ]; - const queryValues = [ - params.year, - params.code, - params.limit, + const filters = [ + sql`year = ${params.year}`, + sql`(territory_1 IN (${perimTableQuery}) OR territory_2 IN (${perimTableQuery}))`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $4`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $4`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $4`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT territory_1, l_territory_1, territory_2, l_territory_2, journeys - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} ORDER BY journeys DESC - LIMIT $3 + LIMIT ${params.limit} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } From 054dae4c2f53fda1bc60b8e723def11ac3a2ca1c Mon Sep 17 00:00:00 2001 From: Ludovic Delhomme Date: Mon, 20 Jan 2025 12:21:58 +0100 Subject: [PATCH 2/4] wip sql --- .../providers/FluxRepositoryProvider.ts | 25 +++++----- .../IncentiveCampaignsRepositoryProvider.ts | 45 +++++++----------- .../providers/IncentiveRepositoryProvider.ts | 46 ++++++------------- .../providers/InfraRepositoryProvider.ts | 35 +++++++------- 4 files changed, 60 insertions(+), 91 deletions(-) diff --git a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts index b66102813b..7e1ef9a4ac 100644 --- a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts @@ -1,6 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; -import sql, { join, raw } from "@/lib/pg/sql.ts"; +import sql, { empty, join, raw } from "@/lib/pg/sql.ts"; import { checkIndicParam, checkTerritoryParam } from "@/pdc/services/observatory/helpers/checkParams.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { @@ -33,17 +33,17 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { params: GetFluxParamsInterface, ): Promise { const tableName = this.table(params); - const observeParam = sql`${checkTerritoryParam(params.observe)}`; - const typeParam = sql`${checkTerritoryParam(params.type)}`; + const observeParam = checkTerritoryParam(params.observe); + const typeParam = checkTerritoryParam(params.type); const perimTableQuery = sql` - SELECT ${observeParam} + SELECT ${raw(observeParam)} FROM ( SELECT com, epci, aom, dep, reg, country FROM ${raw(this.perim_table)} WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = ${params.code} + WHERE ${raw(typeParam)} = ${params.code} `; const filters = [ @@ -72,7 +72,6 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { FROM ${raw(tableName)} WHERE ${join(filters, " AND ")} `; - console.log(query); const response = await this.pg.getClient().query(query); return response.rows; } @@ -88,16 +87,16 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { "distance", "duration", ]; - const indicParam = sql`${checkIndicParam(params.indic, indics, "journeys")}`; + const indicParam = checkIndicParam(params.indic, indics, "journeys"); const typeParam = sql`${checkTerritoryParam(params.type)}`; const limit = sql`${params.past ? Number(params.past) * 12 + 1 : 25}`; const selectedVar = [ sql`year`, - sql`sum(${indicParam}) AS ${indicParam}`, + sql`sum(${raw(indicParam)}::numeric) AS ${raw(indicParam)}`, ]; const filters = [ sql`type = ${typeParam}`, - sql`(territory_1 = '${params.code}' OR territory_2 = '${params.code}')`, + sql`(territory_1 = ${params.code} OR territory_2 = ${params.code})`, ]; const groupBy = [ sql`year`, @@ -116,14 +115,14 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { } const query = sql` SELECT ${join(selectedVar, ", ")} - ${indicParam == sql`distance` ? sql`, sum(journeys) AS journeys` : ""} + ${indicParam == `distance` ? sql`, sum(journeys) AS journeys` : empty} FROM ${raw(tableName)} WHERE ${join(filters, " AND ")} GROUP BY ${join(groupBy, ", ")} ORDER BY (${join(groupBy, ", ")}) DESC LIMIT ${limit}; `; - + console.log(query.values, query.text); const response = await this.pg.getClient().query(query); return response.rows; } @@ -133,7 +132,7 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { params: GetBestFluxParamsInterface, ): Promise { const tableName = this.table(params); - const typeParam = sql`${checkTerritoryParam(params.type)}`; + const typeParam = checkTerritoryParam(params.type); const perimTableQuery = sql` SELECT com FROM ( @@ -141,7 +140,7 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { FROM ${raw(this.perim_table)} WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = ${params.code} + WHERE ${raw(typeParam)} = ${params.code} `; const filters = [ sql`year = ${params.year}`, diff --git a/api/src/pdc/services/observatory/providers/IncentiveCampaignsRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/IncentiveCampaignsRepositoryProvider.ts index 546507671f..c041639c98 100644 --- a/api/src/pdc/services/observatory/providers/IncentiveCampaignsRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/IncentiveCampaignsRepositoryProvider.ts @@ -1,5 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { checkTerritoryParam } from "../helpers/checkParams.ts"; import { CampaignsParamsInterface, @@ -11,8 +12,7 @@ import { @provider({ identifier: IncentiveCampaignsRepositoryInterfaceResolver, }) -export class IncentiveCampaignsRepositoryProvider - implements IncentiveCampaignsRepositoryInterface { +export class IncentiveCampaignsRepositoryProvider implements IncentiveCampaignsRepositoryInterface { private readonly table = "observatoire_stats.incentive_campaigns"; private readonly perim_table = "geo_stats.perimeters_aggregate"; @@ -21,47 +21,34 @@ export class IncentiveCampaignsRepositoryProvider async getCampaigns( params: CampaignsParamsInterface, ): Promise { - const typeParam = params.type !== undefined - ? checkTerritoryParam(params.type) - : null; - const queryValues: (string | number)[] = []; - const conditions = [ - `b.geom IS NOT NULL`, + const typeParam = params.type !== undefined ? checkTerritoryParam(params.type) : null; + const filters = [ + sql`b.geom IS NOT NULL`, ]; if (params.code) { - queryValues.push(params.code); - params.year - ? conditions.push(`left(a.code,9) = $2`) - : conditions.push(`left(a.code,9) = $1`); + filters.push(sql`left(a.code,9) = ${params.code}`); } if (params.year && !params.code) { - queryValues.push(params.year); - //conditions.push(`right(a.date_debut,4) = $1::varchar`); - conditions.push(`right(a.date_fin,4) = $1::varchar`); - conditions.push(`to_date(a.date_fin,'DD/MM/YYYY') < now()`); + filters.push(sql`right(a.date_fin,4) = ${params.year}::varchar`); + filters.push(sql`to_date(a.date_fin,'DD/MM/YYYY') < now()`); } if (params.year && params.code) { - queryValues.push(params.year); - //conditions.push(`right(a.date_debut,4) = $2::varchar`); - conditions.push(`right(a.date_fin,4) = $2::varchar`); + filters.push(sql`right(a.date_fin,4) = ${params.year}::varchar`); } if (!params.year && !params.code) { - conditions.push(`to_date(a.date_fin,'DD/MM/YYYY') > now()`); + filters.push(sql`to_date(a.date_fin,'DD/MM/YYYY') > now()`); } if (typeParam) { - conditions.push(`a.type = '${typeParam}'`); + filters.push(sql`a.type = ${typeParam}`); } - const queryText = ` + const query = sql` SELECT a.*, ST_AsGeoJSON(b.geom,6)::json as geom - FROM ${this.table} a - LEFT JOIN ${this.perim_table} b on a.type = b.type AND left(a.code,9) = b.code + FROM ${raw(this.table)} a + LEFT JOIN ${raw(this.perim_table)} b on a.type = b.type AND left(a.code,9) = b.code AND b.year = geo.get_latest_millesime() - WHERE ${conditions.join(" AND ")} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } diff --git a/api/src/pdc/services/observatory/providers/IncentiveRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/IncentiveRepositoryProvider.ts index 40e5d3a5ec..715ed5af7f 100644 --- a/api/src/pdc/services/observatory/providers/IncentiveRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/IncentiveRepositoryProvider.ts @@ -1,5 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { IncentiveParamsInterface, @@ -11,8 +12,7 @@ import { @provider({ identifier: IncentiveRepositoryInterfaceResolver, }) -export class IncentiveRepositoryProvider - implements IncentiveRepositoryInterface { +export class IncentiveRepositoryProvider implements IncentiveRepositoryInterface { private readonly table = ( params: IncentiveParamsInterface, ) => { @@ -24,40 +24,25 @@ export class IncentiveRepositoryProvider params: IncentiveParamsInterface, ): Promise { const tableName = this.table(params); - const conditions = [ - `year = $1`, - `type = $2`, - `code = $3`, - ]; - const queryValues = [ - params.year, - params.type, - params.code, + const filters = [ + sql`year = ${params.year}`, + sql`type = ${params.type}`, + sql`code = ${params.code}`, ]; if (params.direction) { - queryValues.push(params.direction); - conditions.push(`direction = $4`); + filters.push(sql`direction = ${params.direction}`); } if (params.month) { - queryValues.push(params.month); - params.direction - ? conditions.push(`month = $5`) - : conditions.push(`month = $4`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - params.direction - ? conditions.push(`trimester = $5`) - : conditions.push(`trimester = $4`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - params.direction - ? conditions.push(`semester = $5`) - : conditions.push(`semester = $4`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT code, libelle, @@ -65,13 +50,10 @@ export class IncentiveRepositoryProvider collectivite, operateur, autres - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } diff --git a/api/src/pdc/services/observatory/providers/InfraRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/InfraRepositoryProvider.ts index 2f6b83391d..7540fb24a8 100644 --- a/api/src/pdc/services/observatory/providers/InfraRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/InfraRepositoryProvider.ts @@ -1,5 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { checkTerritoryParam } from "../helpers/checkParams.ts"; import { AiresCovoiturageParamsInterface, @@ -19,9 +20,19 @@ export class InfraRepositoryProvider implements InfraRepositoryInterface { async getAiresCovoiturage( params: AiresCovoiturageParamsInterface, ): Promise { - const sql = { - values: [params.code], - text: `SELECT + const typeParam = checkTerritoryParam(params.type); + const filters = [ + sql`ouvert = true`, + ]; + if (params.code) { + filters.push(sql`insee IN ( + SELECT arr + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime() + AND ${raw(typeParam)} = ${params.code})`); + } + + const query = sql`SELECT id_lieu, nom_lieu, com_lieu, @@ -34,20 +45,10 @@ export class InfraRepositoryProvider implements InfraRepositoryInterface { proprio, lumiere, ST_AsGeoJSON(geom,6)::json as geom - FROM ${this.table} - WHERE ouvert = true - ${ - checkTerritoryParam(params.type) && params.code - ? `AND insee IN ( - SELECT arr - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime() - AND ${checkTerritoryParam(params.type)} = $1 - )` - : "" - };`, - }; - const response = await this.pg.getClient().query(sql); + FROM ${raw(this.table)} + WHERE ${join(filters, " AND ")} + `; + const response = await this.pg.getClient().query(query); return response.rows; } } From ac19ab1a36cbbd577bcc1b166b27fb7e6815025b Mon Sep 17 00:00:00 2001 From: Ludovic Delhomme Date: Tue, 21 Jan 2025 14:20:16 +0100 Subject: [PATCH 3/4] feat: finished reformat sql queries for obs --- .../providers/KeyfiguresRepositoryProvider.ts | 114 ++++++------- .../providers/LocationRepositoryProvider.ts | 50 +++--- .../providers/OccupationRepositoryProvider.ts | 159 ++++++++---------- 3 files changed, 132 insertions(+), 191 deletions(-) diff --git a/api/src/pdc/services/observatory/providers/KeyfiguresRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/KeyfiguresRepositoryProvider.ts index 0dfa107a04..7479575ceb 100644 --- a/api/src/pdc/services/observatory/providers/KeyfiguresRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/KeyfiguresRepositoryProvider.ts @@ -1,5 +1,6 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { checkTerritoryParam } from "../helpers/checkParams.ts"; import { @@ -12,8 +13,7 @@ import { @provider({ identifier: KeyfiguresRepositoryInterfaceResolver, }) -export class KeyfiguresRepositoryProvider - implements KeyfiguresRepositoryInterface { +export class KeyfiguresRepositoryProvider implements KeyfiguresRepositoryInterface { private readonly table = ( params: KeyfiguresParamsInterface, table: "flux" | "occupation" | "newcomer", @@ -30,78 +30,63 @@ export class KeyfiguresRepositoryProvider ): Promise { const typeParam = checkTerritoryParam(params.type); const joinOnB = [ - "(a.territory_1 = b.code OR a.territory_2 = b.code)", - "a.type = b.type", - "a.year = b.year", + sql`(a.territory_1 = b.code OR a.territory_2 = b.code)`, + sql`a.type = b.type`, + sql`a.year = b.year`, ]; const joinOnC = [ - "(a.territory_1 = c.code OR a.territory_2 = c.code)", - "a.type = c.type", - "a.year = c.year", + sql`(a.territory_1 = c.code OR a.territory_2 = c.code)`, + sql`a.type = c.type`, + sql`a.year = c.year`, ]; - const conditions = [ - `a.year = $1`, - `a.type = $2`, - "b.code = $3", - "c.code = $3", + const filters = [ + sql`a.year = ${params.year}`, + sql`a.type = ${typeParam}`, + sql`b.code = ${params.code}`, + sql`c.code = ${params.code}`, ]; - const intraJourneysConditions = [ - "territory_1 = territory_2", - "year = $1", - "type = $2", - "territory_1 = $3", - ]; - const queryValues = [ - params.year, - typeParam, - params.code, + const intraJourneysFilters = [ + sql`territory_1 = territory_2`, + sql`year = ${params.year}`, + sql`type = ${typeParam}`, + sql`territory_1 = ${params.code}`, ]; if (params.direction) { - queryValues.push(params.direction); - conditions.push(`b.direction = $4`); - conditions.push(`c.direction = $4`); + filters.push(sql`b.direction = ${params.direction}`); + filters.push(sql`c.direction = ${params.direction}`); } if (params.month) { - queryValues.push(params.month); - joinOnB.push("a.month = b.month"); - joinOnC.push("a.month = c.month"); - params.direction - ? intraJourneysConditions.push(`month = $5`) - : intraJourneysConditions.push(`month = $4`); - params.direction - ? conditions.push(`a.month = $5`) - : conditions.push(`a.month = $4`); + joinOnB.push(sql`a.month = b.month`); + joinOnC.push(sql`a.month = c.month`); + if (params.direction) { + intraJourneysFilters.push(sql`month = ${params.month}`); + filters.push(sql`a.month = ${params.month}`); + } } if (params.trimester) { - queryValues.push(params.trimester); - joinOnB.push("a.trimester = b.trimester"); - joinOnC.push("a.trimester = c.trimester"); - params.direction - ? intraJourneysConditions.push(`trimester = $5`) - : intraJourneysConditions.push(`trimester = $4`); - params.direction - ? conditions.push(`a.trimester = $5`) - : conditions.push(`a.trimester = $4`); + joinOnB.push(sql`a.trimester = b.trimester`); + joinOnC.push(sql`a.trimester = c.trimester`); + if (params.direction) { + intraJourneysFilters.push(sql`trimester= ${params.trimester}`); + filters.push(sql`a.trimester = ${params.trimester}`); + } } if (params.semester) { - queryValues.push(params.semester); - joinOnB.push("a.semester = b.semester"); - joinOnC.push("a.semester = c.semester"); - params.direction - ? intraJourneysConditions.push(`semester = $5`) - : intraJourneysConditions.push(`semester = $4`); - params.direction - ? conditions.push(`a.semester = $5`) - : conditions.push(`a.semester = $4`); + joinOnB.push(sql`a.semester = b.semester`); + joinOnC.push(sql`a.semester = c.semester`); + if (params.direction) { + intraJourneysFilters.push(sql`semester= ${params.semester}`); + filters.push(sql`a.semester = ${params.semester}`); + } } - const intraJourneysQuery = ` + const intraJourneysQuery = sql` SELECT journeys - FROM ${this.table(params, "flux")} - WHERE ${intraJourneysConditions.join(" AND ")} + FROM ${raw(this.table(params, "flux"))} + WHERE ${join(intraJourneysFilters, " AND ")} `; - const queryText = ` + const query = sql` SELECT b.code,b.libelle,b.direction, sum(a.passengers)::int AS passengers, @@ -112,18 +97,13 @@ export class KeyfiguresRepositoryProvider b.occupation_rate::float, c.new_drivers::int, c.new_passengers::int - FROM ${this.table(params, "flux")} a - LEFT JOIN ${this.table(params, "occupation")} b ON ${ - joinOnB.join(" AND ") - } - LEFT JOIN ${this.table(params, "newcomer")} c ON ${joinOnC.join(" AND ")} - WHERE ${conditions.join(" AND ")} + FROM ${raw(this.table(params, "flux"))} a + LEFT JOIN ${raw(this.table(params, "occupation"))} b ON ${join(joinOnB, " AND ")} + LEFT JOIN ${raw(this.table(params, "newcomer"))} c ON ${join(joinOnC, " AND ")} + WHERE ${join(filters, " AND ")} GROUP BY b.code,b.libelle,b.direction,b.journeys,b.occupation_rate,c.new_drivers,c.new_passengers; `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } diff --git a/api/src/pdc/services/observatory/providers/LocationRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/LocationRepositoryProvider.ts index c83462f04d..bc84e1ca0a 100644 --- a/api/src/pdc/services/observatory/providers/LocationRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/LocationRepositoryProvider.ts @@ -1,6 +1,7 @@ import { latLngToCell } from "@/deps.ts"; import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; import { checkTerritoryParam } from "../helpers/checkParams.ts"; import { LocationParamsInterface, @@ -23,67 +24,54 @@ export class LocationRepositoryProvider implements LocationRepositoryInterface { ): Promise { const result: LocationResultInterface = []; const typeParam = checkTerritoryParam(params.type); - const perimTableQuery = ` + const perimTableQuery = sql` SELECT com FROM ( SELECT com, epci, aom, dep, reg, country - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime_or($1::smallint) + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = $2 + WHERE ${raw(typeParam)} = ${params.code} `; - const conditions = [ - `extract('year' from start_datetime) = $1`, - `(start_geo_code IN (${perimTableQuery}) OR end_geo_code IN (${perimTableQuery}))`, - ]; - - const queryValues = [ - params.year, - params.code, + const filters = [ + sql`extract('year' from start_datetime) = ${params.year}`, + sql`(start_geo_code IN (${perimTableQuery}) OR end_geo_code IN (${perimTableQuery}))`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`extract('month' from start_datetime) = $3`); + filters.push(sql`extract('month' from start_datetime) = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`extract('quarter' FROM start_datetime) = $3`); + filters.push(sql`extract('quarter' FROM start_datetime) = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push( - `(CASE WHEN extract('quarter' FROM start_datetime)::int > 3 THEN 2 ELSE 1 END) = $3`, + filters.push( + sql`(CASE WHEN extract('quarter' FROM start_datetime)::int > 3 THEN 2 ELSE 1 END) = ${params.semester}`, ); } - const queryText = ` + const query = sql` SELECT start_lat as lat, start_lon as lon - FROM ${this.table} - WHERE ${conditions.join(" AND ")} + FROM ${raw(this.table)} + WHERE ${join(filters, " AND ")} UNION ALL SELECT end_lat as lat, end_lon as lon - FROM ${this.table} - WHERE ${conditions.join(" AND ")} + FROM ${raw(this.table)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); const geomToHex = response.rows .map((r) => latLngToCell(r.lat, r.lon, params.zoom)) .reduce>( (acc, curr) => ((acc[curr] = (acc[curr] || 0) + 1), acc), {}, ); - Object.entries(geomToHex).forEach(([key, val]) => - result.push({ hex: key, count: Number(val) }) - ); + Object.entries(geomToHex).forEach(([key, val]) => result.push({ hex: key, count: Number(val) })); return result; } } diff --git a/api/src/pdc/services/observatory/providers/OccupationRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/OccupationRepositoryProvider.ts index cc15d4df4c..2806a424d0 100644 --- a/api/src/pdc/services/observatory/providers/OccupationRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/OccupationRepositoryProvider.ts @@ -1,9 +1,7 @@ import { provider } from "@/ilos/common/index.ts"; import { PostgresConnection } from "@/ilos/connection-postgres/index.ts"; -import { - checkIndicParam, - checkTerritoryParam, -} from "@/pdc/services/observatory/helpers/checkParams.ts"; +import sql, { join, raw } from "@/lib/pg/sql.ts"; +import { checkIndicParam, checkTerritoryParam } from "@/pdc/services/observatory/helpers/checkParams.ts"; import { getTableName } from "@/pdc/services/observatory/helpers/tableName.ts"; import { BestTerritoriesParamsInterface, @@ -19,8 +17,7 @@ import { @provider({ identifier: OccupationRepositoryInterfaceResolver, }) -export class OccupationRepositoryProvider - implements OccupationRepositoryInterface { +export class OccupationRepositoryProvider implements OccupationRepositoryInterface { private readonly table = ( params: | OccupationParamsInterface @@ -40,61 +37,48 @@ export class OccupationRepositoryProvider const observeParam = checkTerritoryParam(params.observe); const typeParam = checkTerritoryParam(params.type); const selectedVar = [ - "year", - "type", - "code", - "libelle", - "journeys", - "occupation_rate", - "geom", + sql`year`, + sql`type`, + sql`code`, + sql`libelle`, + sql`journeys`, + sql`occupation_rate`, + sql`geom`, ]; - const perimTableQuery = ` - SELECT ${observeParam} + const perimTableQuery = sql` + SELECT ${raw(observeParam)} FROM ( SELECT com, epci, aom, dep, reg, country - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime_or($1::smallint) + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = $2 + WHERE ${raw(typeParam)} = ${params.code} `; - const conditions = [ - `year = $1`, - `type = $3`, - `code IN (${perimTableQuery})`, - `direction = $4`, - ]; - - const queryValues = [ - params.year, - params.code, - observeParam, - params.direction, + const filters = [ + sql`year = ${params.year}`, + sql`type = ${observeParam}`, + sql`code IN (${perimTableQuery})`, + sql`direction = ${params.direction}`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $5`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $5`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $5`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT - ${selectedVar.join(", ")} - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + ${join(selectedVar, ", ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } @@ -112,43 +96,39 @@ export class OccupationRepositoryProvider const indicParam = checkIndicParam(params.indic, indics, "journeys"); const typeParam = checkTerritoryParam(params.type); const limit = params.past ? Number(params.past) * 12 + 1 : 25; - const queryValues = [typeParam, params.code, limit]; const selectedVar = [ - "year", - `${indicParam}`, + sql`year`, + sql`${indicParam}`, ]; - const conditions = [ - `type = $1`, - `code = $2`, - `direction = 'both'`, + const filters = [ + sql`type = ${typeParam}`, + sql`code = ${params.code}`, + sql`direction = 'both'`, ]; const orderBy = [ - "year", + sql`year`, ]; if (params.month) { - selectedVar.push("month"); - orderBy.push("month"); + selectedVar.push(sql`month`); + orderBy.push(sql`month`); } if (params.trimester) { - selectedVar.push("trimester"); - orderBy.push("trimester"); + selectedVar.push(sql`trimester`); + orderBy.push(sql`trimester`); } if (params.semester) { - selectedVar.push("semester"); - orderBy.push("semester"); + selectedVar.push(sql`semester`); + orderBy.push(sql`semester`); } - const queryText = ` - SELECT ${selectedVar.join(", ")} - FROM ${tableName} - WHERE ${conditions.join(" AND ")} - ORDER BY (${orderBy.join(", ")}) DESC - LIMIT $3; + const query = sql` + SELECT ${join(selectedVar, ", ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} + ORDER BY (${join(orderBy, ", ")}) DESC + LIMIT ${limit}; `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } @@ -159,46 +139,39 @@ export class OccupationRepositoryProvider const tableName = this.table(params); const typeParam = checkTerritoryParam(params.type); const observeParam = checkTerritoryParam(params.observe); - const queryValues = [params.year, params.code, observeParam, params.limit]; - const perimTableQuery = ` - SELECT ${observeParam} + const perimTableQuery = sql` + SELECT ${raw(observeParam)} FROM ( SELECT com, epci, aom, dep, reg, country - FROM ${this.perim_table} - WHERE year = geo.get_latest_millesime_or($1::smallint) + FROM ${raw(this.perim_table)} + WHERE year = geo.get_latest_millesime_or(${params.year}::smallint) ) t - WHERE ${typeParam} = $2 + WHERE ${raw(typeParam)} = ${params.code} `; - const conditions = [ - `year = $1`, - `type = $3`, - `direction = 'both'`, - `code IN (${perimTableQuery})`, + const filters = [ + sql`year = ${params.year}`, + sql`type = ${observeParam}`, + sql`direction = 'both'`, + sql`code IN (${perimTableQuery})`, ]; if (params.month) { - queryValues.push(params.month); - conditions.push(`month = $5`); + filters.push(sql`month = ${params.month}`); } if (params.trimester) { - queryValues.push(params.trimester); - conditions.push(`trimester = $5`); + filters.push(sql`trimester = ${params.trimester}`); } if (params.semester) { - queryValues.push(params.semester); - conditions.push(`semester = $5`); + filters.push(sql`semester = ${params.semester}`); } - const queryText = ` + const query = sql` SELECT code, libelle, journeys - FROM ${tableName} - WHERE ${conditions.join(" AND ")} + FROM ${raw(tableName)} + WHERE ${join(filters, " AND ")} ORDER BY journeys DESC - LIMIT $4; + LIMIT ${params.limit}; `; - const response = await this.pg.getClient().query({ - text: queryText, - values: queryValues, - }); + const response = await this.pg.getClient().query(query); return response.rows; } } From a53fe47273ea932ebfac4748b4647f0875dc51ed Mon Sep 17 00:00:00 2001 From: Ludovic Delhomme Date: Tue, 21 Jan 2025 14:27:19 +0100 Subject: [PATCH 4/4] fix: remove console.log in flux repo --- .../pdc/services/observatory/providers/FluxRepositoryProvider.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts index 7e1ef9a4ac..59a777fcb0 100644 --- a/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts +++ b/api/src/pdc/services/observatory/providers/FluxRepositoryProvider.ts @@ -122,7 +122,6 @@ export class FluxRepositoryProvider implements FluxRepositoryInterface { ORDER BY (${join(groupBy, ", ")}) DESC LIMIT ${limit}; `; - console.log(query.values, query.text); const response = await this.pg.getClient().query(query); return response.rows; }