@skalfa/skalfa-da 1.0.0

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/bun.lock ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "workspaces": {
4
+ "": {
5
+ "name": "@skalfa/skalfa-da",
6
+ "dependencies": {
7
+ "@clickhouse/client": "^1.6.0",
8
+ },
9
+ "devDependencies": {
10
+ "@types/node": "^26.0.0",
11
+ "typescript": "^6.0.3",
12
+ },
13
+ },
14
+ },
15
+ "packages": {
16
+ "@clickhouse/client": ["@clickhouse/client@1.22.0", "", { "dependencies": { "@clickhouse/client-common": "1.22.0" } }, "sha512-iQAAM4VT9fO7mYVOkGB/Ul9Xxuf0atKn+GFceZqfE8xFakV8KOAQxR3tfNrXFMlJ8T+Q3gbrpfLFyj7/TbOwyA=="],
17
+
18
+ "@clickhouse/client-common": ["@clickhouse/client-common@1.22.0", "", {}, "sha512-MQgXRhoYXut6GhRrTJlub42bnPX7+5Vm+5gHNR0zZXU5+EwZKsBgMXiWXPOerAmQd3weGKm8hzoeZJCfU3Cw2w=="],
19
+
20
+ "@types/node": ["@types/node@26.0.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-vf2YFi1iY9lHGwNJMs01biZFbKJkrZR1T6/MlzjhJLPdntOHLhTrDSnSVcdtvjihi4VQNlrFRIxLsDBlQpAipA=="],
21
+
22
+ "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="],
23
+
24
+ "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="],
25
+ }
26
+ }
@@ -0,0 +1,26 @@
1
+ export declare const daClient: import("@clickhouse/client").ClickHouseClient;
2
+ type WhereValue = string | number | boolean | null;
3
+ declare class QueryBuilder {
4
+ private selectCols;
5
+ private fromTable;
6
+ private whereClauses;
7
+ private orderClauses;
8
+ private limitValue?;
9
+ private offsetValue?;
10
+ select(...cols: string[]): this;
11
+ from(table: string): this;
12
+ where(col: string, op: string, value: WhereValue): this;
13
+ orderBy(col: string, dir?: "asc" | "desc"): this;
14
+ limit(n: number): this;
15
+ offset(n: number): this;
16
+ toSQL(): string;
17
+ get<T = any>(): Promise<T[]>;
18
+ first<T = any>(): Promise<NonNullable<T> | null>;
19
+ }
20
+ export declare const da: {
21
+ select(...cols: string[]): QueryBuilder;
22
+ from(table: string): QueryBuilder;
23
+ insert<T extends Record<string, any>>(table: string, rows: T | T[]): Promise<import("@clickhouse/client").InsertResult>;
24
+ exec(sql: string): Promise<import("@clickhouse/client").CommandResult>;
25
+ };
26
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,101 @@
1
+ import { createClient } from '@clickhouse/client';
2
+ // ==============================>
3
+ // ## DA / OLAP : ClickHouse Init
4
+ // ==============================>
5
+ export const daClient = createClient({
6
+ url: "http://" + (process.env.DA_HOST || '127.0.0.1') + ':' + (process.env.DA_PORT || '8123'),
7
+ username: process.env.DA_USERNAME || 'default',
8
+ password: process.env.DA_PASSWORD || '',
9
+ database: process.env.DA_DATABASE || 'default',
10
+ });
11
+ class QueryBuilder {
12
+ constructor() {
13
+ this.selectCols = ["*"];
14
+ this.fromTable = "";
15
+ this.whereClauses = [];
16
+ this.orderClauses = [];
17
+ }
18
+ select(...cols) {
19
+ if (cols.length)
20
+ this.selectCols = cols;
21
+ return this;
22
+ }
23
+ from(table) {
24
+ this.fromTable = table;
25
+ return this;
26
+ }
27
+ where(col, op, value) {
28
+ const v = value === null ? "NULL" : typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value;
29
+ this.whereClauses.push(`${col} ${op} ${v}`);
30
+ return this;
31
+ }
32
+ orderBy(col, dir = "asc") {
33
+ this.orderClauses.push(`${col} ${dir.toUpperCase()}`);
34
+ return this;
35
+ }
36
+ limit(n) {
37
+ this.limitValue = n;
38
+ return this;
39
+ }
40
+ offset(n) {
41
+ this.offsetValue = n;
42
+ return this;
43
+ }
44
+ toSQL() {
45
+ if (!this.fromTable)
46
+ throw new Error("FROM table is required");
47
+ let sql = `SELECT ${this.selectCols.join(", ")} FROM ${this.fromTable}`;
48
+ if (this.whereClauses.length)
49
+ sql += ` WHERE ${this.whereClauses.join(" AND ")}`;
50
+ if (this.orderClauses.length)
51
+ sql += ` ORDER BY ${this.orderClauses.join(", ")}`;
52
+ if (this.limitValue !== undefined)
53
+ sql += ` LIMIT ${this.limitValue}`;
54
+ if (this.offsetValue !== undefined)
55
+ sql += ` OFFSET ${this.offsetValue}`;
56
+ return sql;
57
+ }
58
+ async get() {
59
+ const rs = await daClient.query({
60
+ query: this.toSQL(),
61
+ format: "JSONEachRow",
62
+ });
63
+ const text = await rs.text();
64
+ if (!text.trim())
65
+ return [];
66
+ return text.trim().split("\n").map(line => JSON.parse(line));
67
+ }
68
+ async first() {
69
+ const rows = await this.limit(1).get();
70
+ return rows[0] ?? null;
71
+ }
72
+ }
73
+ export const da = {
74
+ // =========================
75
+ // ## Select
76
+ // =========================
77
+ select(...cols) {
78
+ return new QueryBuilder().select(...cols);
79
+ },
80
+ from(table) {
81
+ return new QueryBuilder().from(table);
82
+ },
83
+ // =========================
84
+ // ## Insert
85
+ // =========================
86
+ insert(table, rows) {
87
+ const data = Array.isArray(rows) ? rows : [rows];
88
+ return daClient.insert({
89
+ table,
90
+ values: data,
91
+ format: "JSONEachRow",
92
+ });
93
+ },
94
+ // =========================
95
+ // ## Exec query raw
96
+ // =========================
97
+ exec(sql) {
98
+ return daClient.command({ query: sql });
99
+ },
100
+ };
101
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@skalfa/skalfa-da",
3
+ "version": "1.0.0",
4
+ "description": "Data Analytics / ClickHouse utility package for Skalfa API framework.",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc --ignoreDeprecations 6.0"
9
+ },
10
+ "keywords": [
11
+ "aluna",
12
+ "clickhouse",
13
+ "da",
14
+ "skalfa"
15
+ ],
16
+ "author": "",
17
+ "license": "UNLICENSED",
18
+ "dependencies": {
19
+ "@clickhouse/client": "^1.6.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^26.0.0",
23
+ "typescript": "^6.0.3"
24
+ }
25
+ }
package/src/index.ts ADDED
@@ -0,0 +1,123 @@
1
+ import { createClient } from '@clickhouse/client'
2
+
3
+ // ==============================>
4
+ // ## DA / OLAP : ClickHouse Init
5
+ // ==============================>
6
+ export const daClient = createClient({
7
+ url : "http://" + (process.env.DA_HOST || '127.0.0.1') + ':' + (process.env.DA_PORT || '8123'),
8
+ username : process.env.DA_USERNAME || 'default',
9
+ password : process.env.DA_PASSWORD || '',
10
+ database : process.env.DA_DATABASE || 'default',
11
+ })
12
+
13
+
14
+ // ==============================>
15
+ // ## DA / OLAP : Query Builder
16
+ // ==============================>
17
+ type WhereValue = string | number | boolean | null
18
+
19
+ class QueryBuilder {
20
+ private selectCols: string[] = ["*"]
21
+ private fromTable = ""
22
+ private whereClauses: string[] = []
23
+ private orderClauses: string[] = []
24
+ private limitValue?: number
25
+ private offsetValue?: number
26
+
27
+ select(...cols: string[]) {
28
+ if (cols.length) this.selectCols = cols
29
+ return this
30
+ }
31
+
32
+ from(table: string) {
33
+ this.fromTable = table
34
+ return this
35
+ }
36
+
37
+ where(col: string, op: string, value: WhereValue) {
38
+ const v = value === null ? "NULL" : typeof value === "string" ? `'${value.replace(/'/g, "''")}'` : value
39
+
40
+ this.whereClauses.push(`${col} ${op} ${v}`)
41
+ return this
42
+ }
43
+
44
+ orderBy(col: string, dir: "asc" | "desc" = "asc") {
45
+ this.orderClauses.push(`${col} ${dir.toUpperCase()}`)
46
+ return this
47
+ }
48
+
49
+ limit(n: number) {
50
+ this.limitValue = n
51
+ return this
52
+ }
53
+
54
+ offset(n: number) {
55
+ this.offsetValue = n
56
+ return this
57
+ }
58
+
59
+ toSQL() {
60
+ if (!this.fromTable) throw new Error("FROM table is required")
61
+
62
+ let sql = `SELECT ${this.selectCols.join(", ")} FROM ${this.fromTable}`
63
+
64
+ if (this.whereClauses.length) sql += ` WHERE ${this.whereClauses.join(" AND ")}`
65
+ if (this.orderClauses.length) sql += ` ORDER BY ${this.orderClauses.join(", ")}`
66
+ if (this.limitValue !== undefined) sql += ` LIMIT ${this.limitValue}`
67
+ if (this.offsetValue !== undefined) sql += ` OFFSET ${this.offsetValue}`
68
+
69
+ return sql
70
+ }
71
+
72
+ async get<T = any>() {
73
+ const rs = await daClient.query({
74
+ query: this.toSQL(),
75
+ format: "JSONEachRow",
76
+ })
77
+
78
+ const text = await rs.text()
79
+ if (!text.trim()) return []
80
+
81
+ return text.trim().split("\n").map(line => JSON.parse(line)) as T[]
82
+ }
83
+
84
+ async first<T = any>() {
85
+ const rows = await this.limit(1).get<T>()
86
+ return rows[0] ?? null
87
+ }
88
+ }
89
+
90
+ export const da = {
91
+ // =========================
92
+ // ## Select
93
+ // =========================
94
+ select(...cols: string[]) {
95
+ return new QueryBuilder().select(...cols)
96
+ },
97
+
98
+ from(table: string) {
99
+ return new QueryBuilder().from(table)
100
+ },
101
+
102
+
103
+ // =========================
104
+ // ## Insert
105
+ // =========================
106
+ insert<T extends Record<string, any>>(table: string, rows: T | T[]) {
107
+ const data = Array.isArray(rows) ? rows : [rows]
108
+
109
+ return daClient.insert({
110
+ table,
111
+ values: data,
112
+ format: "JSONEachRow",
113
+ })
114
+ },
115
+
116
+
117
+ // =========================
118
+ // ## Exec query raw
119
+ // =========================
120
+ exec(sql: string) {
121
+ return daClient.command({ query: sql })
122
+ },
123
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "ignoreDeprecations": "5.0",
4
+ "target": "ES2021",
5
+ "module": "ES2022",
6
+ "moduleResolution": "node",
7
+ "declaration": true,
8
+ "sourceMap": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "./src",
11
+ "strict": true,
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "forceConsistentCasingInFileNames": true,
15
+ "baseUrl": ".",
16
+ "types": ["node"]
17
+ },
18
+ "include": ["src/**/*"]
19
+ }