@risingwave/wavelet-cli 0.1.4 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +50 -48
- package/dist/codegen.js.map +1 -1
- package/dist/index.js +17 -17
- package/dist/index.js.map +1 -1
- package/package.json +13 -4
- package/src/codegen.ts +51 -49
- package/src/index.ts +17 -17
package/dist/codegen.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAqC,MAAM,qBAAqB,CAAA;AAI3F,wBAAsB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA+DzE"}
|
package/dist/codegen.js
CHANGED
|
@@ -8,23 +8,25 @@ const node_fs_1 = require("node:fs");
|
|
|
8
8
|
const pg_1 = __importDefault(require("pg"));
|
|
9
9
|
const { Client } = pg_1.default;
|
|
10
10
|
async function generateClient(config) {
|
|
11
|
-
//
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
// Event types are always known from config
|
|
12
|
+
const eventTypes = [];
|
|
13
|
+
const events = config.events ?? config.streams ?? {};
|
|
14
|
+
for (const [eventName, eventDef] of Object.entries(events)) {
|
|
15
|
+
const columns = Object.entries(eventDef.columns).map(([name, type]) => ({
|
|
15
16
|
name,
|
|
16
17
|
tsType: columnTypeToTs(type),
|
|
17
18
|
}));
|
|
18
|
-
|
|
19
|
+
eventTypes.push({ name: eventName, columns });
|
|
19
20
|
}
|
|
20
|
-
//
|
|
21
|
-
const
|
|
21
|
+
// Query types: try config-declared columns first, then RisingWave introspection, then generic
|
|
22
|
+
const queryTypes = [];
|
|
22
23
|
let dbClient = null;
|
|
23
|
-
|
|
24
|
+
const queries = config.queries ?? config.views ?? {};
|
|
25
|
+
for (const [queryName, queryDef] of Object.entries(queries)) {
|
|
24
26
|
// Tier 1: explicit columns in config
|
|
25
|
-
const declaredColumns =
|
|
27
|
+
const declaredColumns = getQueryColumns(queryDef);
|
|
26
28
|
if (declaredColumns) {
|
|
27
|
-
|
|
29
|
+
queryTypes.push({ name: queryName, columns: declaredColumns });
|
|
28
30
|
continue;
|
|
29
31
|
}
|
|
30
32
|
// Tier 2: introspect from RisingWave (if reachable)
|
|
@@ -33,10 +35,10 @@ async function generateClient(config) {
|
|
|
33
35
|
}
|
|
34
36
|
if (dbClient) {
|
|
35
37
|
try {
|
|
36
|
-
const result = await dbClient.query(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`, [
|
|
38
|
+
const result = await dbClient.query(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`, [queryName]);
|
|
37
39
|
if (result.rows.length > 0) {
|
|
38
|
-
|
|
39
|
-
name:
|
|
40
|
+
queryTypes.push({
|
|
41
|
+
name: queryName,
|
|
40
42
|
columns: result.rows.map((row) => ({
|
|
41
43
|
name: row.column_name,
|
|
42
44
|
tsType: pgTypeToTs(row.data_type),
|
|
@@ -50,24 +52,24 @@ async function generateClient(config) {
|
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
// Tier 3: generic fallback
|
|
53
|
-
|
|
55
|
+
queryTypes.push({ name: queryName, columns: [] });
|
|
54
56
|
}
|
|
55
57
|
if (dbClient) {
|
|
56
58
|
await dbClient.end().catch(() => { });
|
|
57
59
|
}
|
|
58
|
-
const code = generateCode(
|
|
60
|
+
const code = generateCode(queryTypes, eventTypes);
|
|
59
61
|
(0, node_fs_1.mkdirSync)('.wavelet', { recursive: true });
|
|
60
62
|
(0, node_fs_1.writeFileSync)('.wavelet/client.ts', code);
|
|
61
63
|
}
|
|
62
|
-
function
|
|
64
|
+
function getQueryColumns(queryDef) {
|
|
63
65
|
// SqlFragment has no columns
|
|
64
|
-
if ('_tag' in
|
|
66
|
+
if ('_tag' in queryDef && queryDef._tag === 'sql')
|
|
65
67
|
return null;
|
|
66
|
-
//
|
|
67
|
-
const
|
|
68
|
-
if (!
|
|
68
|
+
// QueryDef might have explicit columns
|
|
69
|
+
const qd = queryDef;
|
|
70
|
+
if (!qd.columns)
|
|
69
71
|
return null;
|
|
70
|
-
return Object.entries(
|
|
72
|
+
return Object.entries(qd.columns).map(([name, type]) => ({
|
|
71
73
|
name,
|
|
72
74
|
tsType: columnTypeToTs(type),
|
|
73
75
|
}));
|
|
@@ -82,17 +84,17 @@ async function tryConnect(connectionString) {
|
|
|
82
84
|
return null;
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
|
-
function generateCode(
|
|
87
|
+
function generateCode(queries, events) {
|
|
86
88
|
let code = `// Auto-generated by wavelet generate - do not edit\n`;
|
|
87
89
|
code += `// Run 'npx wavelet generate' to regenerate\n\n`;
|
|
88
90
|
code += `import { WaveletClient } from '@risingwave/wavelet-sdk'\n`;
|
|
89
|
-
code += `import type {
|
|
90
|
-
//
|
|
91
|
-
for (const
|
|
92
|
-
const typeName = pascalCase(
|
|
93
|
-
if (
|
|
91
|
+
code += `import type { QueryHandle, EventHandle, Diff, WaveletClientOptions } from '@risingwave/wavelet-sdk'\n\n`;
|
|
92
|
+
// Query row types
|
|
93
|
+
for (const q of queries) {
|
|
94
|
+
const typeName = pascalCase(q.name) + 'Row';
|
|
95
|
+
if (q.columns.length > 0) {
|
|
94
96
|
code += `export interface ${typeName} {\n`;
|
|
95
|
-
for (const col of
|
|
97
|
+
for (const col of q.columns) {
|
|
96
98
|
code += ` ${col.name}: ${col.tsType}\n`;
|
|
97
99
|
}
|
|
98
100
|
code += `}\n\n`;
|
|
@@ -101,11 +103,11 @@ function generateCode(views, streams) {
|
|
|
101
103
|
code += `export type ${typeName} = Record<string, unknown>\n\n`;
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
|
-
//
|
|
105
|
-
for (const
|
|
106
|
-
const typeName = pascalCase(
|
|
106
|
+
// Event types
|
|
107
|
+
for (const ev of events) {
|
|
108
|
+
const typeName = pascalCase(ev.name) + 'Event';
|
|
107
109
|
code += `export interface ${typeName} {\n`;
|
|
108
|
-
for (const col of
|
|
110
|
+
for (const col of ev.columns) {
|
|
109
111
|
code += ` ${col.name}: ${col.tsType}\n`;
|
|
110
112
|
}
|
|
111
113
|
code += `}\n\n`;
|
|
@@ -116,30 +118,30 @@ function generateCode(views, streams) {
|
|
|
116
118
|
code += ` constructor(options: WaveletClientOptions) {\n`;
|
|
117
119
|
code += ` this.client = new WaveletClient(options)\n`;
|
|
118
120
|
code += ` }\n\n`;
|
|
119
|
-
//
|
|
120
|
-
code += `
|
|
121
|
-
for (const
|
|
122
|
-
const typeName = pascalCase(
|
|
123
|
-
code += ` ${
|
|
121
|
+
// Query accessors
|
|
122
|
+
code += ` queries = {\n`;
|
|
123
|
+
for (const q of queries) {
|
|
124
|
+
const typeName = pascalCase(q.name) + 'Row';
|
|
125
|
+
code += ` ${q.name}: this.client.query<${typeName}>('${q.name}'),\n`;
|
|
124
126
|
}
|
|
125
127
|
code += ` }\n\n`;
|
|
126
|
-
//
|
|
127
|
-
code += `
|
|
128
|
-
for (const
|
|
129
|
-
const typeName = pascalCase(
|
|
130
|
-
code += ` ${
|
|
128
|
+
// Event accessors
|
|
129
|
+
code += ` events = {\n`;
|
|
130
|
+
for (const ev of events) {
|
|
131
|
+
const typeName = pascalCase(ev.name) + 'Event';
|
|
132
|
+
code += ` ${ev.name}: this.client.event<${typeName}>('${ev.name}'),\n`;
|
|
131
133
|
}
|
|
132
134
|
code += ` }\n`;
|
|
133
135
|
code += `}\n\n`;
|
|
134
|
-
//
|
|
135
|
-
const
|
|
136
|
-
code += `export type
|
|
136
|
+
// Query name literal type
|
|
137
|
+
const queryNames = queries.map(q => `'${q.name}'`).join(' | ');
|
|
138
|
+
code += `export type QueryName = ${queryNames || 'never'}\n\n`;
|
|
137
139
|
// React hook overloads
|
|
138
140
|
code += `// React hook overloads for type-safe useWavelet\n`;
|
|
139
141
|
code += `import type { UseWaveletResult } from '@risingwave/wavelet-sdk/react'\n\n`;
|
|
140
|
-
for (const
|
|
141
|
-
const typeName = pascalCase(
|
|
142
|
-
code += `export declare function useWavelet(
|
|
142
|
+
for (const q of queries) {
|
|
143
|
+
const typeName = pascalCase(q.name) + 'Row';
|
|
144
|
+
code += `export declare function useWavelet(query: '${q.name}'): UseWaveletResult<${typeName}>\n`;
|
|
143
145
|
}
|
|
144
146
|
return code;
|
|
145
147
|
}
|
package/dist/codegen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":";;;;;AAMA,
|
|
1
|
+
{"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,8 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
Commands:
|
|
12
12
|
dev Start local development server
|
|
13
|
-
generate Generate typed client from
|
|
14
|
-
push Sync
|
|
13
|
+
generate Generate typed client from query definitions
|
|
14
|
+
push Sync query definitions to Wavelet server
|
|
15
15
|
status Show current configuration and connection status
|
|
16
16
|
init Initialize a new Wavelet project
|
|
17
17
|
|
|
@@ -65,9 +65,9 @@ async function runInit() {
|
|
|
65
65
|
export default defineConfig({
|
|
66
66
|
database: process.env.WAVELET_DATABASE_URL ?? 'postgres://root@localhost:4566/dev',
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
// Define your
|
|
70
|
-
//
|
|
68
|
+
events: {
|
|
69
|
+
// Define your events here
|
|
70
|
+
// game_events: {
|
|
71
71
|
// columns: {
|
|
72
72
|
// user_id: 'string',
|
|
73
73
|
// action: 'string',
|
|
@@ -76,11 +76,11 @@ export default defineConfig({
|
|
|
76
76
|
// }
|
|
77
77
|
},
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
// Define your materialized views here
|
|
79
|
+
queries: {
|
|
80
|
+
// Define your queries (materialized views) here
|
|
81
81
|
// leaderboard: sql\`
|
|
82
82
|
// SELECT user_id, SUM(value) as total
|
|
83
|
-
// FROM
|
|
83
|
+
// FROM game_events
|
|
84
84
|
// GROUP BY user_id
|
|
85
85
|
// ORDER BY total DESC
|
|
86
86
|
// LIMIT 100
|
|
@@ -91,7 +91,7 @@ export default defineConfig({
|
|
|
91
91
|
console.log('Created wavelet.config.ts');
|
|
92
92
|
console.log('');
|
|
93
93
|
console.log('Next steps:');
|
|
94
|
-
console.log(' 1. Edit wavelet.config.ts to define your
|
|
94
|
+
console.log(' 1. Edit wavelet.config.ts to define your events and queries');
|
|
95
95
|
console.log(' 2. Run: wavelet dev');
|
|
96
96
|
}
|
|
97
97
|
async function runDev() {
|
|
@@ -106,7 +106,7 @@ async function runDev() {
|
|
|
106
106
|
const { DdlManager, WaveletServer } = await import('@risingwave/wavelet-server');
|
|
107
107
|
const ddl = new DdlManager(config.database);
|
|
108
108
|
await ddl.connect();
|
|
109
|
-
console.log('\nSyncing
|
|
109
|
+
console.log('\nSyncing events and queries...');
|
|
110
110
|
const actions = await ddl.sync(config);
|
|
111
111
|
printDdlActions(actions);
|
|
112
112
|
await ddl.close();
|
|
@@ -157,15 +157,15 @@ async function runStatus() {
|
|
|
157
157
|
const configPath = getConfigPath();
|
|
158
158
|
try {
|
|
159
159
|
const config = await loadConfig(configPath);
|
|
160
|
-
const
|
|
161
|
-
const
|
|
160
|
+
const eventCount = Object.keys(config.events ?? config.streams ?? {}).length;
|
|
161
|
+
const queryCount = Object.keys(config.queries ?? config.views ?? {}).length;
|
|
162
162
|
console.log(`Config: ${configPath}`);
|
|
163
163
|
console.log(`Database: ${config.database.replace(/\/\/[^@]+@/, '//***@')}`);
|
|
164
|
-
console.log(`
|
|
165
|
-
console.log(`
|
|
166
|
-
if (
|
|
167
|
-
console.log('\
|
|
168
|
-
for (const name of Object.keys(config.views ?? {})) {
|
|
164
|
+
console.log(`Events: ${eventCount}`);
|
|
165
|
+
console.log(`Queries: ${queryCount}`);
|
|
166
|
+
if (queryCount > 0) {
|
|
167
|
+
console.log('\nQueries:');
|
|
168
|
+
for (const name of Object.keys(config.queries ?? config.views ?? {})) {
|
|
169
169
|
console.log(` - ${name}`);
|
|
170
170
|
}
|
|
171
171
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAEA,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAE/B,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBZ,CAAA;AAED,KAAK,UAAU,IAAI;IACjB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,MAAM;YACT,MAAM,OAAO,EAAE,CAAA;YACf,MAAK;QACP,KAAK,KAAK;YACR,MAAM,MAAM,EAAE,CAAA;YACd,MAAK;QACP,KAAK,UAAU;YACb,MAAM,WAAW,EAAE,CAAA;YACnB,MAAK;QACP,KAAK,MAAM;YACT,MAAM,OAAO,EAAE,CAAA;YACf,MAAK;QACP,KAAK,QAAQ;YACX,MAAM,SAAS,EAAE,CAAA;YACjB,MAAK;QACP,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI,CAAC;QACV,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;YACjB,MAAK;QACP;YACE,OAAO,CAAC,KAAK,CAAC,qBAAqB,OAAO,GAAG,CAAC,CAAA;YAC9C,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAA;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACnB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,OAAO;IACpB,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAA;IAE7D,IAAI,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAA;QAC1D,OAAM;IACR,CAAC;IAED,aAAa,CAAC,mBAAmB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BpC,CAAC,CAAA;IAEA,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;IACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IACf,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;IAC1B,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@risingwave/wavelet-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Wavelet CLI - manage views, generate types, run dev server",
|
|
5
|
+
"homepage": "https://github.com/risingwavelabs/wavelet",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/risingwavelabs/wavelet.git",
|
|
9
|
+
"directory": "packages/cli"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/risingwavelabs/wavelet/issues"
|
|
13
|
+
},
|
|
5
14
|
"bin": {
|
|
6
|
-
"wavelet": "
|
|
15
|
+
"wavelet": "dist/index.js"
|
|
7
16
|
},
|
|
8
17
|
"scripts": {
|
|
9
18
|
"build": "tsc",
|
|
10
19
|
"dev": "tsx src/index.ts"
|
|
11
20
|
},
|
|
12
21
|
"dependencies": {
|
|
13
|
-
"@risingwave/wavelet": "0.
|
|
14
|
-
"@risingwave/wavelet-server": "0.
|
|
22
|
+
"@risingwave/wavelet": "0.2.4",
|
|
23
|
+
"@risingwave/wavelet-server": "0.2.4",
|
|
15
24
|
"pg": "^8.13.0",
|
|
16
25
|
"tsx": "^4.0.0"
|
|
17
26
|
},
|
package/src/codegen.ts
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
import { writeFileSync, mkdirSync } from 'node:fs'
|
|
2
2
|
import pg from 'pg'
|
|
3
|
-
import type { WaveletConfig, SqlFragment,
|
|
3
|
+
import type { WaveletConfig, SqlFragment, QueryDef, ColumnType } from '@risingwave/wavelet'
|
|
4
4
|
|
|
5
5
|
const { Client } = pg
|
|
6
6
|
|
|
7
7
|
export async function generateClient(config: WaveletConfig): Promise<void> {
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
// Event types are always known from config
|
|
9
|
+
const eventTypes: TypedEntity[] = []
|
|
10
|
+
const events = config.events ?? config.streams ?? {}
|
|
11
|
+
for (const [eventName, eventDef] of Object.entries(events)) {
|
|
12
|
+
const columns = Object.entries(eventDef.columns).map(([name, type]) => ({
|
|
12
13
|
name,
|
|
13
14
|
tsType: columnTypeToTs(type),
|
|
14
15
|
}))
|
|
15
|
-
|
|
16
|
+
eventTypes.push({ name: eventName, columns })
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
//
|
|
19
|
-
const
|
|
19
|
+
// Query types: try config-declared columns first, then RisingWave introspection, then generic
|
|
20
|
+
const queryTypes: TypedEntity[] = []
|
|
20
21
|
let dbClient: InstanceType<typeof Client> | null = null
|
|
22
|
+
const queries = config.queries ?? config.views ?? {}
|
|
21
23
|
|
|
22
|
-
for (const [
|
|
24
|
+
for (const [queryName, queryDef] of Object.entries(queries)) {
|
|
23
25
|
// Tier 1: explicit columns in config
|
|
24
|
-
const declaredColumns =
|
|
26
|
+
const declaredColumns = getQueryColumns(queryDef)
|
|
25
27
|
if (declaredColumns) {
|
|
26
|
-
|
|
28
|
+
queryTypes.push({ name: queryName, columns: declaredColumns })
|
|
27
29
|
continue
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -36,11 +38,11 @@ export async function generateClient(config: WaveletConfig): Promise<void> {
|
|
|
36
38
|
try {
|
|
37
39
|
const result = await dbClient.query(
|
|
38
40
|
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`,
|
|
39
|
-
[
|
|
41
|
+
[queryName]
|
|
40
42
|
)
|
|
41
43
|
if (result.rows.length > 0) {
|
|
42
|
-
|
|
43
|
-
name:
|
|
44
|
+
queryTypes.push({
|
|
45
|
+
name: queryName,
|
|
44
46
|
columns: result.rows.map((row: any) => ({
|
|
45
47
|
name: row.column_name,
|
|
46
48
|
tsType: pgTypeToTs(row.data_type),
|
|
@@ -54,14 +56,14 @@ export async function generateClient(config: WaveletConfig): Promise<void> {
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
// Tier 3: generic fallback
|
|
57
|
-
|
|
59
|
+
queryTypes.push({ name: queryName, columns: [] })
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
if (dbClient) {
|
|
61
63
|
await dbClient.end().catch(() => {})
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
const code = generateCode(
|
|
66
|
+
const code = generateCode(queryTypes, eventTypes)
|
|
65
67
|
|
|
66
68
|
mkdirSync('.wavelet', { recursive: true })
|
|
67
69
|
writeFileSync('.wavelet/client.ts', code)
|
|
@@ -72,15 +74,15 @@ interface TypedEntity {
|
|
|
72
74
|
columns: { name: string; tsType: string }[]
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
function
|
|
77
|
+
function getQueryColumns(queryDef: QueryDef | SqlFragment): { name: string; tsType: string }[] | null {
|
|
76
78
|
// SqlFragment has no columns
|
|
77
|
-
if ('_tag' in
|
|
79
|
+
if ('_tag' in queryDef && queryDef._tag === 'sql') return null
|
|
78
80
|
|
|
79
|
-
//
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
81
|
+
// QueryDef might have explicit columns
|
|
82
|
+
const qd = queryDef as QueryDef
|
|
83
|
+
if (!qd.columns) return null
|
|
82
84
|
|
|
83
|
-
return Object.entries(
|
|
85
|
+
return Object.entries(qd.columns).map(([name, type]) => ({
|
|
84
86
|
name,
|
|
85
87
|
tsType: columnTypeToTs(type),
|
|
86
88
|
}))
|
|
@@ -96,18 +98,18 @@ async function tryConnect(connectionString: string): Promise<InstanceType<typeof
|
|
|
96
98
|
}
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
function generateCode(
|
|
101
|
+
function generateCode(queries: TypedEntity[], events: TypedEntity[]): string {
|
|
100
102
|
let code = `// Auto-generated by wavelet generate - do not edit\n`
|
|
101
103
|
code += `// Run 'npx wavelet generate' to regenerate\n\n`
|
|
102
104
|
code += `import { WaveletClient } from '@risingwave/wavelet-sdk'\n`
|
|
103
|
-
code += `import type {
|
|
105
|
+
code += `import type { QueryHandle, EventHandle, Diff, WaveletClientOptions } from '@risingwave/wavelet-sdk'\n\n`
|
|
104
106
|
|
|
105
|
-
//
|
|
106
|
-
for (const
|
|
107
|
-
const typeName = pascalCase(
|
|
108
|
-
if (
|
|
107
|
+
// Query row types
|
|
108
|
+
for (const q of queries) {
|
|
109
|
+
const typeName = pascalCase(q.name) + 'Row'
|
|
110
|
+
if (q.columns.length > 0) {
|
|
109
111
|
code += `export interface ${typeName} {\n`
|
|
110
|
-
for (const col of
|
|
112
|
+
for (const col of q.columns) {
|
|
111
113
|
code += ` ${col.name}: ${col.tsType}\n`
|
|
112
114
|
}
|
|
113
115
|
code += `}\n\n`
|
|
@@ -116,11 +118,11 @@ function generateCode(views: TypedEntity[], streams: TypedEntity[]): string {
|
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
//
|
|
120
|
-
for (const
|
|
121
|
-
const typeName = pascalCase(
|
|
121
|
+
// Event types
|
|
122
|
+
for (const ev of events) {
|
|
123
|
+
const typeName = pascalCase(ev.name) + 'Event'
|
|
122
124
|
code += `export interface ${typeName} {\n`
|
|
123
|
-
for (const col of
|
|
125
|
+
for (const col of ev.columns) {
|
|
124
126
|
code += ` ${col.name}: ${col.tsType}\n`
|
|
125
127
|
}
|
|
126
128
|
code += `}\n\n`
|
|
@@ -133,33 +135,33 @@ function generateCode(views: TypedEntity[], streams: TypedEntity[]): string {
|
|
|
133
135
|
code += ` this.client = new WaveletClient(options)\n`
|
|
134
136
|
code += ` }\n\n`
|
|
135
137
|
|
|
136
|
-
//
|
|
137
|
-
code += `
|
|
138
|
-
for (const
|
|
139
|
-
const typeName = pascalCase(
|
|
140
|
-
code += ` ${
|
|
138
|
+
// Query accessors
|
|
139
|
+
code += ` queries = {\n`
|
|
140
|
+
for (const q of queries) {
|
|
141
|
+
const typeName = pascalCase(q.name) + 'Row'
|
|
142
|
+
code += ` ${q.name}: this.client.query<${typeName}>('${q.name}'),\n`
|
|
141
143
|
}
|
|
142
144
|
code += ` }\n\n`
|
|
143
145
|
|
|
144
|
-
//
|
|
145
|
-
code += `
|
|
146
|
-
for (const
|
|
147
|
-
const typeName = pascalCase(
|
|
148
|
-
code += ` ${
|
|
146
|
+
// Event accessors
|
|
147
|
+
code += ` events = {\n`
|
|
148
|
+
for (const ev of events) {
|
|
149
|
+
const typeName = pascalCase(ev.name) + 'Event'
|
|
150
|
+
code += ` ${ev.name}: this.client.event<${typeName}>('${ev.name}'),\n`
|
|
149
151
|
}
|
|
150
152
|
code += ` }\n`
|
|
151
153
|
code += `}\n\n`
|
|
152
154
|
|
|
153
|
-
//
|
|
154
|
-
const
|
|
155
|
-
code += `export type
|
|
155
|
+
// Query name literal type
|
|
156
|
+
const queryNames = queries.map(q => `'${q.name}'`).join(' | ')
|
|
157
|
+
code += `export type QueryName = ${queryNames || 'never'}\n\n`
|
|
156
158
|
|
|
157
159
|
// React hook overloads
|
|
158
160
|
code += `// React hook overloads for type-safe useWavelet\n`
|
|
159
161
|
code += `import type { UseWaveletResult } from '@risingwave/wavelet-sdk/react'\n\n`
|
|
160
|
-
for (const
|
|
161
|
-
const typeName = pascalCase(
|
|
162
|
-
code += `export declare function useWavelet(
|
|
162
|
+
for (const q of queries) {
|
|
163
|
+
const typeName = pascalCase(q.name) + 'Row'
|
|
164
|
+
code += `export declare function useWavelet(query: '${q.name}'): UseWaveletResult<${typeName}>\n`
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
return code
|
package/src/index.ts
CHANGED
|
@@ -10,8 +10,8 @@ Usage:
|
|
|
10
10
|
|
|
11
11
|
Commands:
|
|
12
12
|
dev Start local development server
|
|
13
|
-
generate Generate typed client from
|
|
14
|
-
push Sync
|
|
13
|
+
generate Generate typed client from query definitions
|
|
14
|
+
push Sync query definitions to Wavelet server
|
|
15
15
|
status Show current configuration and connection status
|
|
16
16
|
init Initialize a new Wavelet project
|
|
17
17
|
|
|
@@ -69,9 +69,9 @@ async function runInit() {
|
|
|
69
69
|
export default defineConfig({
|
|
70
70
|
database: process.env.WAVELET_DATABASE_URL ?? 'postgres://root@localhost:4566/dev',
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
// Define your
|
|
74
|
-
//
|
|
72
|
+
events: {
|
|
73
|
+
// Define your events here
|
|
74
|
+
// game_events: {
|
|
75
75
|
// columns: {
|
|
76
76
|
// user_id: 'string',
|
|
77
77
|
// action: 'string',
|
|
@@ -80,11 +80,11 @@ export default defineConfig({
|
|
|
80
80
|
// }
|
|
81
81
|
},
|
|
82
82
|
|
|
83
|
-
|
|
84
|
-
// Define your materialized views here
|
|
83
|
+
queries: {
|
|
84
|
+
// Define your queries (materialized views) here
|
|
85
85
|
// leaderboard: sql\`
|
|
86
86
|
// SELECT user_id, SUM(value) as total
|
|
87
|
-
// FROM
|
|
87
|
+
// FROM game_events
|
|
88
88
|
// GROUP BY user_id
|
|
89
89
|
// ORDER BY total DESC
|
|
90
90
|
// LIMIT 100
|
|
@@ -96,7 +96,7 @@ export default defineConfig({
|
|
|
96
96
|
console.log('Created wavelet.config.ts')
|
|
97
97
|
console.log('')
|
|
98
98
|
console.log('Next steps:')
|
|
99
|
-
console.log(' 1. Edit wavelet.config.ts to define your
|
|
99
|
+
console.log(' 1. Edit wavelet.config.ts to define your events and queries')
|
|
100
100
|
console.log(' 2. Run: wavelet dev')
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -116,7 +116,7 @@ async function runDev() {
|
|
|
116
116
|
const ddl = new DdlManager(config.database)
|
|
117
117
|
await ddl.connect()
|
|
118
118
|
|
|
119
|
-
console.log('\nSyncing
|
|
119
|
+
console.log('\nSyncing events and queries...')
|
|
120
120
|
const actions = await ddl.sync(config)
|
|
121
121
|
printDdlActions(actions)
|
|
122
122
|
await ddl.close()
|
|
@@ -178,17 +178,17 @@ async function runStatus() {
|
|
|
178
178
|
|
|
179
179
|
try {
|
|
180
180
|
const config = await loadConfig(configPath)
|
|
181
|
-
const
|
|
182
|
-
const
|
|
181
|
+
const eventCount = Object.keys(config.events ?? config.streams ?? {}).length
|
|
182
|
+
const queryCount = Object.keys(config.queries ?? config.views ?? {}).length
|
|
183
183
|
|
|
184
184
|
console.log(`Config: ${configPath}`)
|
|
185
185
|
console.log(`Database: ${config.database.replace(/\/\/[^@]+@/, '//***@')}`)
|
|
186
|
-
console.log(`
|
|
187
|
-
console.log(`
|
|
186
|
+
console.log(`Events: ${eventCount}`)
|
|
187
|
+
console.log(`Queries: ${queryCount}`)
|
|
188
188
|
|
|
189
|
-
if (
|
|
190
|
-
console.log('\
|
|
191
|
-
for (const name of Object.keys(config.views ?? {})) {
|
|
189
|
+
if (queryCount > 0) {
|
|
190
|
+
console.log('\nQueries:')
|
|
191
|
+
for (const name of Object.keys(config.queries ?? config.views ?? {})) {
|
|
192
192
|
console.log(` - ${name}`)
|
|
193
193
|
}
|
|
194
194
|
}
|