Skip to content

Commit 6f7b510

Browse files
authored
MCP: Update AppKit and use typed SQL parameters (#4116)
## Changes - use AppKit from npm (no longer bundling it) - Use typed SQL queries ## Why <!-- Why are these changes needed? Provide the context that the reviewer might be missing. For example, were there any decisions behind the change that are not reflected in the code itself? --> ## Tests <!-- How have you tested the changes? --> <!-- If your PR needs to be included in the release notes for next release, add a separate entry in NEXT_CHANGELOG.md as part of your PR. -->
1 parent 26724c5 commit 6f7b510

File tree

12 files changed

+761
-1456
lines changed

12 files changed

+761
-1456
lines changed

.wsignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ python/docs/images/databricks-logo.svg
1111
**/*.zip
1212
**/*.whl
1313
**/*.png
14-
**/*.tgz
1514

1615
# new lines are recorded differently on windows and unix.
1716
# In unix: "raw_body": "hello, world\n"
Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
appkit/node_modules/
2-
appkit/dist/
3-
appkit/build/
4-
appkit/.env
5-
appkit/.databricks/
6-
appkit/.claude/
7-
appkit/.smoke-test/
8-
appkit/test-results/
9-
appkit/playwright-report/
1+
appkit/**/node_modules/
2+
appkit/**/dist/
3+
appkit/**/build/
4+
appkit/**/.env
5+
appkit/**/.databricks/
6+
appkit/**/.claude/
7+
appkit/**/.smoke-test/
8+
appkit/**/test-results/
9+
appkit/**/playwright-report/

experimental/apps-mcp/templates/appkit/databricks_template_schema.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
"order": 4
2626
}
2727
},
28-
"success_message": "\nYour new project has been created in the '{{.project_name}}' directory!\nYOU MUST read {{.project_name}}/CLAUDE.md immediately."
28+
"success_message": "\nYour new project has been created in the '{{.project_name}}' directory!"
2929
}

experimental/apps-mcp/templates/appkit/template/{{.project_name}}/client/src/App.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useAnalyticsQuery, AreaChart, LineChart, RadarChart } from '@databricks/app-kit-ui/react';
2+
import { sql } from "@databricks/app-kit-ui/js";
23
import { Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts';
34
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
45
import { Skeleton } from '@/components/ui/skeleton';
@@ -9,7 +10,7 @@ import { useState, useEffect } from 'react';
910

1011
function App() {
1112
const { data, loading, error } = useAnalyticsQuery('hello_world', {
12-
message: 'hello world',
13+
message: sql.string('hello world'),
1314
});
1415

1516
const [health, setHealth] = useState<{
@@ -48,7 +49,7 @@ function App() {
4849

4950
const [maxMonthNum, setMaxMonthNum] = useState<number>(12);
5051

51-
const salesParameters = { max_month_num: maxMonthNum };
52+
const salesParameters = { max_month_num: sql.number(maxMonthNum) };
5253

5354
return (
5455
<div className="min-h-screen bg-background flex flex-col items-center justify-center p-4 w-full">

experimental/apps-mcp/templates/appkit/template/{{.project_name}}/config/queries/schema.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
* Example:
99
* SQL: SELECT name, age FROM users WHERE city = :city
1010
* Schema: z.array(z.object({ name: z.string(), age: z.number() }))
11-
* Usage: useAnalyticsQuery('users', { city: 'NYC' })
11+
* Usage: useAnalyticsQuery('users', { city: sql.string('NYC') })
1212
* ^ input params ^ schema validates this result
1313
*/
1414

1515
import { z } from 'zod';
16-
1716
export const querySchemas = {
1817
mocked_sales: z.array(
1918
z.object({

experimental/apps-mcp/templates/appkit/template/{{.project_name}}/docs/app-kit-sdk.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@ import { Skeleton } from '@/components/ui/skeleton';
5151
interface QueryResult { column_name: string; value: number; }
5252

5353
function CustomDisplay() {
54-
const { data, loading, error } = useAnalyticsQuery<QueryResult[]>('query_name', {});
54+
const { data, loading, error } = useAnalyticsQuery<QueryResult[]>('query_name', {
55+
start_date: sql.date(Date.now()),
56+
category: sql.string("tools")
57+
});
5558

5659
if (loading) return <Skeleton className="h-4 w-3/4" />;
5760
if (error) return <div className="text-destructive">Error: {error}</div>;
@@ -74,7 +77,7 @@ function CustomDisplay() {
7477
```typescript
7578
const { data, loading, error } = useAnalyticsQuery<T>(
7679
queryName: string, // SQL file name without .sql extension
77-
params: Record<string, string | number> // Query parameters
80+
params: Record<string, SQLTypeMarker> // Query parameters
7881
);
7982
// Returns: { data: T | null, loading: boolean, error: string | null }
8083
```

experimental/apps-mcp/templates/appkit/template/{{.project_name}}/docs/frontend.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Available: `AreaChart`, `BarChart`, `LineChart`, `PieChart`, `RadarChart`, `Data
1111
```typescript
1212
import { BarChart, LineChart, DataTable } from '@databricks/app-kit-ui/react';
1313
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
14+
import { sql } from "@databricks/app-kit-ui/js";
1415

1516
function MyDashboard() {
1617
return (
@@ -25,7 +26,7 @@ function MyDashboard() {
2526
<Card>
2627
<CardHeader><CardTitle>Revenue Trend</CardTitle></CardHeader>
2728
<CardContent>
28-
<LineChart queryKey="revenue_over_time" parameters={{ months: 12 }} />
29+
<LineChart queryKey="revenue_over_time" parameters={{ months: sql.number(12) }} />
2930
</CardContent>
3031
</Card>
3132
</div>

experimental/apps-mcp/templates/appkit/template/{{.project_name}}/docs/sql-queries.md

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -98,28 +98,64 @@ WHERE column_value >= :min_value
9898
### Frontend Parameter Passing
9999

100100
```typescript
101+
import { sql } from "@databricks/app-kit-ui/js";
102+
101103
const { data } = useAnalyticsQuery('filtered_data', {
102-
min_value: minValue,
103-
max_value: maxValue,
104-
category: category,
105-
optional_filter: optionalFilter || '', // empty string for optional params
104+
min_value: sql.number(minValue),
105+
max_value: sql.number(maxValue),
106+
category: sql.string(category),
107+
optional_filter: sql.string(optionalFilter || ''), // empty string for optional params
106108
});
107109
```
108110

109111
### Date Parameters
110112

111-
For dates, use `YYYY-MM-DD` format in frontend, `CAST()` function in SQL:
113+
Use `sql.date()` for date parameters with `YYYY-MM-DD` format strings.
114+
115+
**Frontend - Using Date Parameters:**
112116

113117
```typescript
114-
// Date helper for query params
115-
const daysAgo = (n: number) => new Date(Date.now() - n * 86400000).toISOString().split('T')[0];
118+
import { sql } from '@databricks/app-kit-ui/js';
119+
import { useState } from 'react';
120+
121+
function MyComponent() {
122+
const [startDate, setStartDate] = useState<string>('2016-02-01');
123+
const [endDate, setEndDate] = useState<string>('2016-02-29');
124+
125+
const queryParams = {
126+
start_date: sql.date(startDate), // Pass YYYY-MM-DD string to sql.date()
127+
end_date: sql.date(endDate),
128+
};
129+
130+
const { data } = useAnalyticsQuery('my_query', queryParams);
116131

117-
const startDate = daysAgo(7); // 7 days ago
132+
// ...
133+
}
118134
```
119135

136+
**SQL - Date Filtering:**
137+
120138
```sql
121-
-- SQL
122-
WHERE timestamp_column >= CAST(:start_date AS DATE)
139+
-- Filter by date range using DATE() function
140+
SELECT COUNT(*) as trip_count
141+
FROM samples.nyctaxi.trips
142+
WHERE DATE(tpep_pickup_datetime) >= :start_date
143+
AND DATE(tpep_pickup_datetime) <= :end_date
144+
```
145+
146+
**Date Helper Functions:**
147+
148+
```typescript
149+
// Helper to get dates relative to today
150+
const daysAgo = (n: number) => {
151+
const date = new Date(Date.now() - n * 86400000);
152+
return sql.date(date)
153+
};
154+
155+
const params = {
156+
start_date: daysAgo(7), // 7 days ago
157+
end_date: sql.date(daysAgo(0)), // Today
158+
};
123159
```
124160

125161
### Optional Date Parameters - Use Sentinel Dates
@@ -132,10 +168,10 @@ Databricks App Kit validates parameter types before query execution. **DO NOT us
132168
// Frontend: Use sentinel dates for "no filter" instead of empty strings
133169
const revenueParams = {
134170
group_by: 'month',
135-
start_date: '1900-01-01', // Sentinel: effectively no lower bound
136-
end_date: '9999-12-31', // Sentinel: effectively no upper bound
137-
country: country || '',
138-
property_type: propertyType || '',
171+
start_date: sql.date('1900-01-01'), // Sentinel: effectively no lower bound
172+
end_date: sql.date('9999-12-31'), // Sentinel: effectively no upper bound
173+
country: sql.string(country || ''),
174+
property_type: sql.string(propertyType || ''),
139175
};
140176
```
141177

@@ -145,24 +181,15 @@ WHERE b.check_in >= CAST(:start_date AS DATE)
145181
AND b.check_in <= CAST(:end_date AS DATE)
146182
```
147183

148-
**❌ WRONG - Empty Strings Cause Validation Errors:**
149-
150-
```typescript
151-
// ❌ DON'T DO THIS - causes "Invalid date format" error
152-
const params = {
153-
start_date: '', // Empty string triggers parameter validation error
154-
end_date: '',
155-
};
156-
```
157-
158184
**Why Sentinel Dates Work:**
159185
- `1900-01-01` is before any real data (effectively no lower bound filter)
160186
- `9999-12-31` is after any real data (effectively no upper bound filter)
161187
- Always valid DATE types, so no parameter validation errors
162188
- All real dates fall within this range, so no filtering occurs
163189

164190
**Parameter Types Summary:**
191+
- ALWAYS use sql.* helper functions from the `@databricks/app-kit-ui/js` package to define SQL parameters
165192
- **Strings/Numbers**: Use directly in SQL with `:param_name`
166-
- **Dates**: Format as `YYYY-MM-DD`, use with `CAST(:param AS DATE)` in SQL
193+
- **Dates**: Use with `CAST(:param AS DATE)` in SQL
167194
- **Optional Strings**: Use empty string default, check with `(:param = '' OR column = :param)`
168-
- **Optional Dates**: Use sentinel dates (`'1900-01-01'` and `'9999-12-31'`) instead of empty strings
195+
- **Optional Dates**: Use sentinel dates (`sql.date('1900-01-01')` and `sql.date('9999-12-31')`) instead of empty strings

0 commit comments

Comments
 (0)