jashdoshi77 commited on
Commit
4791304
Β·
1 Parent(s): c442c5a

added join status logic

Browse files
Files changed (2) hide show
  1. ai/signatures.py +19 -1
  2. ai/sql_pattern_checker.py +52 -0
ai/signatures.py CHANGED
@@ -270,6 +270,15 @@ class AnalyzeAndPlan(dspy.Signature):
270
  β€’ Component cost queries from sales_order_line_pricing
271
  (join back to sales_order and apply status = 'closed')
272
 
 
 
 
 
 
 
 
 
 
273
  NEVER apply status = 'closed' to:
274
  β€’ Purchase order tables (they have a separate status column)
275
  β€’ Inventory tables
@@ -490,7 +499,16 @@ class SQLGeneration(dspy.Signature):
490
  - NEVER add gold_amount + diamond_amount or any component columns β€”
491
  that always gives the WRONG answer (misses labour, taxes, etc.)
492
 
493
- 6. STATUS = 'closed' IS THE DEFAULT FOR ALL SALES ORDER QUERIES:
 
 
 
 
 
 
 
 
 
494
  Unless the question explicitly mentions a different status (e.g. "pending",
495
  "open", "cancelled", "all orders"), ALWAYS add WHERE so.status = 'closed'.
496
  This is not optional β€” omitting it returns incomplete/incorrect data.
 
270
  β€’ Component cost queries from sales_order_line_pricing
271
  (join back to sales_order and apply status = 'closed')
272
 
273
+ IMPORTANT β€” line-level tables have NO status column:
274
+ sales_order_line_pricing, sales_order_line_gold, sales_order_line_diamond,
275
+ and sales_order_line do NOT have a status column.
276
+ To apply the status filter when using these tables, you MUST join back to
277
+ sales_table_v2_sales_order and filter on so.status = 'closed':
278
+ JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id
279
+ JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id
280
+ WHERE so.status = 'closed'
281
+
282
  NEVER apply status = 'closed' to:
283
  β€’ Purchase order tables (they have a separate status column)
284
  β€’ Inventory tables
 
499
  - NEVER add gold_amount + diamond_amount or any component columns β€”
500
  that always gives the WRONG answer (misses labour, taxes, etc.)
501
 
502
+ 6. STATUS = 'closed' IS THE DEFAULT β€” AND LINE TABLES HAVE NO STATUS COLUMN:
503
+ sales_order_line_pricing / sales_order_line_gold / sales_order_line_diamond
504
+ do NOT have a status column. When using these tables, you MUST join back to
505
+ sales_table_v2_sales_order to apply the filter:
506
+ JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id
507
+ JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id
508
+ WHERE so.status = 'closed'
509
+ Omitting this join means ALL orders (cancelled, pending, open) are included β€” WRONG.
510
+
511
+ 6b. STATUS = 'closed' IS THE DEFAULT FOR ALL SALES ORDER QUERIES:
512
  Unless the question explicitly mentions a different status (e.g. "pending",
513
  "open", "cancelled", "all orders"), ALWAYS add WHERE so.status = 'closed'.
514
  This is not optional β€” omitting it returns incomplete/incorrect data.
ai/sql_pattern_checker.py CHANGED
@@ -237,6 +237,58 @@ def check_sql_patterns(sql: str) -> list[dict[str, Any]]:
237
  # Generic β€” works for gold_kt on pricing table, or any future similar mistake.
238
  issues.extend(check_column_table_mismatches(sql))
239
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  return issues
241
 
242
 
 
237
  # Generic β€” works for gold_kt on pricing table, or any future similar mistake.
238
  issues.extend(check_column_table_mismatches(sql))
239
 
240
+ # ── Pattern 5 ────────────────────────────────────────────────────────────
241
+ # Sales line tables used without joining sales_order for the status filter.
242
+ # Any query on line-level tables (pricing, gold, diamond, sales_order_line)
243
+ # must join back to sales_table_v2_sales_order and apply status = 'closed'
244
+ # unless a different status is explicitly present in the SQL.
245
+ SALES_LINE_TABLES = {
246
+ "sales_table_v2_sales_order_line_pricing",
247
+ "sales_table_v2_sales_order_line_gold",
248
+ "sales_table_v2_sales_order_line_diamond",
249
+ "sales_table_v2_sales_order_line",
250
+ }
251
+ SALES_HEADER = "sales_table_v2_sales_order"
252
+
253
+ tables_in_sql = {t.lower() for t in re.findall(r'\b(\w+)\b', sql_lower)}
254
+ uses_line_table = bool(SALES_LINE_TABLES & tables_in_sql)
255
+ has_sales_header = SALES_HEADER in tables_in_sql
256
+ has_status_filter = bool(re.search(r"\bstatus\s*=", sql_lower))
257
+
258
+ if uses_line_table and not has_status_filter:
259
+ # Only flag if the header table is absent (status can't be filtered)
260
+ # OR if the header is present but status filter is still missing
261
+ issues.append({
262
+ "pattern_name": "missing_status_closed_on_line_tables",
263
+ "description": (
264
+ "MISSING status = 'closed' filter: the query uses sales line tables "
265
+ "(sales_order_line_pricing / sales_order_line_gold / sales_order_line_diamond) "
266
+ "but does not filter by sales_order status. "
267
+ "Line tables have no status column β€” you must JOIN sales_table_v2_sales_order "
268
+ "and add WHERE so.status = 'closed' to exclude incomplete/cancelled orders."
269
+ ),
270
+ "correction": (
271
+ "Add a JOIN to sales_table_v2_sales_order and filter by status:\n"
272
+ "\n"
273
+ "JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id\n"
274
+ "JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id\n"
275
+ "WHERE so.status = 'closed'\n"
276
+ "\n"
277
+ "Full corrected structure example:\n"
278
+ "SELECT g.gold_kt,\n"
279
+ " SUM(lp.gold_amount_per_unit * lp.quantity) AS total_gold_amount,\n"
280
+ " SUM(lp.diamond_amount_per_unit * lp.quantity) AS total_diamond_amount,\n"
281
+ " SUM(lp.making_charges_per_unit * lp.quantity) AS total_making_charges\n"
282
+ "FROM sales_table_v2_sales_order_line_pricing lp\n"
283
+ "JOIN sales_table_v2_sales_order_line_gold g ON lp.sol_id = g.sol_id\n"
284
+ "JOIN sales_table_v2_sales_order_line sol ON lp.sol_id = sol.sol_id\n"
285
+ "JOIN sales_table_v2_sales_order so ON sol.so_id = so.so_id\n"
286
+ "WHERE so.status = 'closed'\n"
287
+ "GROUP BY g.gold_kt\n"
288
+ "ORDER BY g.gold_kt"
289
+ ),
290
+ })
291
+
292
  return issues
293
 
294