@forge/sql 0.0.1-experimental-9332276 → 0.0.1-experimental-9fa730f
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/README.md +5 -1
- package/out/__test__/sql-statement.test.d.ts +2 -0
- package/out/__test__/sql-statement.test.d.ts.map +1 -0
- package/out/__test__/sql-statement.test.js +40 -0
- package/out/__test__/sql.test.js +143 -50
- package/out/sql-statement.d.ts +11 -0
- package/out/sql-statement.d.ts.map +1 -0
- package/out/sql-statement.js +21 -0
- package/out/sql.d.ts +5 -5
- package/out/sql.d.ts.map +1 -1
- package/out/sql.js +27 -14
- package/out/utils/__test__/response-handler.test.d.ts +2 -0
- package/out/utils/__test__/response-handler.test.d.ts.map +1 -0
- package/out/utils/__test__/response-handler.test.js +61 -0
- package/out/utils/{reponse-handler.d.ts → response-handler.d.ts} +3 -3
- package/out/utils/response-handler.d.ts.map +1 -0
- package/out/utils/types.d.ts +6 -3
- package/out/utils/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/out/__test__/fetch-wrapper.test.d.ts +0 -2
- package/out/__test__/fetch-wrapper.test.d.ts.map +0 -1
- package/out/__test__/fetch-wrapper.test.js +0 -23
- package/out/utils/fetch-wrapper.d.ts +0 -3
- package/out/utils/fetch-wrapper.d.ts.map +0 -1
- package/out/utils/fetch-wrapper.js +0 -25
- package/out/utils/reponse-handler.d.ts.map +0 -1
- /package/out/utils/{reponse-handler.js → response-handler.js} +0 -0
package/README.md
CHANGED
|
@@ -4,5 +4,9 @@ Usage example:
|
|
|
4
4
|
```typescript
|
|
5
5
|
import sql from "@forge/sql";
|
|
6
6
|
|
|
7
|
-
await sql.execute(`SELECT * FROM example`);
|
|
7
|
+
const result = await sql.execute(`SELECT * FROM example`);
|
|
8
|
+
|
|
9
|
+
const statement = sql.prepare('INSERT INTO test VALUES (?, ?)');
|
|
10
|
+
|
|
11
|
+
const result = await statement.bindParams('John Doe', 42).execute();
|
|
8
12
|
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-statement.test.d.ts","sourceRoot":"","sources":["../../src/__test__/sql-statement.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const sql_statement_1 = require("../sql-statement");
|
|
4
|
+
describe('SqlStatement', () => {
|
|
5
|
+
let mockRemoteSqlApi;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
mockRemoteSqlApi = jest.fn().mockResolvedValue({ rows: [] });
|
|
8
|
+
});
|
|
9
|
+
it('should initialize with a query and remoteSqlApi function', () => {
|
|
10
|
+
const sqlStatement = new sql_statement_1.SqlStatement('SELECT * FROM table', mockRemoteSqlApi);
|
|
11
|
+
expect(sqlStatement).toBeInstanceOf(sql_statement_1.SqlStatement);
|
|
12
|
+
});
|
|
13
|
+
it('should bind parameters correctly', () => {
|
|
14
|
+
const sqlStatement = new sql_statement_1.SqlStatement('SELECT * FROM table WHERE id = ?', mockRemoteSqlApi);
|
|
15
|
+
const params = [1];
|
|
16
|
+
sqlStatement.bindParams(...params);
|
|
17
|
+
expect(sqlStatement['params']).toEqual(params);
|
|
18
|
+
});
|
|
19
|
+
it('should execute the query with parameters using remoteSqlApi', async () => {
|
|
20
|
+
const sqlStatement = new sql_statement_1.SqlStatement('SELECT * FROM table WHERE id = ?', mockRemoteSqlApi);
|
|
21
|
+
const params = [1];
|
|
22
|
+
sqlStatement.bindParams(...params);
|
|
23
|
+
const result = await sqlStatement.execute();
|
|
24
|
+
expect(mockRemoteSqlApi).toHaveBeenCalledWith('SELECT * FROM table WHERE id = ?', params);
|
|
25
|
+
expect(result).toEqual({ rows: [] });
|
|
26
|
+
});
|
|
27
|
+
it('should handle execution without parameters', async () => {
|
|
28
|
+
const sqlStatement = new sql_statement_1.SqlStatement('SELECT * FROM table', mockRemoteSqlApi);
|
|
29
|
+
const result = await sqlStatement.execute();
|
|
30
|
+
expect(mockRemoteSqlApi).toHaveBeenCalledWith('SELECT * FROM table', []);
|
|
31
|
+
expect(result).toEqual({ rows: [] });
|
|
32
|
+
});
|
|
33
|
+
it('should return result from remoteSqlApi', async () => {
|
|
34
|
+
const expectedResult = { rows: [{ id: 1, name: 'Test' }] };
|
|
35
|
+
mockRemoteSqlApi.mockResolvedValueOnce(expectedResult);
|
|
36
|
+
const sqlStatement = new sql_statement_1.SqlStatement('SELECT * FROM table', mockRemoteSqlApi);
|
|
37
|
+
const result = await sqlStatement.execute();
|
|
38
|
+
expect(result).toEqual(expectedResult);
|
|
39
|
+
});
|
|
40
|
+
});
|
package/out/__test__/sql.test.js
CHANGED
|
@@ -1,58 +1,151 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const
|
|
4
|
-
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
|
|
3
|
+
const api_1 = require("@forge/api");
|
|
5
4
|
const sql_1 = require("../sql");
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
ok: true,
|
|
16
|
-
text: async () => JSON.stringify({
|
|
17
|
-
values: []
|
|
18
|
-
})
|
|
19
|
-
});
|
|
20
|
-
await sql_1.sql.execute('asdf');
|
|
21
|
-
expect(fetchMock).toHaveBeenCalled();
|
|
22
|
-
});
|
|
23
|
-
});
|
|
5
|
+
const sql_statement_1 = require("../sql-statement");
|
|
6
|
+
const response_handler_1 = require("../utils/response-handler");
|
|
7
|
+
jest.mock('@forge/api');
|
|
8
|
+
jest.mock('../sql-statement');
|
|
9
|
+
jest.mock('../utils/response-handler', () => ({
|
|
10
|
+
ApiError: jest.fn(),
|
|
11
|
+
getResponseBody: jest.fn()
|
|
12
|
+
}));
|
|
24
13
|
describe('SqlClient', () => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
14
|
+
let sqlClient;
|
|
15
|
+
let mockFetch;
|
|
16
|
+
let mockSqlStatement;
|
|
17
|
+
let mockGetResponseBody;
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
sqlClient = new sql_1.SqlClient();
|
|
20
|
+
mockFetch = jest.fn();
|
|
21
|
+
api_1.__fetchProduct.mockReturnValue(mockFetch);
|
|
22
|
+
mockSqlStatement = {
|
|
23
|
+
bindParams: jest.fn().mockReturnThis(),
|
|
24
|
+
execute: jest.fn()
|
|
25
|
+
};
|
|
26
|
+
sql_statement_1.SqlStatement.mockImplementation(() => mockSqlStatement);
|
|
27
|
+
mockGetResponseBody = jest.fn();
|
|
28
|
+
jest.requireMock('../utils/response-handler').getResponseBody = mockGetResponseBody;
|
|
29
|
+
jest.clearAllMocks();
|
|
30
|
+
});
|
|
31
|
+
describe('sendRequest', () => {
|
|
32
|
+
it('should send a request with the correct options and return the response', async () => {
|
|
33
|
+
const mockResponse = { ok: true, status: 200 };
|
|
34
|
+
mockFetch.mockResolvedValue(mockResponse);
|
|
35
|
+
const path = 'api/v1/sql/execute';
|
|
36
|
+
const options = { method: 'GET', headers: { 'Custom-Header': 'value' } };
|
|
37
|
+
const response = await sqlClient['sendRequest'](path, options);
|
|
38
|
+
expect(mockFetch).toHaveBeenCalledWith(path, {
|
|
39
|
+
...options,
|
|
40
|
+
redirect: 'follow',
|
|
41
|
+
headers: {
|
|
42
|
+
...options.headers,
|
|
43
|
+
'Content-Type': 'application/json'
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
expect(response).toBe(mockResponse);
|
|
47
|
+
});
|
|
48
|
+
it('should handle requests without options', async () => {
|
|
49
|
+
const mockResponse = { ok: true, status: 200 };
|
|
50
|
+
mockFetch.mockResolvedValue(mockResponse);
|
|
51
|
+
const path = 'api/v1/sql/execute';
|
|
52
|
+
const response = await sqlClient['sendRequest'](path);
|
|
53
|
+
expect(mockFetch).toHaveBeenCalledWith(path, {
|
|
54
|
+
redirect: 'follow',
|
|
55
|
+
headers: {
|
|
56
|
+
'Content-Type': 'application/json'
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
expect(response).toBe(mockResponse);
|
|
60
|
+
});
|
|
61
|
+
it('should propagate fetch errors', async () => {
|
|
62
|
+
const mockError = new Error('Network error');
|
|
63
|
+
mockFetch.mockRejectedValue(mockError);
|
|
64
|
+
const path = 'api/v1/sql/execute';
|
|
65
|
+
await expect(sqlClient['sendRequest'](path)).rejects.toThrow(mockError);
|
|
66
|
+
expect(mockFetch).toHaveBeenCalledWith(path, expect.any(Object));
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('storageApi', () => {
|
|
70
|
+
it('should send a request and return the response body', async () => {
|
|
71
|
+
const mockResponse = { text: jest.fn().mockResolvedValue(JSON.stringify({ response: { rows: [] } })) };
|
|
72
|
+
mockFetch.mockResolvedValue(mockResponse);
|
|
73
|
+
mockGetResponseBody.mockResolvedValue({ rows: [] });
|
|
74
|
+
const result = await sqlClient.storageApi('SELECT * FROM test');
|
|
75
|
+
expect(mockFetch).toHaveBeenCalledWith('api/v1/sql/execute', {
|
|
76
|
+
method: 'POST',
|
|
77
|
+
body: JSON.stringify({ query: 'SELECT * FROM test', params: [], method: 'all' }),
|
|
78
|
+
redirect: 'follow',
|
|
79
|
+
headers: { 'Content-Type': 'application/json' }
|
|
80
|
+
});
|
|
81
|
+
expect(mockGetResponseBody).toHaveBeenCalledWith(mockResponse);
|
|
82
|
+
expect(result).toEqual({ rows: [] });
|
|
83
|
+
});
|
|
84
|
+
it('should send a request with parameters and method', async () => {
|
|
85
|
+
const mockResponse = { text: jest.fn().mockResolvedValue(JSON.stringify({ response: { rows: [] } })) };
|
|
86
|
+
mockFetch.mockResolvedValue(mockResponse);
|
|
87
|
+
mockGetResponseBody.mockResolvedValue({ rows: [] });
|
|
88
|
+
const params = [1];
|
|
89
|
+
const result = await sqlClient.storageApi('SELECT * FROM test WHERE id = ?', params, 'one');
|
|
90
|
+
expect(mockFetch).toHaveBeenCalledWith('api/v1/sql/execute', {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
body: JSON.stringify({ query: 'SELECT * FROM test WHERE id = ?', params, method: 'one' }),
|
|
93
|
+
redirect: 'follow',
|
|
94
|
+
headers: { 'Content-Type': 'application/json' }
|
|
95
|
+
});
|
|
96
|
+
expect(mockGetResponseBody).toHaveBeenCalledWith(mockResponse);
|
|
97
|
+
expect(result).toEqual({ rows: [] });
|
|
98
|
+
});
|
|
99
|
+
it('should handle errors from getResponseBody', async () => {
|
|
100
|
+
const mockResponse = { text: jest.fn().mockResolvedValue('Invalid JSON') };
|
|
101
|
+
mockFetch.mockResolvedValue(mockResponse);
|
|
102
|
+
const mockError = new Error('Invalid JSON');
|
|
103
|
+
mockGetResponseBody.mockRejectedValue(mockError);
|
|
104
|
+
await expect(sqlClient.storageApi('INVALID SQL QUERY')).rejects.toThrow(mockError);
|
|
105
|
+
expect(mockFetch).toHaveBeenCalledWith('api/v1/sql/execute', expect.any(Object));
|
|
106
|
+
expect(mockGetResponseBody).toHaveBeenCalledWith(mockResponse);
|
|
107
|
+
});
|
|
40
108
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
109
|
+
describe('prepare', () => {
|
|
110
|
+
it('should return a SqlStatement instance', () => {
|
|
111
|
+
const statement = sqlClient.prepare('SELECT * FROM test');
|
|
112
|
+
expect(statement).toBe(mockSqlStatement);
|
|
113
|
+
expect(sql_statement_1.SqlStatement).toHaveBeenCalledWith('SELECT * FROM test', expect.any(Function));
|
|
114
|
+
});
|
|
115
|
+
it('should pass the correct query to SqlStatement', () => {
|
|
116
|
+
sqlClient.prepare('INSERT INTO test VALUES (?, ?)');
|
|
117
|
+
expect(sql_statement_1.SqlStatement).toHaveBeenCalledWith('INSERT INTO test VALUES (?, ?)', expect.any(Function));
|
|
118
|
+
});
|
|
119
|
+
it('should pass the storageApi method to SqlStatement', () => {
|
|
120
|
+
sqlClient.prepare('SELECT * FROM test');
|
|
121
|
+
const passedFunction = sql_statement_1.SqlStatement.mock.calls[0][1];
|
|
122
|
+
expect(typeof passedFunction).toBe('function');
|
|
123
|
+
});
|
|
47
124
|
});
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
125
|
+
describe('execute', () => {
|
|
126
|
+
it('should execute a query and return the result', async () => {
|
|
127
|
+
const mockResult = { rows: [{ id: 1, name: 'Test' }] };
|
|
128
|
+
mockSqlStatement.execute.mockResolvedValue(mockResult);
|
|
129
|
+
const result = await sqlClient.execute('SELECT * FROM test');
|
|
130
|
+
expect(result).toEqual(mockResult);
|
|
131
|
+
expect(sql_statement_1.SqlStatement).toHaveBeenCalledWith('SELECT * FROM test', expect.any(Function));
|
|
132
|
+
expect(mockSqlStatement.execute).toHaveBeenCalled();
|
|
133
|
+
});
|
|
134
|
+
it('should execute a query with parameters', async () => {
|
|
135
|
+
const mockResult = { rows: [{ id: 1, name: 'Test' }] };
|
|
136
|
+
mockSqlStatement.execute.mockResolvedValue(mockResult);
|
|
137
|
+
const result = await sqlClient.prepare('SELECT * FROM test WHERE id = ?').bindParams(1).execute();
|
|
138
|
+
expect(result).toEqual(mockResult);
|
|
139
|
+
expect(mockSqlStatement.bindParams).toHaveBeenCalledWith(1);
|
|
140
|
+
expect(mockSqlStatement.execute).toHaveBeenCalled();
|
|
141
|
+
});
|
|
142
|
+
it('should handle API errors', async () => {
|
|
143
|
+
const mockApiError = new response_handler_1.ApiError(400, 'BAD_REQUEST', 'Invalid query');
|
|
144
|
+
mockSqlStatement.execute.mockRejectedValue(mockApiError);
|
|
145
|
+
const result = await sqlClient.execute('INVALID SQL QUERY');
|
|
146
|
+
expect(result).toEqual({ rows: [], err: mockApiError });
|
|
147
|
+
expect(sql_statement_1.SqlStatement).toHaveBeenCalledWith('INVALID SQL QUERY', expect.any(Function));
|
|
148
|
+
expect(mockSqlStatement.execute).toHaveBeenCalled();
|
|
149
|
+
});
|
|
57
150
|
});
|
|
58
151
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Result } from './utils/types';
|
|
2
|
+
export declare type SqlParameters = any[];
|
|
3
|
+
export declare class SqlStatement {
|
|
4
|
+
private readonly query;
|
|
5
|
+
private params;
|
|
6
|
+
private readonly remoteSqlApi;
|
|
7
|
+
constructor(query: string, remoteSqlApi: (query: string, params?: SqlParameters, method?: string) => Promise<any>);
|
|
8
|
+
bindParams(...args: SqlParameters): SqlStatement;
|
|
9
|
+
execute(): Promise<Result>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=sql-statement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql-statement.d.ts","sourceRoot":"","sources":["../src/sql-statement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC,oBAAY,aAAa,GAAG,GAAG,EAAE,CAAC;AAElC,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA2E;gBAE5F,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC;IAMjH,UAAU,CAAC,GAAG,IAAI,EAAE,aAAa,GAAG,YAAY;IAK1C,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;CAGjC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SqlStatement = void 0;
|
|
4
|
+
class SqlStatement {
|
|
5
|
+
query;
|
|
6
|
+
params;
|
|
7
|
+
remoteSqlApi;
|
|
8
|
+
constructor(query, remoteSqlApi) {
|
|
9
|
+
this.query = query;
|
|
10
|
+
this.params = [];
|
|
11
|
+
this.remoteSqlApi = remoteSqlApi;
|
|
12
|
+
}
|
|
13
|
+
bindParams(...args) {
|
|
14
|
+
this.params = args;
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
async execute() {
|
|
18
|
+
return this.remoteSqlApi(this.query, this.params);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.SqlStatement = SqlStatement;
|
package/out/sql.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Result } from './utils/types';
|
|
2
|
+
import { SqlParameters, SqlStatement } from './sql-statement';
|
|
3
3
|
export declare class SqlClient {
|
|
4
|
-
private
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
private sendRequest;
|
|
5
|
+
storageApi(query: string, params?: SqlParameters, method?: string): Promise<Result>;
|
|
6
|
+
prepare(query: string): SqlStatement;
|
|
7
7
|
execute(query: string): Promise<Result>;
|
|
8
8
|
}
|
|
9
9
|
export declare const sql: SqlClient;
|
package/out/sql.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../src/sql.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAY,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE9D,qBAAa,SAAS;YACN,WAAW;IAYnB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,aAAkB,EAAE,MAAM,SAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ5F,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAI9B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAO9C;AAED,eAAO,MAAM,GAAG,WAAkB,CAAC"}
|
package/out/sql.js
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.sql = exports.SqlClient = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
const api_1 = require("@forge/api");
|
|
5
|
+
const response_handler_1 = require("./utils/response-handler");
|
|
6
|
+
const sql_statement_1 = require("./sql-statement");
|
|
6
7
|
class SqlClient {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
buildRequest(requestBody) {
|
|
12
|
-
return {
|
|
13
|
-
method: 'POST',
|
|
14
|
-
body: JSON.stringify(requestBody),
|
|
8
|
+
async sendRequest(path, options) {
|
|
9
|
+
const response = await (0, api_1.__fetchProduct)({ provider: 'none', remote: 'sql' })(path, {
|
|
10
|
+
...options,
|
|
11
|
+
redirect: 'follow',
|
|
15
12
|
headers: {
|
|
13
|
+
...options?.headers,
|
|
16
14
|
'Content-Type': 'application/json'
|
|
17
15
|
}
|
|
18
|
-
};
|
|
16
|
+
});
|
|
17
|
+
return response;
|
|
18
|
+
}
|
|
19
|
+
async storageApi(query, params = [], method = 'all') {
|
|
20
|
+
const response = await this.sendRequest('api/v1/sql/execute', {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
body: JSON.stringify({ query, params, method })
|
|
23
|
+
});
|
|
24
|
+
return await (0, response_handler_1.getResponseBody)(response);
|
|
25
|
+
}
|
|
26
|
+
prepare(query) {
|
|
27
|
+
return new sql_statement_1.SqlStatement(query, this.storageApi.bind(this));
|
|
19
28
|
}
|
|
20
29
|
async execute(query) {
|
|
21
|
-
|
|
22
|
-
|
|
30
|
+
try {
|
|
31
|
+
return await this.prepare(query).execute();
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
return { rows: [], err: e };
|
|
35
|
+
}
|
|
23
36
|
}
|
|
24
37
|
}
|
|
25
38
|
exports.SqlClient = SqlClient;
|
|
26
|
-
exports.sql = new SqlClient(
|
|
39
|
+
exports.sql = new SqlClient();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-handler.test.d.ts","sourceRoot":"","sources":["../../../src/utils/__test__/response-handler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const response_handler_1 = require("../response-handler");
|
|
4
|
+
describe('getResponseBody', () => {
|
|
5
|
+
it('should return parsed response when response is ok', async () => {
|
|
6
|
+
const mockResponse = {
|
|
7
|
+
text: jest.fn().mockResolvedValue(JSON.stringify({ response: { rows: [] } })),
|
|
8
|
+
ok: true,
|
|
9
|
+
status: 200
|
|
10
|
+
};
|
|
11
|
+
const result = await (0, response_handler_1.getResponseBody)(mockResponse);
|
|
12
|
+
expect(result).toEqual({ rows: [] });
|
|
13
|
+
});
|
|
14
|
+
it('should throw ApiError with parsed error when response is not ok and error JSON is valid', async () => {
|
|
15
|
+
const mockResponse = {
|
|
16
|
+
text: jest
|
|
17
|
+
.fn()
|
|
18
|
+
.mockResolvedValue(JSON.stringify({ error: { code: 'ERROR_CODE', title: 'Error Title', data: { info: 'detail' } } })),
|
|
19
|
+
ok: false,
|
|
20
|
+
status: 400
|
|
21
|
+
};
|
|
22
|
+
await expect((0, response_handler_1.getResponseBody)(mockResponse)).rejects.toThrow(response_handler_1.ApiError);
|
|
23
|
+
await expect((0, response_handler_1.getResponseBody)(mockResponse)).rejects.toMatchObject({
|
|
24
|
+
status: 400,
|
|
25
|
+
code: 'ERROR_CODE',
|
|
26
|
+
message: 'Error Title',
|
|
27
|
+
data: { info: 'detail' }
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
it('should throw ApiError with UNKNOWN_ERROR when response is not ok and error JSON is invalid', async () => {
|
|
31
|
+
const mockResponse = {
|
|
32
|
+
text: jest.fn().mockResolvedValue('Invalid JSON'),
|
|
33
|
+
ok: false,
|
|
34
|
+
status: 500
|
|
35
|
+
};
|
|
36
|
+
await expect((0, response_handler_1.getResponseBody)(mockResponse)).rejects.toThrow(response_handler_1.ApiError);
|
|
37
|
+
await expect((0, response_handler_1.getResponseBody)(mockResponse)).rejects.toMatchObject({
|
|
38
|
+
status: 500,
|
|
39
|
+
code: 'UNKNOWN_ERROR',
|
|
40
|
+
message: 'Invalid JSON'
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it('should throw Error when response text is not valid JSON', async () => {
|
|
44
|
+
const mockResponse = {
|
|
45
|
+
text: jest.fn().mockResolvedValue('Invalid JSON'),
|
|
46
|
+
ok: true,
|
|
47
|
+
status: 200
|
|
48
|
+
};
|
|
49
|
+
await expect((0, response_handler_1.getResponseBody)(mockResponse)).rejects.toThrowError(new Error('Unexpected error. Response was not valid JSON: Invalid JSON'));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe('ApiError', () => {
|
|
53
|
+
it('should create an ApiError with correct properties', () => {
|
|
54
|
+
const error = new response_handler_1.ApiError(404, 'NOT_FOUND', 'Resource not found', { resource: 'User' });
|
|
55
|
+
expect(error).toBeInstanceOf(Error);
|
|
56
|
+
expect(error.status).toBe(404);
|
|
57
|
+
expect(error.code).toBe('NOT_FOUND');
|
|
58
|
+
expect(error.message).toBe('Resource not found');
|
|
59
|
+
expect(error.data).toEqual({ resource: 'User' });
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Response } from './types';
|
|
1
|
+
import { Response, Result } from './types';
|
|
2
2
|
export declare class ApiError extends Error {
|
|
3
3
|
readonly status: number;
|
|
4
4
|
readonly code: string;
|
|
5
5
|
readonly data?: any;
|
|
6
6
|
constructor(status: number, code: string, message: string, data?: any);
|
|
7
7
|
}
|
|
8
|
-
export declare function getResponseBody(response: Response): Promise<
|
|
9
|
-
//# sourceMappingURL=
|
|
8
|
+
export declare function getResponseBody(response: Response): Promise<Result>;
|
|
9
|
+
//# sourceMappingURL=response-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response-handler.d.ts","sourceRoot":"","sources":["../../src/utils/response-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;IAErB,QAAQ,CAAC,IAAI,CAAC;gBAHL,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACN,IAAI,CAAC,KAAK;CAItB;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BzE"}
|
package/out/utils/types.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare type Response = Pick<
|
|
3
|
-
export
|
|
1
|
+
import { APIResponse } from '@forge/api';
|
|
2
|
+
export declare type Response = Pick<APIResponse, 'text' | 'ok' | 'status'>;
|
|
3
|
+
export interface Result {
|
|
4
|
+
rows: any[];
|
|
5
|
+
err?: Error;
|
|
6
|
+
}
|
|
4
7
|
//# sourceMappingURL=types.d.ts.map
|
package/out/utils/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,oBAAY,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;AAEnE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,GAAG,CAAC,EAAE,KAAK,CAAC;CACb"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forge/sql",
|
|
3
|
-
"version": "0.0.1-experimental-
|
|
3
|
+
"version": "0.0.1-experimental-9fa730f",
|
|
4
4
|
"description": "Forge SQL package",
|
|
5
5
|
"author": "Atlassian",
|
|
6
6
|
"license": "UNLICENSED",
|
|
@@ -21,6 +21,6 @@
|
|
|
21
21
|
"node-fetch": "2.7.0"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@forge/api": "^3.9.
|
|
24
|
+
"@forge/api": "^3.9.1-experimental-9fa730f"
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-wrapper.test.d.ts","sourceRoot":"","sources":["../../src/__test__/fetch-wrapper.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
|
|
5
|
-
const fetch_wrapper_1 = require("../utils/fetch-wrapper");
|
|
6
|
-
jest.mock('node-fetch');
|
|
7
|
-
const fetchMock = node_fetch_1.default;
|
|
8
|
-
describe('v2', () => {
|
|
9
|
-
it('chooses the v2 fetch based on runtime', async () => {
|
|
10
|
-
const fetch = (0, fetch_wrapper_1.runtimeV2FetchWrapper)();
|
|
11
|
-
fetchMock.mockResolvedValueOnce({
|
|
12
|
-
headers: {
|
|
13
|
-
has: jest.isMockFunction
|
|
14
|
-
},
|
|
15
|
-
ok: true,
|
|
16
|
-
json: async () => ({
|
|
17
|
-
values: []
|
|
18
|
-
})
|
|
19
|
-
});
|
|
20
|
-
await fetch('asdf');
|
|
21
|
-
expect(fetchMock).toHaveBeenCalled();
|
|
22
|
-
});
|
|
23
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-wrapper.d.ts","sourceRoot":"","sources":["../../src/utils/fetch-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAqB,MAAM,YAAY,CAAC;AAI5D,wBAAgB,qBAAqB,IAAI,WAAW,CAoBnD"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runtimeV2FetchWrapper = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const api_1 = require("@forge/api");
|
|
6
|
-
const node_fetch_1 = tslib_1.__importDefault(require("node-fetch"));
|
|
7
|
-
const fetch_1 = require("@forge/api/out/api/fetch");
|
|
8
|
-
function runtimeV2FetchWrapper() {
|
|
9
|
-
return async (path, init) => {
|
|
10
|
-
const url = `https://sql/${path}`;
|
|
11
|
-
init = (0, fetch_1.addMagicAgent)(init);
|
|
12
|
-
init.redirect = 'follow';
|
|
13
|
-
init.headers = {
|
|
14
|
-
...init.headers,
|
|
15
|
-
redirect: 'follow',
|
|
16
|
-
'Content-Type': 'application/json'
|
|
17
|
-
};
|
|
18
|
-
const response = await (0, node_fetch_1.default)(url, init);
|
|
19
|
-
if (response.headers.has('forge-proxy-error')) {
|
|
20
|
-
throw new api_1.ProxyRequestError(response.status, response.headers.get('forge-proxy-error'));
|
|
21
|
-
}
|
|
22
|
-
return response;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
exports.runtimeV2FetchWrapper = runtimeV2FetchWrapper;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"reponse-handler.d.ts","sourceRoot":"","sources":["../../src/utils/reponse-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,qBAAa,QAAS,SAAQ,KAAK;IAE/B,QAAQ,CAAC,MAAM,EAAE,MAAM;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM;IAErB,QAAQ,CAAC,IAAI,CAAC;gBAHL,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACN,IAAI,CAAC,KAAK;CAItB;AAED,wBAAsB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CA0BtE"}
|
|
File without changes
|