• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vzakharchenko / forge-sql-orm / 18184255909

02 Oct 2025 05:26AM UTC coverage: 83.921% (-2.7%) from 86.669%
18184255909

Pull #738

github

web-flow
Merge a7f4cb4a1 into 62498cd35
Pull Request #738: added support ddl operations

499 of 623 branches covered (80.1%)

Branch coverage included in aggregate %.

157 of 257 new or added lines in 7 files covered. (61.09%)

46 existing lines in 3 files now uncovered.

2549 of 3009 relevant lines covered (84.71%)

13.21 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.47
/src/utils/forgeDriver.ts
1
import { sql, UpdateQueryResponse } from "@forge/sql";
1✔
2
import { saveMetaDataInContextContext } from "./metadataContextUtils";
1✔
3
import { getOperationType } from "./requestTypeContextUtils";
1✔
4

5
/**
6
 * Metadata structure for Forge SQL query results.
7
 * Contains execution timing, response size, and field information.
8
 */
9
export type ForgeSQLMetadata = {
10
  dbExecutionTime: number;
11
  responseSize: number;
12
  fields: {
13
    catalog: string;
14
    name: string;
15
    schema: string;
16
    characterSet: number;
17
    decimals: number;
18
    table: string;
19
    orgTable: string;
20
    orgName: string;
21
    flags: number;
22
    columnType: number;
23
    columnLength: number;
24
  }[];
25
};
26

27
/**
28
 * Result structure for Forge SQL queries.
29
 * Contains rows data and execution metadata.
30
 */
31
export interface ForgeSQLResult {
32
  rows: Record<string, unknown>[] | Record<string, unknown>;
33
  metadata: ForgeSQLMetadata;
34
}
35

36
/**
37
 * Driver result structure for Drizzle ORM compatibility.
38
 */
39
export interface ForgeDriverResult {
40
  rows: unknown[];
41
  insertId?: number;
42
  affectedRows?: number;
43
}
44

45
/**
46
 * Query execution method types.
47
 */
48
export type QueryMethod = "all" | "execute";
49

50
/**
51
 * Type guard to check if an object is an UpdateQueryResponse.
52
 *
53
 * @param obj - The object to check
54
 * @returns True if the object is an UpdateQueryResponse
55
 */
56
export function isUpdateQueryResponse(obj: unknown): obj is UpdateQueryResponse {
1✔
57
  return (
44✔
58
    obj !== null &&
44✔
59
    typeof obj === "object" &&
44✔
60
    typeof (obj as any).affectedRows === "number" &&
44✔
61
    typeof (obj as any).insertId === "number"
37✔
62
  );
63
}
44✔
64

65
function inlineParams(sql: string, params: unknown[]): string {
2✔
66
  let i = 0;
2✔
67
  return sql.replace(/\?/g, () => {
2✔
NEW
68
    const val = params[i++];
×
NEW
69
    if (val === null) return "NULL";
×
NEW
70
    if (typeof val === "number") return val.toString();
×
NEW
71
    return `'${String(val).replace(/'/g, "''")}'`;
×
72
  });
2✔
73
}
2✔
74

75
/**
76
 * Processes DDL query results and saves metadata.
77
 *
78
 * @param result - The DDL query result
79
 * @returns Processed result for Drizzle ORM
80
 */
81
async function processDDLResult(method: QueryMethod, result: any): Promise<ForgeDriverResult> {
2✔
82
  if (result.metadata) {
2✔
83
    await saveMetaDataInContextContext(result.metadata as ForgeSQLMetadata);
2✔
84
  }
2✔
85

86
  if (!result.rows) {
2!
NEW
87
    return { rows: [] };
×
NEW
88
  }
×
89

90
  if (isUpdateQueryResponse(result.rows)) {
2✔
91
    const oneRow = result.rows as any;
2✔
92
    return { ...oneRow, rows: [oneRow] };
2✔
93
  }
2!
94

NEW
95
  if (Array.isArray(result.rows)) {
×
NEW
96
    if (method === "execute") {
×
NEW
97
      return { rows: result.rows };
×
NEW
98
    } else {
×
NEW
99
      const rows = (result.rows as any[]).map((r) => Object.values(r as Record<string, unknown>));
×
NEW
100
      return { rows };
×
UNCOV
101
    }
×
UNCOV
102
  }
×
103

NEW
104
  return { rows: [] };
×
NEW
105
}
×
106

107
/**
108
 * Processes execute method results (UPDATE, INSERT, DELETE).
109
 *
110
 * @param query - The SQL query
111
 * @param params - Query parameters
112
 * @returns Processed result for Drizzle ORM
113
 */
114
async function processExecuteMethod(query: string, params: unknown[]): Promise<ForgeDriverResult> {
45✔
115
  const sqlStatement = sql.prepare<UpdateQueryResponse>(query);
45✔
116

117
  if (params) {
45✔
118
    sqlStatement.bindParams(...params);
45✔
119
  }
45✔
120

121
  const result = await sqlStatement.execute();
45✔
122
  await saveMetaDataInContextContext(result.metadata as ForgeSQLMetadata);
42✔
123
  if (!result.rows) {
45!
NEW
124
    return { rows: [] };
×
NEW
125
  }
✔
126

127
  if (isUpdateQueryResponse(result.rows)) {
42✔
128
    const oneRow = result.rows as any;
35✔
129
    return { ...oneRow, rows: [oneRow] };
35✔
130
  }
35✔
131

132
  return { rows: result.rows };
7✔
133
}
7✔
134

135
/**
136
 * Processes all method results (SELECT queries).
137
 *
138
 * @param query - The SQL query
139
 * @param params - Query parameters
140
 * @returns Processed result for Drizzle ORM
141
 */
142
async function processAllMethod(query: string, params: unknown[]): Promise<ForgeDriverResult> {
31✔
143
  const sqlStatement = await sql.prepare<unknown>(query);
31✔
144

145
  if (params) {
31✔
146
    await sqlStatement.bindParams(...params);
31✔
147
  }
31✔
148

149
  const result = (await sqlStatement.execute()) as ForgeSQLResult;
31✔
150
  await saveMetaDataInContextContext(result.metadata);
31✔
151

152
  if (!result.rows) {
31!
NEW
153
    return { rows: [] };
×
NEW
154
  }
×
155

156
  const rows = (result.rows as any[]).map((r) => Object.values(r as Record<string, unknown>));
31✔
157

158
  return { rows };
31✔
159
}
31✔
160

161
/**
162
 * Main Forge SQL driver function for Drizzle ORM integration.
163
 * Handles DDL operations, execute operations (UPDATE/INSERT/DELETE), and select operations.
164
 *
165
 * @param query - The SQL query to execute
166
 * @param params - Query parameters
167
 * @param method - Execution method ("all" for SELECT, "execute" for UPDATE/INSERT/DELETE)
168
 * @returns Promise with query results compatible with Drizzle ORM
169
 *
170
 * @throws {Error} When DDL operations are called with parameters
171
 *
172
 * @example
173
 * ```typescript
174
 * // DDL operation
175
 * await forgeDriver("CREATE TABLE users (id INT)", [], "all");
176
 *
177
 * // SELECT operation
178
 * await forgeDriver("SELECT * FROM users WHERE id = ?", [1], "all");
179
 *
180
 * // UPDATE operation
181
 * await forgeDriver("UPDATE users SET name = ? WHERE id = ?", ["John", 1], "execute");
182
 * ```
183
 */
184
export const forgeDriver = async (
1✔
185
  query: string,
78✔
186
  params: unknown[],
78✔
187
  method: QueryMethod,
78✔
188
): Promise<ForgeDriverResult> => {
78✔
189
  const operationType = await getOperationType();
78✔
190

191
  // Handle DDL operations
192
  if (operationType === "DDL") {
78✔
193
    const result = await sql.executeDDL(inlineParams(query, params));
2✔
194
    return await processDDLResult(method, result);
2✔
195
  }
2✔
196

197
  // Handle execute method (UPDATE, INSERT, DELETE)
198
  if (method === "execute") {
78✔
199
    return await processExecuteMethod(query, params ?? []);
45!
200
  }
45✔
201

202
  // Handle all method (SELECT)
203
  return await processAllMethod(query, params ?? []);
78!
204
};
78✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc