21
21
22
22
# Third-party libraries
23
23
import psycopg
24
- from shapely import wkb
25
- from shapely .geometry import Point
26
24
27
25
# local libraries
28
26
import soil_id .config
27
+ from shapely import wkb
28
+ from shapely .geometry import Point
29
29
30
30
31
31
def get_datastore_connection ():
@@ -162,7 +162,7 @@ def save_soilgrids_output(plot_id, model_version, soilgrids_blob):
162
162
conn .close ()
163
163
164
164
165
- def get_hwsd2_profile_data (conn , hwsd2_mu_select ):
165
+ def get_hwsd2_profile_data (connection , hwsd2_mu_select ):
166
166
"""
167
167
Retrieve HWSD v2 data based on selected hwsd2 (map unit) values.
168
168
This version reuses an existing connection.
@@ -179,7 +179,7 @@ def get_hwsd2_profile_data(conn, hwsd2_mu_select):
179
179
return pd .DataFrame ()
180
180
181
181
try :
182
- with conn .cursor () as cur :
182
+ with connection .cursor () as cur :
183
183
# Create placeholders for the SQL IN clause
184
184
placeholders = ", " .join (["%s" ] * len (hwsd2_mu_select ))
185
185
sql_query = f"""
@@ -222,7 +222,7 @@ def get_hwsd2_profile_data(conn, hwsd2_mu_select):
222
222
return pd .DataFrame ()
223
223
224
224
225
- def extract_hwsd2_data (lon , lat , buffer_dist , table_name ):
225
+ def extract_hwsd2_data (connection , lon , lat , buffer_dist , table_name ):
226
226
"""
227
227
Fetches HWSD soil data from a PostGIS table within a given buffer around a point,
228
228
performing distance and intersection calculations directly on geographic coordinates.
@@ -236,133 +236,121 @@ def extract_hwsd2_data(lon, lat, buffer_dist, table_name):
236
236
Returns:
237
237
DataFrame: Merged data from hwsdv2 and hwsdv2_data.
238
238
"""
239
- # Use a single connection for both queries.
240
- with get_datastore_connection () as conn :
241
- # Compute the buffer polygon (in WKT) around the problem point.
242
- # Here, we use the geography type to compute a buffer in meters,
243
- # then cast it back to geometry in EPSG:4326.
244
- buffer_query = """
245
- WITH buffer AS (
246
- SELECT ST_AsText(
247
- ST_Buffer(
248
- ST_SetSRID(ST_Point(%s, %s), 4326)::geography,
249
- %s
250
- )::geometry
251
- ) AS wkt
252
- )
253
- SELECT wkt FROM buffer;
254
- """
255
- with conn .cursor () as cur :
256
- cur .execute (buffer_query , (lon , lat , buffer_dist ))
257
- buffer_wkt = cur .fetchone ()[0 ]
258
- print ("Buffer WKT:" , buffer_wkt )
259
-
260
- # Build the main query that uses the computed buffer.
261
- # Distance is computed by casting geometries to geography,
262
- # which returns the geodesic distance in meters.
263
- main_query = f"""
264
- WITH
265
- -- Step 1: Get the polygon that contains the point
266
- point_poly AS (
267
- SELECT ST_MakeValid(geom) AS geom
268
- FROM { table_name }
269
- WHERE ST_Intersects(
270
- geom,
271
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
272
- )
273
- ),
274
-
275
- -- Step 2: Get polygons that intersect the buffer
276
- valid_geom AS (
277
- SELECT
278
- hwsd2,
279
- ST_MakeValid(geom) AS geom
280
- FROM { table_name }
281
- WHERE geom && ST_GeomFromText('{ buffer_wkt } ', 4326)
282
- AND ST_Intersects(geom, ST_GeomFromText('{ buffer_wkt } ', 4326))
283
- )
284
-
285
- -- Step 3: Filter to those that either contain the point or border the point's polygon
286
- SELECT
287
- vg.hwsd2,
288
- ST_AsEWKB(vg.geom) AS geom,
289
- ST_Distance(
290
- vg.geom::geography,
291
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)::geography
292
- ) AS distance,
293
- ST_Intersects(
294
- vg.geom,
295
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
296
- ) AS pt_intersect
297
- FROM valid_geom vg, point_poly pp
298
- WHERE
299
- ST_Intersects(vg.geom, ST_SetSRID(ST_Point({ lon } , { lat } ), 4326))
300
- OR ST_Intersects(vg.geom, pp.geom);
301
- """
239
+ # Compute the buffer polygon (in WKT) around the problem point.
240
+ # Here, we use the geography type to compute a buffer in meters,
241
+ # then cast it back to geometry in EPSG:4326.
242
+ buffer_query = """
243
+ WITH buffer AS (
244
+ SELECT ST_AsText(
245
+ ST_Buffer(
246
+ ST_SetSRID(ST_Point(%s, %s), 4326)::geography,
247
+ %s
248
+ )::geometry
249
+ ) AS wkt
250
+ )
251
+ SELECT wkt FROM buffer;
252
+ """
253
+ with connection .cursor () as cur :
254
+ cur .execute (buffer_query , (lon , lat , buffer_dist ))
255
+ buffer_wkt = cur .fetchone ()[0 ]
256
+ print ("Buffer WKT:" , buffer_wkt )
257
+
258
+ # Build the main query that uses the computed buffer.
259
+ # Distance is computed by casting geometries to geography,
260
+ # which returns the geodesic distance in meters.
261
+ main_query = f"""
262
+ WITH
263
+ -- Step 1: Get the polygon that contains the point
264
+ point_poly AS (
265
+ SELECT ST_MakeValid(geom) AS geom
266
+ FROM { table_name }
267
+ WHERE ST_Intersects(
268
+ geom,
269
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
270
+ )
271
+ ),
272
+
273
+ -- Step 2: Get polygons that intersect the buffer
274
+ valid_geom AS (
275
+ SELECT
276
+ hwsd2,
277
+ ST_MakeValid(geom) AS geom
278
+ FROM { table_name }
279
+ WHERE geom && ST_GeomFromText('{ buffer_wkt } ', 4326)
280
+ AND ST_Intersects(geom, ST_GeomFromText('{ buffer_wkt } ', 4326))
281
+ )
302
282
283
+ -- Step 3: Filter to those that either contain the point or border the point's polygon
284
+ SELECT
285
+ vg.hwsd2,
286
+ ST_AsEWKB(vg.geom) AS geom,
287
+ ST_Distance(
288
+ vg.geom::geography,
289
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)::geography
290
+ ) AS distance,
291
+ ST_Intersects(
292
+ vg.geom,
293
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
294
+ ) AS pt_intersect
295
+ FROM valid_geom vg, point_poly pp
296
+ WHERE
297
+ ST_Intersects(vg.geom, ST_SetSRID(ST_Point({ lon } , { lat } ), 4326))
298
+ OR ST_Intersects(vg.geom, pp.geom);
299
+ """
303
300
304
- # Use GeoPandas to execute the main query and load results into a GeoDataFrame.
305
- hwsd = gpd .read_postgis (main_query , conn , geom_col = "geom" )
306
- print ("Main query returned" , len (hwsd ), "rows." )
301
+ # Use GeoPandas to execute the main query and load results into a GeoDataFrame.
302
+ hwsd = gpd .read_postgis (main_query , connection , geom_col = "geom" )
303
+ print ("Main query returned" , len (hwsd ), "rows." )
307
304
308
- # Remove the geometry column (if not needed) from this dataset.
309
- hwsd = hwsd .drop (columns = ["geom" ])
305
+ # Remove the geometry column (if not needed) from this dataset.
306
+ hwsd = hwsd .drop (columns = ["geom" ])
310
307
311
- # Get the list of hwsd2 identifiers.
312
- hwsd2_mu_select = hwsd ["hwsd2" ].tolist ()
308
+ # Get the list of hwsd2 identifiers.
309
+ hwsd2_mu_select = hwsd ["hwsd2" ].tolist ()
313
310
314
- # Call get_hwsd2_profile_data using the same connection.
315
- hwsd_data = get_hwsd2_profile_data (conn , hwsd2_mu_select )
311
+ # Call get_hwsd2_profile_data using the same connection.
312
+ hwsd_data = get_hwsd2_profile_data (connection , hwsd2_mu_select )
316
313
317
- # Merge the two datasets.
318
- merged = pd .merge (hwsd_data , hwsd , on = "hwsd2" , how = "left" ).drop_duplicates ()
319
- return merged
314
+ # Merge the two datasets.
315
+ merged = pd .merge (hwsd_data , hwsd , on = "hwsd2" , how = "left" ).drop_duplicates ()
316
+ return merged
320
317
321
318
322
319
# global
323
320
324
321
325
322
# Function to fetch data from a PostgreSQL table
326
- def fetch_table_from_db (table_name ):
327
- conn = None
323
+ def fetch_table_from_db (connection , table_name ):
328
324
try :
329
- conn = get_datastore_connection ()
330
- cur = conn .cursor ()
331
-
332
- query = f"SELECT * FROM { table_name } ORDER BY id ASC;"
333
- cur .execute (query )
334
- rows = cur .fetchall ()
325
+ with connection .cursor () as cur :
326
+ query = f"SELECT * FROM { table_name } ORDER BY id ASC;"
327
+ cur .execute (query )
328
+ rows = cur .fetchall ()
335
329
336
- return rows
330
+ return rows
337
331
338
332
except Exception as err :
339
333
logging .error (f"Error querying PostgreSQL: { err } " )
340
334
return None
341
335
342
- finally :
343
- if conn :
344
- conn .close ()
345
336
346
-
347
- def get_WRB_descriptions (WRB_Comp_List ):
337
+ def get_WRB_descriptions (connection , WRB_Comp_List ):
348
338
"""
349
339
Retrieve WRB descriptions based on provided WRB component list.
350
340
"""
351
- conn = None
352
341
try :
353
- conn = get_datastore_connection ()
354
- cur = conn .cursor ()
342
+ with connection .cursor () as cur :
355
343
356
- # Create placeholders for the SQL IN clause
357
- placeholders = ", " .join (["%s" ] * len (WRB_Comp_List ))
358
- sql = f"""SELECT WRB_tax, Description_en, Management_en, Description_es, Management_es,
359
- Description_ks, Management_ks, Description_fr, Management_fr
360
- FROM wrb_fao90_desc
361
- WHERE WRB_tax IN ({ placeholders } )"""
362
-
363
- # Execute the query with the parameters
364
- cur .execute (sql , tuple (WRB_Comp_List ))
365
- results = cur .fetchall ()
344
+ # Create placeholders for the SQL IN clause
345
+ placeholders = ", " .join (["%s" ] * len (WRB_Comp_List ))
346
+ sql = f"""SELECT WRB_tax, Description_en, Management_en, Description_es, Management_es,
347
+ Description_ks, Management_ks, Description_fr, Management_fr
348
+ FROM wrb_fao90_desc
349
+ WHERE WRB_tax IN ({ placeholders } )"""
350
+
351
+ # Execute the query with the parameters
352
+ cur .execute (sql , tuple (WRB_Comp_List ))
353
+ results = cur .fetchall ()
366
354
367
355
# Convert the results to a pandas DataFrame
368
356
data = pd .DataFrame (
@@ -381,18 +369,13 @@ def get_WRB_descriptions(WRB_Comp_List):
381
369
)
382
370
383
371
return data
384
-
385
372
except Exception as err :
386
373
logging .error (f"Error querying PostgreSQL: { err } " )
387
374
return None
388
375
389
- finally :
390
- if conn :
391
- conn .close ()
392
-
393
376
394
377
# global only
395
- def getSG_descriptions (WRB_Comp_List ):
378
+ def getSG_descriptions (connection , WRB_Comp_List ):
396
379
"""
397
380
Fetch WRB descriptions from a PostgreSQL database using wrb2006_to_fao90
398
381
and wrb_fao90_desc tables. Returns a pandas DataFrame with columns:
@@ -405,13 +388,10 @@ def getSG_descriptions(WRB_Comp_List):
405
388
pandas.DataFrame or None if an error occurs.
406
389
"""
407
390
408
- conn = None
409
391
try :
410
- # 1. Get a connection to your datastore (replace with your actual function):
411
- conn = get_datastore_connection ()
412
392
413
393
def execute_query (query , params ):
414
- with conn .cursor () as cur :
394
+ with connection .cursor () as cur :
415
395
# Execute the query with the parameters
416
396
cur .execute (query , params )
417
397
return cur .fetchall ()
@@ -482,7 +462,3 @@ def execute_query(query, params):
482
462
except Exception as err :
483
463
logging .error (f"Error querying PostgreSQL: { err } " )
484
464
return None
485
-
486
- finally :
487
- if conn :
488
- conn .close ()
0 commit comments