Skip to content

Commit 312bcca

Browse files
committed
json support for all dialects
1 parent add3641 commit 312bcca

14 files changed

Lines changed: 1127 additions & 409 deletions

File tree

packages/inquire-mysql2/src/Connection.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export default class Mysql2Connection implements Connection<Resource> {
3939
*/
4040
public format(request: QueryObject) {
4141
let { query, values = [] } = request;
42+
//escaped question marks for identifiers (??)
43+
query = query.replaceAll('??', '\\?');
4244
for (let i = 0; i < values.length; i++) {
4345
//check the value for Date and arrays and objects
4446
const value = values[i];

packages/inquire-mysql2/tests/Connection.test.ts

Lines changed: 118 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -5,137 +5,137 @@ import { expect } from 'chai';
55
import Connection from '../src/Connection';
66

77
describe('Connection Test', () => {
8-
// Line 29
9-
it('Should return the correct value for lastId when _lastId is set to a positive integer', () => {
10-
const mockResource = {} as any;
11-
const connection = new Connection(mockResource);
12-
connection['_lastId'] = 42;
13-
const lastId = connection.lastId;
14-
expect(lastId).to.equal(42);
15-
});
16-
17-
// Line 44
18-
it('Should handle a request object with no values property', () => {
19-
const mockResource = {} as any;
20-
const connection = new Connection(mockResource);
21-
const request = {
22-
query: 'SELECT * FROM table'
23-
};
24-
const formatted = connection.format(request);
25-
expect(formatted.values).to.deep.equal([]);
26-
});
27-
28-
// Line 49
29-
it('should convert Date objects in the values array to ISO string format', () => {
30-
const mockResource = {} as any;
31-
const connection = new Connection(mockResource);
32-
const date = new Date('2023-10-05T14:48:00.000Z');
33-
const request = {
34-
query: 'SELECT * FROM table WHERE date = ?',
35-
values: [date]
36-
};
37-
const formatted = connection.format(request);
38-
expect(formatted.values[0]).to.equal(date.toISOString());
39-
});
40-
41-
// Line 51
42-
it('Should handle an empty array by converting it to an empty JSON array string', () => {
43-
const mockResource = {} as any;
44-
const connection = new Connection(mockResource);
45-
const request = {
46-
query: 'SELECT * FROM table WHERE data = ?',
47-
values: [[]]
48-
};
49-
const formatted = connection.format(request);
50-
expect(formatted.values[0]).to.equal('[]');
51-
});
52-
53-
// Line 53
54-
it('Should convert a nested object in the values array to a JSON string', () => {
55-
const mockResource = {} as any;
56-
const connection = new Connection(mockResource);
57-
const nestedObject = { key: { nestedKey: 'nestedValue' } };
58-
const request = {
59-
query: 'INSERT INTO table (data) VALUES (?)',
60-
values: [nestedObject]
61-
};
62-
const formatted = connection.format(request);
63-
expect(formatted.values[0]).to.equal(JSON.stringify(nestedObject));
64-
});
8+
// Line 29
9+
it('Should return the correct value for lastId when _lastId is set to a positive integer', () => {
10+
const mockResource = {} as any;
11+
const connection = new Connection(mockResource);
12+
connection['_lastId'] = 42;
13+
const lastId = connection.lastId;
14+
expect(lastId).to.equal(42);
15+
});
6516

66-
// Line 67 - 69
67-
it('Should set _lastId when results[0] is an object with insertId property and not an array', async () => {
68-
const mockResource = {
69-
execute: async () => [{ insertId: 123 }]
70-
} as any;
71-
const connection = new Connection(mockResource);
72-
const request = {
73-
query: 'INSERT INTO table (column) VALUES (?)',
74-
values: ['value']
75-
};
76-
await connection.query(request);
77-
expect(connection.lastId).to.equal(123);
78-
});
17+
// Line 44
18+
it('Should handle a request object with no values property', () => {
19+
const mockResource = {} as any;
20+
const connection = new Connection(mockResource);
21+
const request = {
22+
query: 'SELECT * FROM table'
23+
};
24+
const formatted = connection.format(request);
25+
expect(formatted.values).to.deep.equal([]);
26+
});
27+
28+
// Line 49
29+
it('should convert Date objects in the values array to ISO string format', () => {
30+
const mockResource = {} as any;
31+
const connection = new Connection(mockResource);
32+
const date = new Date('2023-10-05T14:48:00.000Z');
33+
const request = {
34+
query: 'SELECT * FROM table WHERE date = ?',
35+
values: [date]
36+
};
37+
const formatted = connection.format(request);
38+
expect(formatted.values[0]).to.equal(date.toISOString());
39+
});
7940

80-
// Line 70
81-
it('Should return an empty array when results is an empty array', async () => {
82-
const mockResource = {
83-
execute: async () => [[]]
84-
} as any;
85-
const connection = new Connection(mockResource);
86-
const request = {
87-
query: 'SELECT * FROM table',
88-
values: []
89-
};
90-
const results = await connection.query(request);
91-
expect(results).to.deep.equal([]);
92-
});
41+
// Line 51
42+
it('Should handle an empty array by converting it to an empty JSON array string', () => {
43+
const mockResource = {} as any;
44+
const connection = new Connection(mockResource);
45+
const request = {
46+
query: 'SELECT * FROM table WHERE data = ?',
47+
values: [[]]
48+
};
49+
const formatted = connection.format(request);
50+
expect(formatted.values[0]).to.equal('[]');
51+
});
9352

94-
// Line 88 - 90
95-
it('Should successfully execute the callback and commit when both operations succeed', async () => {
96-
const mockResource = {
97-
beginTransaction: async () => {},
98-
commit: async () => { mockResource.commit.calledOnce = true; }
99-
} as any;
100-
const connection = new Connection(mockResource);
101-
const callback = async (conn: any) => {
102-
return ['success'];
103-
};
104-
const results = await connection.transaction(callback);
105-
expect(results).to.deep.equal(['success']);
106-
expect(mockResource.commit.calledOnce).to.be.true;
107-
});
53+
// Line 53
54+
it('Should convert a nested object in the values array to a JSON string', () => {
55+
const mockResource = {} as any;
56+
const connection = new Connection(mockResource);
57+
const nestedObject = { key: { nestedKey: 'nestedValue' } };
58+
const request = {
59+
query: 'INSERT INTO table (data) VALUES (?)',
60+
values: [nestedObject]
61+
};
62+
const formatted = connection.format(request);
63+
expect(formatted.values[0]).to.equal(JSON.stringify(nestedObject));
64+
});
10865

109-
// Line 91 - 93
110-
it('Should handle and rollback transaction when beginTransaction throws an error', async () => {
66+
// Line 67 - 69
67+
it('Should set _lastId when results[0] is an object with insertId property and not an array', async () => {
11168
const mockResource = {
112-
beginTransaction: async () => { throw new Error('Transaction error'); },
113-
rollback: async () => { mockResource.rollback.calledOnce = true; }
69+
execute: async () => [{ insertId: 123 }]
11470
} as any;
11571
const connection = new Connection(mockResource);
116-
const callback = async () => { return []; };
117-
try {
118-
await connection.transaction(callback);
119-
} catch (e) {
120-
expect(e.message).to.equal('Transaction error');
121-
}
122-
expect(mockResource.rollback.calledOnce).to.be.true;
123-
});
72+
const request = {
73+
query: 'INSERT INTO table (column) VALUES (?)',
74+
values: ['value']
75+
};
76+
await connection.query(request);
77+
expect(connection.lastId).to.equal(123);
78+
});
12479

125-
// Line 103 - 104
126-
it('Should return results as Results<R> when results[0] is an array using lowercase isarray method', async () => {
80+
// Line 70
81+
it('Should return an empty array when results is an empty array', async () => {
12782
const mockResource = {
128-
execute: async () => [[{ id: 1, name: 'test' }]]
83+
execute: async () => [[]]
12984
} as any;
13085
const connection = new Connection(mockResource);
13186
const request = {
132-
query: 'SELECT * FROM table',
133-
values: []
87+
query: 'SELECT * FROM table',
88+
values: []
13489
};
135-
const results = await connection.raw(request);
136-
expect(results).to.deep.equal([[{ id: 1, name: 'test' }]]);
137-
});
138-
90+
const results = await connection.query(request);
91+
expect(results).to.deep.equal([]);
92+
});
93+
94+
// Line 88 - 90
95+
it('Should successfully execute the callback and commit when both operations succeed', async () => {
96+
const mockResource = {
97+
beginTransaction: async () => {},
98+
commit: async () => { mockResource.commit.calledOnce = true; }
99+
} as any;
100+
const connection = new Connection(mockResource);
101+
const callback = async (conn: any) => {
102+
return ['success'];
103+
};
104+
const results = await connection.transaction(callback);
105+
expect(results).to.deep.equal(['success']);
106+
expect(mockResource.commit.calledOnce).to.be.true;
107+
});
108+
109+
// Line 91 - 93
110+
it('Should handle and rollback transaction when beginTransaction throws an error', async () => {
111+
const mockResource = {
112+
beginTransaction: async () => { throw new Error('Transaction error'); },
113+
rollback: async () => { mockResource.rollback.calledOnce = true; }
114+
} as any;
115+
const connection = new Connection(mockResource);
116+
const callback = async () => { return []; };
117+
try {
118+
await connection.transaction(callback);
119+
} catch (e) {
120+
expect(e.message).to.equal('Transaction error');
121+
}
122+
expect(mockResource.rollback.calledOnce).to.be.true;
123+
});
124+
125+
// Line 103 - 104
126+
it('Should return results as Results<R> when results[0] is an array using lowercase isarray method', async () => {
127+
const mockResource = {
128+
execute: async () => [[{ id: 1, name: 'test' }]]
129+
} as any;
130+
const connection = new Connection(mockResource);
131+
const request = {
132+
query: 'SELECT * FROM table',
133+
values: []
134+
};
135+
const results = await connection.raw(request);
136+
expect(results).to.deep.equal([[{ id: 1, name: 'test' }]]);
137+
});
139138

139+
140140

141141
});

packages/inquire-pg/src/Connection.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ export default class PGConnection implements Connection<Resource> {
3636
*/
3737
public format(request: QueryObject) {
3838
let { query, values = [] } = request;
39+
//escaped question marks for identifiers (??) should not
40+
// be replaced with parameter placeholders ($1, $2, etc.)
41+
const hash = Math.random().toString(36).substring(2, 15);
42+
query = query.replaceAll('??', `:QUESTION${hash}:`);
3943
for (let i = 0; i < values.length; i++) {
4044
if (!query.includes('?')) {
4145
throw Exception.for(
@@ -59,6 +63,7 @@ export default class PGConnection implements Connection<Resource> {
5963
'Query does not match the number of values.'
6064
);
6165
}
66+
query = query.replaceAll(`:QUESTION${hash}:`, '?');
6267
return { query, values };
6368
}
6469

0 commit comments

Comments
 (0)