Skip to content

Commit bf3f817

Browse files
committed
Prototype Snowflake proxy
Piggyback off the Postgres type for now.
1 parent 3894531 commit bf3f817

File tree

4 files changed

+770
-6
lines changed

4 files changed

+770
-6
lines changed

lib/server.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import serializeErrors from "./serialize-errors";
1010
import {notFound, unauthorized, exit} from "./errors";
1111
import mysql from "./mysql";
1212
import postgres from "./postgres";
13+
import snowflake from "./snowflake";
1314

1415
export function server(config, argv) {
1516
const development = process.env.NODE_ENV === "development";
@@ -25,7 +26,7 @@ export function server(config, argv) {
2526
} = config;
2627

2728
const handler =
28-
type === "mysql" ? mysql(url) : type === "postgres" ? postgres(url) : null;
29+
type === "mysql" ? mysql(url) : type === "postgres" ? snowflake(url) : null;
2930
if (!handler) {
3031
return exit(`Unknown database type: ${type}`);
3132
}

lib/snowflake.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {json} from "micro";
2+
import {URL} from "url";
3+
import JSONStream from "JSONStream";
4+
import snowflake from "snowflake-sdk";
5+
6+
export default url => {
7+
url = new URL(url);
8+
console.log(url);
9+
const {host: account, username, password, pathname, searchParams} = new URL(
10+
url
11+
);
12+
const connection = snowflake.createConnection({
13+
account,
14+
username,
15+
password,
16+
database: pathname.slice(1),
17+
schema: searchParams.get("schema"),
18+
warehouse: searchParams.get("warehouse"),
19+
role: searchParams.get("role")
20+
});
21+
22+
return async function query(req, res) {
23+
const body = await json(req);
24+
const {sql, params} = body;
25+
26+
const client = await new Promise((resolve, reject) => {
27+
if (connection.isUp()) return resolve(connection);
28+
snowflake.configure({ocspFailOpen: false});
29+
connection.connect((err, conn) => {
30+
if (err) reject(err);
31+
else resolve(conn);
32+
});
33+
});
34+
35+
const statement = client.execute({sqlText: sql, binds: params});
36+
try {
37+
const stream = statement.streamRows();
38+
39+
await new Promise((resolve, reject) => {
40+
stream
41+
.once("end", resolve)
42+
.on("error", reject)
43+
.pipe(JSONStream.stringify(`{"data":[`, ",", "]"))
44+
.pipe(res, {end: false});
45+
});
46+
} catch (error) {
47+
if (!error.statusCode) error.statusCode = 400;
48+
throw error;
49+
}
50+
51+
const schema = {
52+
type: "array",
53+
items: {
54+
type: "object",
55+
properties: statement
56+
.getColumns()
57+
.reduce(
58+
(schema, column) => (
59+
(schema[column.getName()] = dataTypeSchema(column)), schema
60+
),
61+
{}
62+
)
63+
}
64+
};
65+
res.end(`,"schema":${JSON.stringify(schema)}}`);
66+
};
67+
};
68+
69+
// https://www.postgresql.org/docs/9.6/datatype.html
70+
const array = ["null", "array"],
71+
boolean = ["null", "boolean"],
72+
// integer = ["null", "integer"],
73+
number = ["null", "number"],
74+
object = ["null", "object"],
75+
string = ["null", "string"];
76+
function dataTypeSchema(column) {
77+
// https://github.com/snowflakedb/snowflake-connector-nodejs/blob/master/lib/connection/result/data_types.js
78+
switch (column.getType()) {
79+
case "binary":
80+
return {type: object, buffer: true};
81+
case "boolean":
82+
return {type: boolean};
83+
case "fixed":
84+
case "real":
85+
return {type: number};
86+
case "date":
87+
case "time":
88+
case "timestamp_ltz":
89+
case "timestamp_ntz":
90+
case "timestamp_tz":
91+
return {type: string, date: true};
92+
case "variant":
93+
case "object":
94+
return {type: object};
95+
case "array":
96+
return {type: array, items: {type: object}};
97+
case "text":
98+
default:
99+
return {type: string};
100+
}
101+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"pg": "^7.11.0",
1515
"pg-query-stream": "^2.0.0",
1616
"serialize-error": "^4.1.0",
17+
"snowflake-sdk": "^1.5.0",
1718
"yargs": "^13.2.4"
1819
},
1920
"devDependencies": {

0 commit comments

Comments
 (0)