@mlagie/sql-connector 2.0.7 → 2.0.9
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/package.json +24 -8
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -43
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -29
- package/.github/workflows/publish.yml +0 -80
- package/eslint.config.mjs +0 -37
- package/releases/1.4.8.md +0 -43
- package/releases/1.5.0.md +0 -127
- package/releases/2.0.0.md +0 -32
- package/releases/2.0.1.md +0 -23
- package/releases/2.0.2.md +0 -20
- package/releases/2.0.3.md +0 -20
- package/releases/2.0.4.md +0 -42
- package/releases/2.0.5.md +0 -65
- package/releases/2.0.6.md +0 -80
- package/releases/2.0.7.md +0 -38
- package/socket.yml +0 -4
- package/tests/Model.test.js +0 -721
- package/tests/ModelInstance.test.js +0 -335
- package/tests/buildQuery.test.js +0 -217
- package/tests/connect.test.js +0 -44
- package/tests/formatObject.test.js +0 -46
- package/tests/generateCondition.test.js +0 -241
- package/tests/mysqlMock.js +0 -22
- package/tests/safe.test.js +0 -48
- package/tests/sql.test.js +0 -62
- package/tests/sqlTypeMap.test.js +0 -16
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
const generateCondition = require('../src/utils/generateCondition');
|
|
2
|
-
const { Schema } = require('../src/models/Schema');
|
|
3
|
-
|
|
4
|
-
describe('Utils - generateCondition.js', () => {
|
|
5
|
-
test('Devrait générer une chaîne classique de conditions WHERE (isUpdate = false)', () => {
|
|
6
|
-
const filter = { status: 'active', age: 18 };
|
|
7
|
-
const result = generateCondition(filter, false);
|
|
8
|
-
expect(result).toBe("`status` = 'active' AND `age` = 18");
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
test('Devrait générer une chaîne d\'assignations SET (isUpdate = true)', () => {
|
|
12
|
-
const data = { email: 'test@test.com', updated: 1 };
|
|
13
|
-
const result = generateCondition(data, true);
|
|
14
|
-
expect(result).toBe("`email` = 'test@test.com' , `updated` = 1");
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('Devrait générer un opérateur IN lorsqu\'une valeur est un tableau', () => {
|
|
18
|
-
const filter = { id: [1, 2, 3] };
|
|
19
|
-
const result = generateCondition(filter, false);
|
|
20
|
-
expect(result).toBe('`id` IN (1, 2, 3)');
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test('Devrait générer "IS NULL" pour les filtres et conserver l\'assignation brute en cas d\'Update', () => {
|
|
24
|
-
expect(generateCondition({ deletedAt: null }, false)).toBe('`deletedAt` IS NULL');
|
|
25
|
-
expect(generateCondition({ deletedAt: null }, true)).toBe('`deletedAt` = NULL');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('Devrait convertir une chaîne date ISO au format MySQL si spécifiée dans le Schéma', () => {
|
|
29
|
-
const schema = new Schema({
|
|
30
|
-
publishedAt: { type: Date }
|
|
31
|
-
});
|
|
32
|
-
const filter = { publishedAt: '2026-07-03T15:00:00.000Z' };
|
|
33
|
-
const result = generateCondition(filter, false, schema);
|
|
34
|
-
expect(result).toBe("`publishedAt` = '2026-07-03 15:00:00'");
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('Devrait nettoyer les guillemets de protection d\'une chaîne de caractères', () => {
|
|
38
|
-
const filter = { name: '"Alice"' };
|
|
39
|
-
expect(generateCondition(filter, false)).toBe("`name` = 'Alice'");
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test("generateCondition utilise les champs unique du schema", () => {
|
|
43
|
-
const result = generateCondition(
|
|
44
|
-
{ email: "john@test.fr" },
|
|
45
|
-
false,
|
|
46
|
-
{
|
|
47
|
-
schemaDict: {
|
|
48
|
-
email: {
|
|
49
|
-
unique: true
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
expect(result).toContain("email");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("generateCondition génère un IN pour les champs uniques tableau", () => {
|
|
59
|
-
const result = generateCondition(
|
|
60
|
-
{ email: ["a@test.fr", "b@test.fr"] },
|
|
61
|
-
false,
|
|
62
|
-
{
|
|
63
|
-
schemaDict: {
|
|
64
|
-
email: {
|
|
65
|
-
unique: true
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
expect(result).toContain("IN");
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
test("generateCondition génère un JSON_CONTAINS pour objet unique", () => {
|
|
75
|
-
const result = generateCondition(
|
|
76
|
-
{
|
|
77
|
-
metadata: {
|
|
78
|
-
role: "admin"
|
|
79
|
-
}
|
|
80
|
-
},
|
|
81
|
-
false,
|
|
82
|
-
{
|
|
83
|
-
schemaDict: {
|
|
84
|
-
metadata: {
|
|
85
|
-
unique: true
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
|
|
91
|
-
expect(result).toContain("JSON_CONTAINS");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test("generateCondition génère IS NULL pour champ unique", () => {
|
|
95
|
-
const result = generateCondition(
|
|
96
|
-
{ email: null },
|
|
97
|
-
false,
|
|
98
|
-
{
|
|
99
|
-
schemaDict: {
|
|
100
|
-
email: {
|
|
101
|
-
unique: true
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
|
|
107
|
-
expect(result).toContain("IS NULL");
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test("generateCondition convertit une date ISO sur champ unique", () => {
|
|
111
|
-
const result = generateCondition(
|
|
112
|
-
{
|
|
113
|
-
created_at: "2025-01-01T10:00:00Z"
|
|
114
|
-
},
|
|
115
|
-
false,
|
|
116
|
-
{
|
|
117
|
-
schemaDict: {
|
|
118
|
-
created_at: {
|
|
119
|
-
unique: true
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
expect(result).toContain("2025-01-01 10:00:00");
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test("generateCondition update JSON", () => {
|
|
129
|
-
const result = generateCondition(
|
|
130
|
-
{
|
|
131
|
-
metadata: {
|
|
132
|
-
role: "admin"
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
true
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
expect(result).toContain("=");
|
|
139
|
-
expect(result).not.toContain("JSON_CONTAINS");
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test("generateCondition filtre JSON", () => {
|
|
143
|
-
const result = generateCondition(
|
|
144
|
-
{
|
|
145
|
-
metadata: {
|
|
146
|
-
role: "admin"
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
false
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
expect(result).toContain("JSON_CONTAINS");
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
test("generateCondition retourne une condition simple", () => {
|
|
156
|
-
const result = generateCondition(
|
|
157
|
-
{ id: 42 },
|
|
158
|
-
false
|
|
159
|
-
);
|
|
160
|
-
|
|
161
|
-
expect(result).toContain("42");
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("generateCondition retire les guillemets doubles entourant une valeur", () => {
|
|
165
|
-
const result = generateCondition(
|
|
166
|
-
{ name: '"john"' },
|
|
167
|
-
false,
|
|
168
|
-
{
|
|
169
|
-
schemaDict: {
|
|
170
|
-
name: {
|
|
171
|
-
unique: true
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
expect(result).toContain("john");
|
|
178
|
-
expect(result).not.toContain('"john"');
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
test("generateCondition utilise JSON_CONTAINS avec une chaîne JSON", () => {
|
|
182
|
-
const result = generateCondition(
|
|
183
|
-
{
|
|
184
|
-
metadata: '{"role":"admin"}'
|
|
185
|
-
},
|
|
186
|
-
false,
|
|
187
|
-
{
|
|
188
|
-
schemaDict: {
|
|
189
|
-
metadata: {
|
|
190
|
-
unique: true
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
expect(result).toContain("JSON_CONTAINS");
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test("generateCondition détecte une chaîne JSON", () => {
|
|
200
|
-
const result = generateCondition({
|
|
201
|
-
metadata: '{"role":"admin"}'
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
expect(result).toContain("JSON_CONTAINS");
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("generateCondition supporte fieldDef.type string", () => {
|
|
208
|
-
generateCondition(
|
|
209
|
-
{
|
|
210
|
-
created_at: "2025-01-01T10:00:00Z"
|
|
211
|
-
},
|
|
212
|
-
false,
|
|
213
|
-
{
|
|
214
|
-
schemaDict: {
|
|
215
|
-
created_at: {
|
|
216
|
-
type: "Date"
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
test("generateCondition convertit une date ISO pour un champ Date", () => {
|
|
224
|
-
const result = generateCondition(
|
|
225
|
-
{
|
|
226
|
-
created_at: "2025-01-01T10:00:00Z"
|
|
227
|
-
},
|
|
228
|
-
false,
|
|
229
|
-
{
|
|
230
|
-
schemaDict: {
|
|
231
|
-
created_at: {
|
|
232
|
-
type: Date
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
expect(result).toContain("2025-01-01 10:00:00");
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
});
|
package/tests/mysqlMock.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
const mockExecute = jest.fn();
|
|
2
|
-
const mockEnd = jest.fn((callback) => { if (callback) callback(null); });
|
|
3
|
-
|
|
4
|
-
const mockPool = {
|
|
5
|
-
promise: () => ({
|
|
6
|
-
execute: mockExecute
|
|
7
|
-
}),
|
|
8
|
-
end: mockEnd
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
jest.mock('mysql2', () => {
|
|
12
|
-
// Le require est fait à l'intérieur du callback au moment de l'exécution
|
|
13
|
-
const mysql2Actual = jest.requireActual('mysql2');
|
|
14
|
-
|
|
15
|
-
return {
|
|
16
|
-
createPool: jest.fn(() => mockPool),
|
|
17
|
-
escape: mysql2Actual.escape,
|
|
18
|
-
escapeId: mysql2Actual.escapeId
|
|
19
|
-
};
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
module.exports = { mockExecute, mockEnd, mockPool };
|
package/tests/safe.test.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const { getSafe, setSafe } = require('../src/utils/security/safe');
|
|
2
|
-
|
|
3
|
-
describe('Utils - safe.js', () => {
|
|
4
|
-
describe('getSafe', () => {
|
|
5
|
-
test('Devrait lire une propriété existante valide', () => {
|
|
6
|
-
const obj = { name: 'Alice' };
|
|
7
|
-
expect(getSafe(obj, 'name')).toBe('Alice');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test('Devrait renvoyer undefined pour une propriété absente', () => {
|
|
11
|
-
const obj = { name: 'Alice' };
|
|
12
|
-
expect(getSafe(obj, 'age')).toBeUndefined();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
test('Devrait bloquer l’accès aux propriétés interdites (Pollution de Prototype)', () => {
|
|
16
|
-
const obj = {};
|
|
17
|
-
expect(getSafe(obj, '__proto__')).toBeUndefined();
|
|
18
|
-
expect(getSafe(obj, 'constructor')).toBeUndefined();
|
|
19
|
-
expect(getSafe(obj, 'prototype')).toBeUndefined();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('Devrait gérer un objet null ou indéfini sans lever d’erreur', () => {
|
|
23
|
-
expect(getSafe(null, 'name')).toBeUndefined();
|
|
24
|
-
expect(getSafe(undefined, 'name')).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
describe('setSafe', () => {
|
|
29
|
-
test('Devrait assigner une valeur à une clé valide', () => {
|
|
30
|
-
const obj = {};
|
|
31
|
-
const result = setSafe(obj, 'age', 30);
|
|
32
|
-
expect(result).toBe(true);
|
|
33
|
-
expect(obj.age).toBe(30);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('Devrait refuser d’assigner des clés interdites et renvoyer false', () => {
|
|
37
|
-
const obj = {};
|
|
38
|
-
expect(setSafe(obj, '__proto__', { polluted: true })).toBe(false);
|
|
39
|
-
expect(setSafe(obj, 'constructor', {})).toBe(false);
|
|
40
|
-
expect(setSafe(obj, 'prototype', {})).toBe(false);
|
|
41
|
-
expect(obj.__proto__.polluted).toBeUndefined();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('Devrait renvoyer false si l’objet cible n’est pas valide', () => {
|
|
45
|
-
expect(setSafe(null, 'key', 'val')).toBe(false);
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
});
|
package/tests/sql.test.js
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
const { escapeIdentifier, escapeIdentifierList, escapeValue, escapeOrderDirection } = require('../src/utils/sql');
|
|
2
|
-
|
|
3
|
-
describe('Utils - sql.js', () => {
|
|
4
|
-
describe('escapeIdentifier', () => {
|
|
5
|
-
test('Devrait renvoyer "*" inchangé', () => {
|
|
6
|
-
expect(escapeIdentifier('*')).toBe('*');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
test('Devrait formater un identifiant simple avec des backticks', () => {
|
|
10
|
-
expect(escapeIdentifier('users')).toBe('`users`');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test('Devrait nettoyer les backticks existants (normalisation)', () => {
|
|
14
|
-
expect(escapeIdentifier('`users`')).toBe('`users`');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('Devrait gérer les identifiants composites sépares par un point', () => {
|
|
18
|
-
expect(escapeIdentifier('users.id')).toBe('`users`.`id`');
|
|
19
|
-
expect(escapeIdentifier('users.*')).toBe('`users`.*');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('Devrait lever une erreur si l’identifiant n’est pas une chaîne de caractères ou vide', () => {
|
|
23
|
-
expect(() => escapeIdentifier('')).toThrow('Invalid SQL identifier');
|
|
24
|
-
expect(() => escapeIdentifier(null)).toThrow('Invalid SQL identifier');
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('Devrait lever une erreur en cas de tentative d’injection de caractères non autorisés', () => {
|
|
28
|
-
expect(() => escapeIdentifier('users; DROP TABLE users;')).toThrow('Invalid SQL identifier');
|
|
29
|
-
expect(() => escapeIdentifier('users-table')).toThrow('Invalid SQL identifier');
|
|
30
|
-
expect(() => escapeIdentifier('users.id;--')).toThrow('Invalid SQL identifier');
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('escapeIdentifierList', () => {
|
|
35
|
-
test('Devrait joindre et échapper une liste d’identifiants', () => {
|
|
36
|
-
expect(escapeIdentifierList(['id', 'email'])).toBe('`id`, `email`');
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
describe('escapeValue', () => {
|
|
41
|
-
test('Devrait déléguer l’échappement de valeurs de manière sécurisée', () => {
|
|
42
|
-
expect(escapeValue("John's")).toBe("'John\\'s'");
|
|
43
|
-
expect(escapeValue(42)).toBe('42');
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('escapeOrderDirection', () => {
|
|
48
|
-
test('Devrait normaliser en majuscule ASC et DESC', () => {
|
|
49
|
-
expect(escapeOrderDirection('asc')).toBe('ASC');
|
|
50
|
-
expect(escapeOrderDirection('DESC')).toBe('DESC');
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('Devrait retourner ASC par défaut si null ou undefined', () => {
|
|
54
|
-
expect(escapeOrderDirection(null)).toBe('ASC');
|
|
55
|
-
expect(escapeOrderDirection(undefined)).toBe('ASC');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('Devrait lever une erreur pour toute direction invalide', () => {
|
|
59
|
-
expect(() => escapeOrderDirection('INJECTION;')).toThrow('Invalid SQL sort direction');
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
});
|
package/tests/sqlTypeMap.test.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const { sqlTypeMap } = require('../src/utils/sqlTypeMap');
|
|
2
|
-
|
|
3
|
-
describe('Utils - sqlTypeMap.js', () => {
|
|
4
|
-
test('Devrait posséder les correspondances de types standards indispensables', () => {
|
|
5
|
-
expect(sqlTypeMap.String).toBe('VARCHAR');
|
|
6
|
-
expect(sqlTypeMap.Number).toBe('INT');
|
|
7
|
-
expect(sqlTypeMap.Boolean).toBe('BOOLEAN');
|
|
8
|
-
expect(sqlTypeMap.Date).toBe('DATETIME');
|
|
9
|
-
expect(sqlTypeMap.Object).toBe('JSON');
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('Devrait retourner les valeurs temporelles par défaut configurées', () => {
|
|
13
|
-
expect(sqlTypeMap.Now).toBe('NOW()');
|
|
14
|
-
expect(sqlTypeMap.CurrentTimestamp).toBe('CURRENT_TIMESTAMP');
|
|
15
|
-
});
|
|
16
|
-
});
|