Skip to content

Commit 2814433

Browse files
committed
Fix tests
1 parent 0bb3919 commit 2814433

5 files changed

Lines changed: 55 additions & 18 deletions

File tree

apps/backend/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ STACK_QSTASH_NEXT_SIGNING_KEY=
8484
# Email monitor
8585
STACK_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=# enter the resend poller api key here
8686
STACK_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=# enter the resend domain that should receive the emails
87+
STACK_EMAIL_MONITOR_PROJECT_ID=# enter the project id for the project that the email monitor will attempt to sign up for
8788
STACK_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=# enter the publishable client key for email monitor to use when attempting a sign up
8889
STACK_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=# enter a valid verification callback url for the project that the email monitor will attempt to sign up for
8990
STACK_EMAIL_MONITOR_INBUCKET_API_URL=# enter a valid inbucket api url for the email monitor to check emails from in test mode

apps/backend/.env.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ STACK_STRIPE_WEBHOOK_SECRET=mock_stripe_webhook_secret
5959

6060
# Email monitor configuration for tests
6161
STACK_EMAIL_MONITOR_VERIFICATION_CALLBACK_URL=http://localhost:8101/handler/email-verification
62+
STACK_EMAIL_MONITOR_PROJECT_ID=internal
6263
STACK_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY=this-publishable-client-key-is-for-local-development-only
6364
STACK_EMAIL_MONITOR_RESEND_EMAIL_DOMAIN=stack-generated.example.com
6465
STACK_EMAIL_MONITOR_RESEND_EMAIL_API_KEY=this-is-a-fake-key

apps/backend/src/app/health/email/route.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const performSignUp = async (email: string, password: string) => {
6969
"Content-Type": "application/json",
7070
"X-Stack-Access-Type": "client",
7171
"X-Stack-Publishable-Client-Key": getEnvVariable("STACK_EMAIL_MONITOR_PUBLISHABLE_CLIENT_KEY"),
72-
"X-Stack-Project-Id": "internal",
72+
"X-Stack-Project-Id": getEnvVariable("STACK_EMAIL_MONITOR_PROJECT_ID"),
7373
},
7474
body: JSON.stringify({
7575
email,

apps/dashboard/src/lib/classify-query.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { describe, it, expect } from "vitest";
1+
import { describe, expect, it } from "vitest";
22
import { classifyClickHouseSqlVsPrompt } from "./classify-query";
33

44
describe("classifyClickHouseSqlVsPrompt", () => {

apps/dashboard/src/lib/classify-query.ts

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ export function classifyClickHouseSqlVsPrompt(input: unknown): {
1111
const raw = (input ?? "").toString();
1212
const s = raw.trim();
1313

14-
if (!s) return { kind: "prompt", confidence: 0.5, reasons: ["empty"] };
14+
if (!s) {
15+
return { kind: "prompt", confidence: 0.5, reasons: ["empty"] };
16+
}
1517

1618
// Strip code fences if someone pasted markdown
1719
const unfenced = s.replace(/^```[\w-]*\n([\s\S]*?)\n```$/m, "$1").trim();
@@ -25,15 +27,28 @@ export function classifyClickHouseSqlVsPrompt(input: unknown): {
2527
const reasons: string[] = [];
2628

2729
// 1) Strong starts (high signal)
28-
const startsWithSql = /^(with|select|insert|update|delete|alter|create|drop|truncate|show|describe|desc|explain|use|set)\b/i.test(unfenced);
29-
if (startsWithSql) { sql += 3; reasons.push("starts-with-sql-keyword"); }
30+
const startsWithSqlKeyword = /^(with|select|insert|update|delete|alter|create|drop|truncate|describe|desc|explain|use|set)\b/i.test(unfenced);
31+
const showEnglishLead = /^show\s+(me|us|my|our|your|them|him|her)\b/i.test(unfenced);
32+
const showHasSqlTarget = /^show\s+(tables?|databases?|columns?|create|processlist|functions?|settings|grants|roles|quotas|dictionary|dictionaries|clusters|indexes|partitions|privileges|users?)\b/i.test(unfenced);
33+
const startsWithShowSql = /^show\b/i.test(unfenced) && showHasSqlTarget && !showEnglishLead;
34+
const startsWithSql = startsWithSqlKeyword || startsWithShowSql;
35+
if (startsWithSql) {
36+
sql += 3;
37+
reasons.push("starts-with-sql-keyword");
38+
}
3039

3140
// 2) Structural patterns (very strong)
3241
const hasSelectFrom = /\bselect\b[\s\S]{0,300}\bfrom\b/i.test(unfenced);
33-
if (hasSelectFrom) { sql += 4; reasons.push("select-from-structure"); }
42+
if (hasSelectFrom) {
43+
sql += 4;
44+
reasons.push("select-from-structure");
45+
}
3446

3547
const hasInsertInto = /\binsert\b[\s\S]{0,80}\binto\b/i.test(unfenced);
36-
if (hasInsertInto) { sql += 4; reasons.push("insert-into-structure"); }
48+
if (hasInsertInto) {
49+
sql += 4;
50+
reasons.push("insert-into-structure");
51+
}
3752

3853
// 3) Common SQL clauses
3954
const clauseHits = [
@@ -49,44 +64,64 @@ export function classifyClickHouseSqlVsPrompt(input: unknown): {
4964
"prewhere", "final", "sample", "array", "engine", "partition", "ttl", "distributed", "merge", "replacing", "collapsing",
5065
"materialized", "view", "database", "table", "cluster"
5166
].filter(k => wordSet.has(k));
52-
if (chHits.length) { sql += 2; reasons.push("clickhouse-ish:" + chHits.join(",")); }
67+
if (chHits.length) {
68+
sql += 2;
69+
reasons.push("clickhouse-ish:" + chHits.join(","));
70+
}
5371

5472
// 5) Operator / punctuation density
5573
const opCount = (unfenced.match(/(<=|>=|!=|=|<|>|\b(in|like|ilike|between|and|or)\b)/gi) ?? []).length;
56-
if (opCount >= 2) { sql += 2; reasons.push("many-operators"); }
57-
else if (opCount === 1) { sql += 1; reasons.push("some-operators"); }
74+
if (opCount >= 2) {
75+
sql += 2;
76+
reasons.push("many-operators");
77+
} else if (opCount === 1) {
78+
sql += 1;
79+
reasons.push("some-operators");
80+
}
5881

5982
const punct = (unfenced.match(/[(),;*]/g) ?? []).length;
6083
const punctRatio = punct / Math.max(1, unfenced.length);
61-
if (punctRatio > 0.03) { sql += 1; reasons.push("sql-punctuation-density"); }
84+
if (punctRatio > 0.03) {
85+
sql += 1;
86+
reasons.push("sql-punctuation-density");
87+
}
6288

6389
// 6) Identifier-ish things
6490
if (/`[^`]+`/.test(unfenced) || /"[^"]+"\."[^"]+"/.test(unfenced)) {
65-
sql += 1; reasons.push("quoted-identifiers");
91+
sql += 1;
92+
reasons.push("quoted-identifiers");
6693
}
6794
if (/\b[a-z_]+\.[a-z_]+\b/i.test(unfenced)) {
68-
sql += 1; reasons.push("dot-identifiers");
95+
sql += 1;
96+
reasons.push("dot-identifiers");
6997
}
7098
if (/--|\/\*/.test(unfenced)) {
71-
sql += 1; reasons.push("sql-comments");
99+
sql += 1;
100+
reasons.push("sql-comments");
72101
}
73102

74103
// Prompt-ish features
75-
if (/[?]\s*$/.test(unfenced)) { prompt += 2; reasons.push("ends-with-question-mark"); }
104+
if (/[?]\s*$/.test(unfenced)) {
105+
prompt += 2;
106+
reasons.push("ends-with-question-mark");
107+
}
76108
if (/\b(please|could you|can you|what|why|how|explain|help)\b/i.test(unfenced)) {
77-
prompt += 2; reasons.push("prompt-words");
109+
prompt += 2;
110+
reasons.push("prompt-words");
78111
}
79112

80113
// If it's mostly letters/spaces and barely any operators, lean prompt.
81114
const symbolChars = (unfenced.match(/[^a-z0-9_\s]/gi) ?? []).length;
82115
const symbolRatio = symbolChars / Math.max(1, unfenced.length);
83116
if (symbolRatio < 0.06 && opCount === 0 && !startsWithSql) {
84-
prompt += 2; reasons.push("low-symbol-low-operator");
117+
prompt += 2;
118+
reasons.push("low-symbol-low-operator");
85119
}
86120

87121
// Avoid the classic false positive: "select ..." in English without any SQL structure
88122
if (/^select\b/i.test(unfenced) && !hasSelectFrom && clauseHits.length === 0 && opCount === 0) {
89-
prompt += 3; reasons.push("english-select-false-positive-guard");
123+
prompt += 3;
124+
reasons.push("english-select-false-positive-guard");
90125
}
91126

92127
const margin = sql - prompt;

0 commit comments

Comments
 (0)