@risingwave/wavelet-cli 0.1.3 → 0.1.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 +62 -19
- package/dist/codegen.js.map +1 -1
- package/package.json +3 -3
- package/src/codegen.ts +78 -33
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,EAAoC,MAAM,qBAAqB,CAAA;AAI1F,wBAAsB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DzE"}
|
package/dist/codegen.js
CHANGED
|
@@ -8,24 +8,7 @@ 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
|
-
await client.connect();
|
|
13
|
-
const viewTypes = [];
|
|
14
|
-
for (const viewName of Object.keys(config.views ?? {})) {
|
|
15
|
-
try {
|
|
16
|
-
// Query column info from RisingWave
|
|
17
|
-
const result = await client.query(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`, [viewName]);
|
|
18
|
-
const columns = result.rows.map((row) => ({
|
|
19
|
-
name: row.column_name,
|
|
20
|
-
tsType: pgTypeToTs(row.data_type),
|
|
21
|
-
}));
|
|
22
|
-
viewTypes.push({ name: viewName, columns });
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// If we can't query schema, generate generic types
|
|
26
|
-
viewTypes.push({ name: viewName, columns: [] });
|
|
27
|
-
}
|
|
28
|
-
}
|
|
11
|
+
// Stream types are always known from config
|
|
29
12
|
const streamTypes = [];
|
|
30
13
|
for (const [streamName, streamDef] of Object.entries(config.streams ?? {})) {
|
|
31
14
|
const columns = Object.entries(streamDef.columns).map(([name, type]) => ({
|
|
@@ -34,11 +17,71 @@ async function generateClient(config) {
|
|
|
34
17
|
}));
|
|
35
18
|
streamTypes.push({ name: streamName, columns });
|
|
36
19
|
}
|
|
37
|
-
|
|
20
|
+
// View types: try config-declared columns first, then RisingWave introspection, then generic
|
|
21
|
+
const viewTypes = [];
|
|
22
|
+
let dbClient = null;
|
|
23
|
+
for (const [viewName, viewDef] of Object.entries(config.views ?? {})) {
|
|
24
|
+
// Tier 1: explicit columns in config
|
|
25
|
+
const declaredColumns = getViewColumns(viewDef);
|
|
26
|
+
if (declaredColumns) {
|
|
27
|
+
viewTypes.push({ name: viewName, columns: declaredColumns });
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
// Tier 2: introspect from RisingWave (if reachable)
|
|
31
|
+
if (!dbClient) {
|
|
32
|
+
dbClient = await tryConnect(config.database);
|
|
33
|
+
}
|
|
34
|
+
if (dbClient) {
|
|
35
|
+
try {
|
|
36
|
+
const result = await dbClient.query(`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`, [viewName]);
|
|
37
|
+
if (result.rows.length > 0) {
|
|
38
|
+
viewTypes.push({
|
|
39
|
+
name: viewName,
|
|
40
|
+
columns: result.rows.map((row) => ({
|
|
41
|
+
name: row.column_name,
|
|
42
|
+
tsType: pgTypeToTs(row.data_type),
|
|
43
|
+
})),
|
|
44
|
+
});
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Fall through to tier 3
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Tier 3: generic fallback
|
|
53
|
+
viewTypes.push({ name: viewName, columns: [] });
|
|
54
|
+
}
|
|
55
|
+
if (dbClient) {
|
|
56
|
+
await dbClient.end().catch(() => { });
|
|
57
|
+
}
|
|
38
58
|
const code = generateCode(viewTypes, streamTypes);
|
|
39
59
|
(0, node_fs_1.mkdirSync)('.wavelet', { recursive: true });
|
|
40
60
|
(0, node_fs_1.writeFileSync)('.wavelet/client.ts', code);
|
|
41
61
|
}
|
|
62
|
+
function getViewColumns(viewDef) {
|
|
63
|
+
// SqlFragment has no columns
|
|
64
|
+
if ('_tag' in viewDef && viewDef._tag === 'sql')
|
|
65
|
+
return null;
|
|
66
|
+
// ViewDef might have explicit columns
|
|
67
|
+
const vd = viewDef;
|
|
68
|
+
if (!vd.columns)
|
|
69
|
+
return null;
|
|
70
|
+
return Object.entries(vd.columns).map(([name, type]) => ({
|
|
71
|
+
name,
|
|
72
|
+
tsType: columnTypeToTs(type),
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
async function tryConnect(connectionString) {
|
|
76
|
+
const client = new Client({ connectionString, connectionTimeoutMillis: 3000 });
|
|
77
|
+
try {
|
|
78
|
+
await client.connect();
|
|
79
|
+
return client;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
42
85
|
function generateCode(views, streams) {
|
|
43
86
|
let code = `// Auto-generated by wavelet generate - do not edit\n`;
|
|
44
87
|
code += `// Run 'npx wavelet generate' to regenerate\n\n`;
|
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@risingwave/wavelet-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Wavelet CLI - manage views, generate types, run dev server",
|
|
5
5
|
"bin": {
|
|
6
6
|
"wavelet": "./dist/index.js"
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"dev": "tsx src/index.ts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@risingwave/wavelet": "0.1.
|
|
14
|
-
"@risingwave/wavelet-server": "0.1.
|
|
13
|
+
"@risingwave/wavelet": "0.1.4",
|
|
14
|
+
"@risingwave/wavelet-server": "0.1.4",
|
|
15
15
|
"pg": "^8.13.0",
|
|
16
16
|
"tsx": "^4.0.0"
|
|
17
17
|
},
|
package/src/codegen.ts
CHANGED
|
@@ -1,37 +1,12 @@
|
|
|
1
1
|
import { writeFileSync, mkdirSync } from 'node:fs'
|
|
2
2
|
import pg from 'pg'
|
|
3
|
-
import type { WaveletConfig, SqlFragment, ViewDef } from '@risingwave/wavelet'
|
|
3
|
+
import type { WaveletConfig, SqlFragment, ViewDef, 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
|
-
|
|
10
|
-
|
|
11
|
-
const viewTypes: { name: string; columns: { name: string; tsType: string }[] }[] = []
|
|
12
|
-
|
|
13
|
-
for (const viewName of Object.keys(config.views ?? {})) {
|
|
14
|
-
try {
|
|
15
|
-
// Query column info from RisingWave
|
|
16
|
-
const result = await client.query(
|
|
17
|
-
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`,
|
|
18
|
-
[viewName]
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
const columns = result.rows.map((row: any) => ({
|
|
22
|
-
name: row.column_name,
|
|
23
|
-
tsType: pgTypeToTs(row.data_type),
|
|
24
|
-
}))
|
|
25
|
-
|
|
26
|
-
viewTypes.push({ name: viewName, columns })
|
|
27
|
-
} catch {
|
|
28
|
-
// If we can't query schema, generate generic types
|
|
29
|
-
viewTypes.push({ name: viewName, columns: [] })
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const streamTypes: { name: string; columns: { name: string; tsType: string }[] }[] = []
|
|
34
|
-
|
|
8
|
+
// Stream types are always known from config
|
|
9
|
+
const streamTypes: TypedEntity[] = []
|
|
35
10
|
for (const [streamName, streamDef] of Object.entries(config.streams ?? {})) {
|
|
36
11
|
const columns = Object.entries(streamDef.columns).map(([name, type]) => ({
|
|
37
12
|
name,
|
|
@@ -40,7 +15,51 @@ export async function generateClient(config: WaveletConfig): Promise<void> {
|
|
|
40
15
|
streamTypes.push({ name: streamName, columns })
|
|
41
16
|
}
|
|
42
17
|
|
|
43
|
-
|
|
18
|
+
// View types: try config-declared columns first, then RisingWave introspection, then generic
|
|
19
|
+
const viewTypes: TypedEntity[] = []
|
|
20
|
+
let dbClient: InstanceType<typeof Client> | null = null
|
|
21
|
+
|
|
22
|
+
for (const [viewName, viewDef] of Object.entries(config.views ?? {})) {
|
|
23
|
+
// Tier 1: explicit columns in config
|
|
24
|
+
const declaredColumns = getViewColumns(viewDef)
|
|
25
|
+
if (declaredColumns) {
|
|
26
|
+
viewTypes.push({ name: viewName, columns: declaredColumns })
|
|
27
|
+
continue
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Tier 2: introspect from RisingWave (if reachable)
|
|
31
|
+
if (!dbClient) {
|
|
32
|
+
dbClient = await tryConnect(config.database)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (dbClient) {
|
|
36
|
+
try {
|
|
37
|
+
const result = await dbClient.query(
|
|
38
|
+
`SELECT column_name, data_type FROM information_schema.columns WHERE table_name = $1 ORDER BY ordinal_position`,
|
|
39
|
+
[viewName]
|
|
40
|
+
)
|
|
41
|
+
if (result.rows.length > 0) {
|
|
42
|
+
viewTypes.push({
|
|
43
|
+
name: viewName,
|
|
44
|
+
columns: result.rows.map((row: any) => ({
|
|
45
|
+
name: row.column_name,
|
|
46
|
+
tsType: pgTypeToTs(row.data_type),
|
|
47
|
+
})),
|
|
48
|
+
})
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// Fall through to tier 3
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Tier 3: generic fallback
|
|
57
|
+
viewTypes.push({ name: viewName, columns: [] })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (dbClient) {
|
|
61
|
+
await dbClient.end().catch(() => {})
|
|
62
|
+
}
|
|
44
63
|
|
|
45
64
|
const code = generateCode(viewTypes, streamTypes)
|
|
46
65
|
|
|
@@ -48,10 +67,36 @@ export async function generateClient(config: WaveletConfig): Promise<void> {
|
|
|
48
67
|
writeFileSync('.wavelet/client.ts', code)
|
|
49
68
|
}
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
70
|
+
interface TypedEntity {
|
|
71
|
+
name: string
|
|
72
|
+
columns: { name: string; tsType: string }[]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getViewColumns(viewDef: ViewDef | SqlFragment): { name: string; tsType: string }[] | null {
|
|
76
|
+
// SqlFragment has no columns
|
|
77
|
+
if ('_tag' in viewDef && viewDef._tag === 'sql') return null
|
|
78
|
+
|
|
79
|
+
// ViewDef might have explicit columns
|
|
80
|
+
const vd = viewDef as ViewDef
|
|
81
|
+
if (!vd.columns) return null
|
|
82
|
+
|
|
83
|
+
return Object.entries(vd.columns).map(([name, type]) => ({
|
|
84
|
+
name,
|
|
85
|
+
tsType: columnTypeToTs(type),
|
|
86
|
+
}))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function tryConnect(connectionString: string): Promise<InstanceType<typeof Client> | null> {
|
|
90
|
+
const client = new Client({ connectionString, connectionTimeoutMillis: 3000 })
|
|
91
|
+
try {
|
|
92
|
+
await client.connect()
|
|
93
|
+
return client
|
|
94
|
+
} catch {
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function generateCode(views: TypedEntity[], streams: TypedEntity[]): string {
|
|
55
100
|
let code = `// Auto-generated by wavelet generate - do not edit\n`
|
|
56
101
|
code += `// Run 'npx wavelet generate' to regenerate\n\n`
|
|
57
102
|
code += `import { WaveletClient } from '@risingwave/wavelet-sdk'\n`
|