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,119 +236,108 @@ 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 valid_geom AS (
265
- SELECT
266
- hwsd2,
267
- ST_MakeValid(geom) AS geom
268
- FROM { table_name }
269
- WHERE geom && ST_GeomFromText('{ buffer_wkt } ', 4326)
270
- AND ST_Intersects(geom, ST_GeomFromText('{ buffer_wkt } ', 4326))
271
- )
272
- SELECT
273
- hwsd2,
274
- ST_AsEWKB(geom) AS geom,
275
- ST_Distance(
276
- geom::geography,
277
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)::geography
278
- ) AS distance,
279
- ST_Intersects(
280
- geom,
281
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
282
- ) AS pt_intersect
283
- FROM valid_geom
284
- WHERE ST_Intersects(
285
- geom,
286
- ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
287
- );
288
- """
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 valid_geom AS (
263
+ SELECT
264
+ hwsd2,
265
+ ST_MakeValid(geom) AS geom
266
+ FROM { table_name }
267
+ WHERE geom && ST_GeomFromText('{ buffer_wkt } ', 4326)
268
+ AND ST_Intersects(geom, ST_GeomFromText('{ buffer_wkt } ', 4326))
269
+ )
270
+ SELECT
271
+ hwsd2,
272
+ ST_AsEWKB(geom) AS geom,
273
+ ST_Distance(
274
+ geom::geography,
275
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)::geography
276
+ ) AS distance,
277
+ ST_Intersects(
278
+ geom,
279
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
280
+ ) AS pt_intersect
281
+ FROM valid_geom
282
+ WHERE ST_Intersects(
283
+ geom,
284
+ ST_SetSRID(ST_Point({ lon } , { lat } ), 4326)
285
+ );
286
+ """
289
287
290
- # Use GeoPandas to execute the main query and load results into a GeoDataFrame.
291
- hwsd = gpd .read_postgis (main_query , conn , geom_col = "geom" )
292
- print ("Main query returned" , len (hwsd ), "rows." )
288
+ # Use GeoPandas to execute the main query and load results into a GeoDataFrame.
289
+ hwsd = gpd .read_postgis (main_query , connection , geom_col = "geom" )
290
+ print ("Main query returned" , len (hwsd ), "rows." )
293
291
294
- # Remove the geometry column (if not needed) from this dataset.
295
- hwsd = hwsd .drop (columns = ["geom" ])
292
+ # Remove the geometry column (if not needed) from this dataset.
293
+ hwsd = hwsd .drop (columns = ["geom" ])
296
294
297
- # Get the list of hwsd2 identifiers.
298
- hwsd2_mu_select = hwsd ["hwsd2" ].tolist ()
295
+ # Get the list of hwsd2 identifiers.
296
+ hwsd2_mu_select = hwsd ["hwsd2" ].tolist ()
299
297
300
- # Call get_hwsd2_profile_data using the same connection.
301
- hwsd_data = get_hwsd2_profile_data (conn , hwsd2_mu_select )
298
+ # Call get_hwsd2_profile_data using the same connection.
299
+ hwsd_data = get_hwsd2_profile_data (connection , hwsd2_mu_select )
302
300
303
- # Merge the two datasets.
304
- merged = pd .merge (hwsd_data , hwsd , on = "hwsd2" , how = "left" ).drop_duplicates ()
305
- return merged
301
+ # Merge the two datasets.
302
+ merged = pd .merge (hwsd_data , hwsd , on = "hwsd2" , how = "left" ).drop_duplicates ()
303
+ return merged
306
304
307
305
308
306
# global
309
307
310
308
311
309
# Function to fetch data from a PostgreSQL table
312
- def fetch_table_from_db (table_name ):
313
- conn = None
310
+ def fetch_table_from_db (connection , table_name ):
314
311
try :
315
- conn = get_datastore_connection ()
316
- cur = conn .cursor ()
317
-
318
- query = f"SELECT * FROM { table_name } ORDER BY id ASC;"
319
- cur .execute (query )
320
- rows = cur .fetchall ()
312
+ with connection .cursor () as cur :
313
+ query = f"SELECT * FROM { table_name } ORDER BY id ASC;"
314
+ cur .execute (query )
315
+ rows = cur .fetchall ()
321
316
322
- return rows
317
+ return rows
323
318
324
319
except Exception as err :
325
320
logging .error (f"Error querying PostgreSQL: { err } " )
326
321
return None
327
322
328
- finally :
329
- if conn :
330
- conn .close ()
331
-
332
323
333
- def get_WRB_descriptions (WRB_Comp_List ):
324
+ def get_WRB_descriptions (connection , WRB_Comp_List ):
334
325
"""
335
326
Retrieve WRB descriptions based on provided WRB component list.
336
327
"""
337
- conn = None
338
328
try :
339
- conn = get_datastore_connection ()
340
- cur = conn .cursor ()
341
-
342
- # Create placeholders for the SQL IN clause
343
- placeholders = ", " .join (["%s" ] * len (WRB_Comp_List ))
344
- sql = f"""SELECT WRB_tax, Description_en, Management_en, Description_es, Management_es,
345
- Description_ks, Management_ks, Description_fr, Management_fr
346
- FROM wrb_fao90_desc
347
- WHERE WRB_tax IN ({ placeholders } )"""
329
+ with connection .cursor () as cur :
348
330
349
- # Execute the query with the parameters
350
- cur .execute (sql , tuple (WRB_Comp_List ))
351
- results = cur .fetchall ()
331
+ # Create placeholders for the SQL IN clause
332
+ placeholders = ", " .join (["%s" ] * len (WRB_Comp_List ))
333
+ sql = f"""SELECT WRB_tax, Description_en, Management_en, Description_es, Management_es,
334
+ Description_ks, Management_ks, Description_fr, Management_fr
335
+ FROM wrb_fao90_desc
336
+ WHERE WRB_tax IN ({ placeholders } )"""
337
+
338
+ # Execute the query with the parameters
339
+ cur .execute (sql , tuple (WRB_Comp_List ))
340
+ results = cur .fetchall ()
352
341
353
342
# Convert the results to a pandas DataFrame
354
343
data = pd .DataFrame (
@@ -367,18 +356,13 @@ def get_WRB_descriptions(WRB_Comp_List):
367
356
)
368
357
369
358
return data
370
-
371
359
except Exception as err :
372
360
logging .error (f"Error querying PostgreSQL: { err } " )
373
361
return None
374
362
375
- finally :
376
- if conn :
377
- conn .close ()
378
-
379
363
380
364
# global only
381
- def getSG_descriptions (WRB_Comp_List ):
365
+ def getSG_descriptions (connection , WRB_Comp_List ):
382
366
"""
383
367
Fetch WRB descriptions from a PostgreSQL database using wrb2006_to_fao90
384
368
and wrb_fao90_desc tables. Returns a pandas DataFrame with columns:
@@ -391,13 +375,10 @@ def getSG_descriptions(WRB_Comp_List):
391
375
pandas.DataFrame or None if an error occurs.
392
376
"""
393
377
394
- conn = None
395
378
try :
396
- # 1. Get a connection to your datastore (replace with your actual function):
397
- conn = get_datastore_connection ()
398
379
399
380
def execute_query (query , params ):
400
- with conn .cursor () as cur :
381
+ with connection .cursor () as cur :
401
382
# Execute the query with the parameters
402
383
cur .execute (query , params )
403
384
return cur .fetchall ()
@@ -468,7 +449,3 @@ def execute_query(query, params):
468
449
except Exception as err :
469
450
logging .error (f"Error querying PostgreSQL: { err } " )
470
451
return None
471
-
472
- finally :
473
- if conn :
474
- conn .close ()
0 commit comments