@teleporthq/teleport-plugin-next-data-source 0.42.8 → 0.42.10
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/__tests__/csv-header-detection.test.ts +212 -0
- package/__tests__/validation.test.ts +33 -2
- package/dist/cjs/data-source-fetchers.d.ts +2 -2
- package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
- package/dist/cjs/data-source-fetchers.js +30 -7
- package/dist/cjs/data-source-fetchers.js.map +1 -1
- package/dist/cjs/fetchers/airtable.d.ts.map +1 -1
- package/dist/cjs/fetchers/airtable.js +2 -2
- package/dist/cjs/fetchers/airtable.js.map +1 -1
- package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/cjs/fetchers/clickhouse.js +1 -1
- package/dist/cjs/fetchers/clickhouse.js.map +1 -1
- package/dist/cjs/fetchers/csv-file.d.ts.map +1 -1
- package/dist/cjs/fetchers/csv-file.js +23 -3
- package/dist/cjs/fetchers/csv-file.js.map +1 -1
- package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
- package/dist/cjs/fetchers/firestore.js +1 -1
- package/dist/cjs/fetchers/firestore.js.map +1 -1
- package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -1
- package/dist/cjs/fetchers/google-sheets.js +6 -1
- package/dist/cjs/fetchers/google-sheets.js.map +1 -1
- package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
- package/dist/cjs/fetchers/javascript.js +2 -1
- package/dist/cjs/fetchers/javascript.js.map +1 -1
- package/dist/cjs/fetchers/mariadb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mariadb.js +3 -3
- package/dist/cjs/fetchers/mariadb.js.map +1 -1
- package/dist/cjs/fetchers/mongodb.d.ts +1 -1
- package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
- package/dist/cjs/fetchers/mongodb.js +11 -3
- package/dist/cjs/fetchers/mongodb.js.map +1 -1
- package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
- package/dist/cjs/fetchers/mysql.js +2 -2
- package/dist/cjs/fetchers/mysql.js.map +1 -1
- package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
- package/dist/cjs/fetchers/postgresql.js +3 -3
- package/dist/cjs/fetchers/postgresql.js.map +1 -1
- package/dist/cjs/fetchers/redis.d.ts.map +1 -1
- package/dist/cjs/fetchers/redis.js +1 -1
- package/dist/cjs/fetchers/redis.js.map +1 -1
- package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
- package/dist/cjs/fetchers/redshift.js +2 -2
- package/dist/cjs/fetchers/redshift.js.map +1 -1
- package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
- package/dist/cjs/fetchers/rest-api.js +3 -2
- package/dist/cjs/fetchers/rest-api.js.map +1 -1
- package/dist/cjs/fetchers/static-collection.d.ts.map +1 -1
- package/dist/cjs/fetchers/static-collection.js +2 -1
- package/dist/cjs/fetchers/static-collection.js.map +1 -1
- package/dist/cjs/fetchers/supabase.d.ts.map +1 -1
- package/dist/cjs/fetchers/supabase.js +2 -2
- package/dist/cjs/fetchers/supabase.js.map +1 -1
- package/dist/cjs/fetchers/turso.d.ts.map +1 -1
- package/dist/cjs/fetchers/turso.js +1 -1
- package/dist/cjs/fetchers/turso.js.map +1 -1
- package/dist/cjs/fetchers/utils/header-detection.d.ts +2 -0
- package/dist/cjs/fetchers/utils/header-detection.d.ts.map +1 -0
- package/dist/cjs/fetchers/utils/header-detection.js +8 -0
- package/dist/cjs/fetchers/utils/header-detection.js.map +1 -0
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +168 -4
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/pagination-plugin.d.ts.map +1 -1
- package/dist/cjs/pagination-plugin.js +320 -65
- package/dist/cjs/pagination-plugin.js.map +1 -1
- package/dist/cjs/tsconfig.tsbuildinfo +1 -1
- package/dist/cjs/utils.d.ts +3 -0
- package/dist/cjs/utils.d.ts.map +1 -1
- package/dist/cjs/utils.js +218 -46
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/data-source-fetchers.d.ts +2 -2
- package/dist/esm/data-source-fetchers.d.ts.map +1 -1
- package/dist/esm/data-source-fetchers.js +29 -6
- package/dist/esm/data-source-fetchers.js.map +1 -1
- package/dist/esm/fetchers/airtable.d.ts.map +1 -1
- package/dist/esm/fetchers/airtable.js +3 -3
- package/dist/esm/fetchers/airtable.js.map +1 -1
- package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
- package/dist/esm/fetchers/clickhouse.js +2 -2
- package/dist/esm/fetchers/clickhouse.js.map +1 -1
- package/dist/esm/fetchers/csv-file.d.ts.map +1 -1
- package/dist/esm/fetchers/csv-file.js +23 -3
- package/dist/esm/fetchers/csv-file.js.map +1 -1
- package/dist/esm/fetchers/firestore.d.ts.map +1 -1
- package/dist/esm/fetchers/firestore.js +2 -2
- package/dist/esm/fetchers/firestore.js.map +1 -1
- package/dist/esm/fetchers/google-sheets.d.ts.map +1 -1
- package/dist/esm/fetchers/google-sheets.js +6 -1
- package/dist/esm/fetchers/google-sheets.js.map +1 -1
- package/dist/esm/fetchers/javascript.d.ts.map +1 -1
- package/dist/esm/fetchers/javascript.js +2 -1
- package/dist/esm/fetchers/javascript.js.map +1 -1
- package/dist/esm/fetchers/mariadb.d.ts.map +1 -1
- package/dist/esm/fetchers/mariadb.js +4 -4
- package/dist/esm/fetchers/mariadb.js.map +1 -1
- package/dist/esm/fetchers/mongodb.d.ts +1 -1
- package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
- package/dist/esm/fetchers/mongodb.js +12 -4
- package/dist/esm/fetchers/mongodb.js.map +1 -1
- package/dist/esm/fetchers/mysql.d.ts.map +1 -1
- package/dist/esm/fetchers/mysql.js +3 -3
- package/dist/esm/fetchers/mysql.js.map +1 -1
- package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
- package/dist/esm/fetchers/postgresql.js +4 -4
- package/dist/esm/fetchers/postgresql.js.map +1 -1
- package/dist/esm/fetchers/redis.d.ts.map +1 -1
- package/dist/esm/fetchers/redis.js +2 -2
- package/dist/esm/fetchers/redis.js.map +1 -1
- package/dist/esm/fetchers/redshift.d.ts.map +1 -1
- package/dist/esm/fetchers/redshift.js +3 -3
- package/dist/esm/fetchers/redshift.js.map +1 -1
- package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
- package/dist/esm/fetchers/rest-api.js +3 -2
- package/dist/esm/fetchers/rest-api.js.map +1 -1
- package/dist/esm/fetchers/static-collection.d.ts.map +1 -1
- package/dist/esm/fetchers/static-collection.js +2 -1
- package/dist/esm/fetchers/static-collection.js.map +1 -1
- package/dist/esm/fetchers/supabase.d.ts.map +1 -1
- package/dist/esm/fetchers/supabase.js +3 -3
- package/dist/esm/fetchers/supabase.js.map +1 -1
- package/dist/esm/fetchers/turso.d.ts.map +1 -1
- package/dist/esm/fetchers/turso.js +2 -2
- package/dist/esm/fetchers/turso.js.map +1 -1
- package/dist/esm/fetchers/utils/header-detection.d.ts +2 -0
- package/dist/esm/fetchers/utils/header-detection.d.ts.map +1 -0
- package/dist/esm/fetchers/utils/header-detection.js +4 -0
- package/dist/esm/fetchers/utils/header-detection.js.map +1 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +169 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/pagination-plugin.d.ts.map +1 -1
- package/dist/esm/pagination-plugin.js +320 -65
- package/dist/esm/pagination-plugin.js.map +1 -1
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/dist/esm/utils.d.ts +3 -0
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/esm/utils.js +214 -45
- package/dist/esm/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/data-source-fetchers.ts +29 -13
- package/src/fetchers/airtable.ts +81 -31
- package/src/fetchers/clickhouse.ts +88 -19
- package/src/fetchers/csv-file.ts +256 -27
- package/src/fetchers/firestore.ts +65 -13
- package/src/fetchers/google-sheets.ts +243 -26
- package/src/fetchers/javascript.ts +106 -23
- package/src/fetchers/mariadb.ts +85 -26
- package/src/fetchers/mongodb.ts +156 -37
- package/src/fetchers/mysql.ts +86 -26
- package/src/fetchers/postgresql.ts +89 -27
- package/src/fetchers/redis.ts +43 -5
- package/src/fetchers/redshift.ts +87 -18
- package/src/fetchers/rest-api.ts +105 -24
- package/src/fetchers/static-collection.ts +100 -18
- package/src/fetchers/supabase.ts +178 -54
- package/src/fetchers/turso.ts +87 -18
- package/src/fetchers/utils/header-detection.ts +200 -0
- package/src/index.ts +248 -2
- package/src/pagination-plugin.ts +708 -191
- package/src/utils.ts +374 -38
package/src/fetchers/mariadb.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
replaceSecretReference,
|
|
3
|
+
generateDateFormatterCode,
|
|
4
|
+
generateSafeJSONParseCode,
|
|
5
|
+
} from '../utils'
|
|
2
6
|
|
|
3
7
|
interface MariaDBConfig {
|
|
4
8
|
host?: string
|
|
@@ -20,6 +24,62 @@ export const generateMariaDBFetcher = (
|
|
|
20
24
|
|
|
21
25
|
return `import mariadb from 'mariadb'
|
|
22
26
|
|
|
27
|
+
${generateSafeJSONParseCode()}
|
|
28
|
+
|
|
29
|
+
// Helper function to process filters and build conditions
|
|
30
|
+
const processFilters = (filters, conditions, queryParams) => {
|
|
31
|
+
if (!filters) return
|
|
32
|
+
|
|
33
|
+
const parsedFilters = safeJSONParse(filters)
|
|
34
|
+
|
|
35
|
+
if (Array.isArray(parsedFilters)) {
|
|
36
|
+
parsedFilters.forEach((filter) => {
|
|
37
|
+
if (!filter.source || filter.destination === undefined) return
|
|
38
|
+
|
|
39
|
+
const field = \`\\\`\${filter.source}\\\`\`
|
|
40
|
+
const value = filter.destination
|
|
41
|
+
const operand = filter.operand || '='
|
|
42
|
+
|
|
43
|
+
if (Array.isArray(value)) {
|
|
44
|
+
if (value.length === 0) return
|
|
45
|
+
const placeholders = value.map(() => '?').join(', ')
|
|
46
|
+
queryParams.push(...value)
|
|
47
|
+
if (operand === '!=') {
|
|
48
|
+
conditions.push(\`\${field} NOT IN (\${placeholders})\`)
|
|
49
|
+
} else {
|
|
50
|
+
conditions.push(\`\${field} IN (\${placeholders})\`)
|
|
51
|
+
}
|
|
52
|
+
} else {
|
|
53
|
+
if (value === null) {
|
|
54
|
+
if (operand === '=') {
|
|
55
|
+
conditions.push(\`\${field} IS NULL\`)
|
|
56
|
+
} else if (operand === '!=') {
|
|
57
|
+
conditions.push(\`\${field} IS NOT NULL\`)
|
|
58
|
+
}
|
|
59
|
+
} else {
|
|
60
|
+
const validOps = ['=', '!=', '>', '<', '>=', '<=']
|
|
61
|
+
const sqlOperator = validOps.includes(operand) ? operand : '='
|
|
62
|
+
conditions.push(\`\${field} \${sqlOperator} ?\`)
|
|
63
|
+
queryParams.push(value)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
} else {
|
|
68
|
+
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
69
|
+
if (Array.isArray(value)) {
|
|
70
|
+
const placeholders = value.map(() => '?').join(', ')
|
|
71
|
+
queryParams.push(...value)
|
|
72
|
+
conditions.push(\`\\\`\${key}\\\` IN (\${placeholders})\`)
|
|
73
|
+
} else {
|
|
74
|
+
conditions.push(\`\\\`\${key}\\\` = ?\`)
|
|
75
|
+
queryParams.push(value)
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
${generateDateFormatterCode()}
|
|
82
|
+
|
|
23
83
|
export default async function handler(req, res) {
|
|
24
84
|
let connection = null
|
|
25
85
|
try {
|
|
@@ -52,7 +112,7 @@ export default async function handler(req, res) {
|
|
|
52
112
|
}
|
|
53
113
|
})
|
|
54
114
|
|
|
55
|
-
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
|
|
115
|
+
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query
|
|
56
116
|
|
|
57
117
|
const conditions = []
|
|
58
118
|
const queryParams = []
|
|
@@ -62,7 +122,7 @@ export default async function handler(req, res) {
|
|
|
62
122
|
|
|
63
123
|
if (queryColumns) {
|
|
64
124
|
// Use specified columns
|
|
65
|
-
columns =
|
|
125
|
+
columns = safeJSONParse(queryColumns)
|
|
66
126
|
} else {
|
|
67
127
|
// Fallback: Get all columns from information_schema
|
|
68
128
|
try {
|
|
@@ -86,19 +146,8 @@ export default async function handler(req, res) {
|
|
|
86
146
|
}
|
|
87
147
|
}
|
|
88
148
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
92
|
-
if (Array.isArray(value)) {
|
|
93
|
-
const placeholders = value.map(() => '?').join(', ')
|
|
94
|
-
queryParams.push(...value)
|
|
95
|
-
conditions.push(\`\\\`\${key}\\\` IN (\${placeholders})\`)
|
|
96
|
-
} else {
|
|
97
|
-
conditions.push(\`\\\`\${key}\\\` = ?\`)
|
|
98
|
-
queryParams.push(value)
|
|
99
|
-
}
|
|
100
|
-
})
|
|
101
|
-
}
|
|
149
|
+
// Apply filters using helper function
|
|
150
|
+
processFilters(filters, conditions, queryParams)
|
|
102
151
|
|
|
103
152
|
let sql = \`SELECT * FROM \\\`${tableName}\\\`\`
|
|
104
153
|
|
|
@@ -106,7 +155,21 @@ export default async function handler(req, res) {
|
|
|
106
155
|
sql += \` WHERE \${conditions.join(' AND ')}\`
|
|
107
156
|
}
|
|
108
157
|
|
|
109
|
-
|
|
158
|
+
// Handle sorts - new array format
|
|
159
|
+
if (sorts) {
|
|
160
|
+
const parsedSorts = safeJSONParse(sorts)
|
|
161
|
+
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
|
|
162
|
+
const orderClauses = parsedSorts.map((sort) => {
|
|
163
|
+
if (!sort.field) return null
|
|
164
|
+
const order = sort.order?.toUpperCase() === 'DESC' ? 'DESC' : 'ASC'
|
|
165
|
+
return \`\\\`\${sort.field}\\\` \${order}\`
|
|
166
|
+
}).filter(Boolean)
|
|
167
|
+
|
|
168
|
+
if (orderClauses.length > 0) {
|
|
169
|
+
sql += \` ORDER BY \${orderClauses.join(', ')}\`
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} else if (sortBy) {
|
|
110
173
|
sql += \` ORDER BY \\\`\${sortBy}\\\` \${sortOrder?.toUpperCase() || 'ASC'}\`
|
|
111
174
|
}
|
|
112
175
|
|
|
@@ -126,7 +189,7 @@ export default async function handler(req, res) {
|
|
|
126
189
|
const plainRows = rowArray.map((row) =>
|
|
127
190
|
row && typeof row.toJSON === 'function' ? row.toJSON() : row
|
|
128
191
|
)
|
|
129
|
-
const safeData = JSON.parse(JSON.stringify(plainRows))
|
|
192
|
+
const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
|
|
130
193
|
|
|
131
194
|
return res.status(200).json({
|
|
132
195
|
success: true,
|
|
@@ -203,7 +266,8 @@ async function getCount(req, res) {
|
|
|
203
266
|
|
|
204
267
|
if (queryColumns) {
|
|
205
268
|
// Use specified columns
|
|
206
|
-
|
|
269
|
+
const parsed = safeJSONParse(queryColumns)
|
|
270
|
+
columns = Array.isArray(parsed) ? parsed : [parsed]
|
|
207
271
|
} else {
|
|
208
272
|
// Fallback: Get all columns from information_schema
|
|
209
273
|
try {
|
|
@@ -227,13 +291,8 @@ async function getCount(req, res) {
|
|
|
227
291
|
}
|
|
228
292
|
}
|
|
229
293
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
for (const filter of parsedFilters) {
|
|
233
|
-
conditions.push(\`\${filter.column} \${filter.operator} ?\`)
|
|
234
|
-
queryParams.push(filter.value)
|
|
235
|
-
}
|
|
236
|
-
}
|
|
294
|
+
// Apply filters using helper function
|
|
295
|
+
processFilters(filters, conditions, queryParams)
|
|
237
296
|
|
|
238
297
|
let countSql = \`SELECT COUNT(*) as count FROM ${tableName}\`
|
|
239
298
|
if (conditions.length > 0) {
|
package/src/fetchers/mongodb.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
replaceSecretReference,
|
|
3
|
+
generateDateFormatterCode,
|
|
4
|
+
generateSafeJSONParseCode,
|
|
5
|
+
} from '../utils'
|
|
2
6
|
|
|
3
7
|
export const validateMongoDBConfig = (
|
|
4
8
|
config: Record<string, unknown>
|
|
@@ -67,6 +71,101 @@ export const generateMongoDBFetcher = (
|
|
|
67
71
|
|
|
68
72
|
return `import { MongoClient, ObjectId } from 'mongodb'
|
|
69
73
|
|
|
74
|
+
${generateSafeJSONParseCode()}
|
|
75
|
+
|
|
76
|
+
// Helper function to process filters
|
|
77
|
+
const processFilters = (filters, filter) => {
|
|
78
|
+
if (!filters) return
|
|
79
|
+
|
|
80
|
+
const parsedFilters = safeJSONParse(filters)
|
|
81
|
+
|
|
82
|
+
if (Array.isArray(parsedFilters)) {
|
|
83
|
+
parsedFilters.forEach((filterItem) => {
|
|
84
|
+
if (!filterItem.source || filterItem.destination === undefined) return
|
|
85
|
+
|
|
86
|
+
const field = filterItem.source
|
|
87
|
+
const value = filterItem.destination
|
|
88
|
+
const operand = filterItem.operand || '='
|
|
89
|
+
|
|
90
|
+
// Handle _id specially
|
|
91
|
+
const processValue = (v) => {
|
|
92
|
+
if (field === '_id' && typeof v === 'string') {
|
|
93
|
+
try {
|
|
94
|
+
return new ObjectId(v)
|
|
95
|
+
} catch (e) {
|
|
96
|
+
return v
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return v
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (Array.isArray(value)) {
|
|
103
|
+
const processedValues = value.map(processValue)
|
|
104
|
+
if (operand === '!=') {
|
|
105
|
+
filter[field] = { $nin: processedValues }
|
|
106
|
+
} else {
|
|
107
|
+
filter[field] = { $in: processedValues }
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
const processedValue = processValue(value)
|
|
111
|
+
|
|
112
|
+
// Handle null values
|
|
113
|
+
if (processedValue === null) {
|
|
114
|
+
if (operand === '=') {
|
|
115
|
+
filter[field] = null
|
|
116
|
+
} else if (operand === '!=') {
|
|
117
|
+
filter[field] = { $ne: null }
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
// Map operand to MongoDB operators
|
|
121
|
+
switch (operand) {
|
|
122
|
+
case '=':
|
|
123
|
+
filter[field] = processedValue
|
|
124
|
+
break
|
|
125
|
+
case '!=':
|
|
126
|
+
filter[field] = { $ne: processedValue }
|
|
127
|
+
break
|
|
128
|
+
case '>':
|
|
129
|
+
filter[field] = { $gt: processedValue }
|
|
130
|
+
break
|
|
131
|
+
case '>=':
|
|
132
|
+
filter[field] = { $gte: processedValue }
|
|
133
|
+
break
|
|
134
|
+
case '<':
|
|
135
|
+
filter[field] = { $lt: processedValue }
|
|
136
|
+
break
|
|
137
|
+
case '<=':
|
|
138
|
+
filter[field] = { $lte: processedValue }
|
|
139
|
+
break
|
|
140
|
+
default:
|
|
141
|
+
filter[field] = processedValue
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
} else {
|
|
147
|
+
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
148
|
+
if (key === '_id') {
|
|
149
|
+
if (Array.isArray(value)) {
|
|
150
|
+
filter[key] = {
|
|
151
|
+
$in: value.map((id) => (typeof id === 'string' ? new ObjectId(id) : id))
|
|
152
|
+
}
|
|
153
|
+
} else if (typeof value === 'string') {
|
|
154
|
+
filter[key] = new ObjectId(value)
|
|
155
|
+
} else {
|
|
156
|
+
filter[key] = value
|
|
157
|
+
}
|
|
158
|
+
} else if (Array.isArray(value)) {
|
|
159
|
+
filter[key] = { $in: value }
|
|
160
|
+
} else {
|
|
161
|
+
filter[key] = value
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
${generateDateFormatterCode()}
|
|
168
|
+
|
|
70
169
|
export default async function handler(req, res) {
|
|
71
170
|
let client = null
|
|
72
171
|
try {
|
|
@@ -80,7 +179,7 @@ export default async function handler(req, res) {
|
|
|
80
179
|
const db = client.db(${JSON.stringify(database)})
|
|
81
180
|
const collection = db.collection('${tableName}')
|
|
82
181
|
|
|
83
|
-
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
|
|
182
|
+
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query
|
|
84
183
|
|
|
85
184
|
const filter = {}
|
|
86
185
|
|
|
@@ -89,7 +188,7 @@ export default async function handler(req, res) {
|
|
|
89
188
|
|
|
90
189
|
if (queryColumns) {
|
|
91
190
|
// Use specified columns
|
|
92
|
-
columns =
|
|
191
|
+
columns = safeJSONParse(queryColumns)
|
|
93
192
|
} else {
|
|
94
193
|
// Fallback: Get all field names from a sample document
|
|
95
194
|
try {
|
|
@@ -111,30 +210,26 @@ export default async function handler(req, res) {
|
|
|
111
210
|
}
|
|
112
211
|
}
|
|
113
212
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
117
|
-
if (key === '_id') {
|
|
118
|
-
if (Array.isArray(value)) {
|
|
119
|
-
filter[key] = {
|
|
120
|
-
$in: value.map((id) => (typeof id === 'string' ? new ObjectId(id) : id))
|
|
121
|
-
}
|
|
122
|
-
} else if (typeof value === 'string') {
|
|
123
|
-
filter[key] = new ObjectId(value)
|
|
124
|
-
} else {
|
|
125
|
-
filter[key] = value
|
|
126
|
-
}
|
|
127
|
-
} else if (Array.isArray(value)) {
|
|
128
|
-
filter[key] = { $in: value }
|
|
129
|
-
} else {
|
|
130
|
-
filter[key] = value
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
}
|
|
213
|
+
// Apply filters using helper function
|
|
214
|
+
processFilters(filters, filter)
|
|
134
215
|
|
|
135
216
|
let cursor = collection.find(filter)
|
|
136
217
|
|
|
137
|
-
|
|
218
|
+
// Handle sorts - new array format
|
|
219
|
+
if (sorts) {
|
|
220
|
+
const parsedSorts = safeJSONParse(sorts)
|
|
221
|
+
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
|
|
222
|
+
const sortObject = {}
|
|
223
|
+
parsedSorts.forEach((sort) => {
|
|
224
|
+
if (sort.field) {
|
|
225
|
+
sortObject[sort.field] = sort.order?.toLowerCase() === 'desc' ? -1 : 1
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
if (Object.keys(sortObject).length > 0) {
|
|
229
|
+
cursor = cursor.sort(sortObject)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
} else if (sortBy) {
|
|
138
233
|
const sortOrderValue = sortOrder?.toLowerCase() === 'desc' ? -1 : 1
|
|
139
234
|
cursor = cursor.sort({ [sortBy]: sortOrderValue })
|
|
140
235
|
}
|
|
@@ -151,7 +246,7 @@ export default async function handler(req, res) {
|
|
|
151
246
|
}
|
|
152
247
|
|
|
153
248
|
const documents = await cursor.toArray()
|
|
154
|
-
const safeData = JSON.parse(JSON.stringify(documents))
|
|
249
|
+
const safeData = JSON.parse(JSON.stringify(documents, dateReplacer))
|
|
155
250
|
|
|
156
251
|
return res.status(200).json({
|
|
157
252
|
success: true,
|
|
@@ -179,15 +274,34 @@ export default async function handler(req, res) {
|
|
|
179
274
|
}
|
|
180
275
|
|
|
181
276
|
// tslint:disable-next-line:variable-name
|
|
182
|
-
export const generateMongoDBCountFetcher = (
|
|
277
|
+
export const generateMongoDBCountFetcher = (config: any, tableName: string): string => {
|
|
278
|
+
const mongoConfig = config as MongoDBConfig
|
|
279
|
+
const hasUsername = mongoConfig?.username
|
|
280
|
+
const database = mongoConfig?.database
|
|
281
|
+
|
|
282
|
+
// Build connection string from parts if not provided
|
|
283
|
+
let connectionString = mongoConfig.connectionString
|
|
284
|
+
if (!connectionString) {
|
|
285
|
+
connectionString = `mongodb://${
|
|
286
|
+
hasUsername ? `${mongoConfig.username}:${mongoConfig.password}@` : ''
|
|
287
|
+
}${mongoConfig.host}:${mongoConfig.port || 27017}/${database}`
|
|
288
|
+
}
|
|
289
|
+
|
|
183
290
|
return `
|
|
184
291
|
async function getCount(req, res) {
|
|
185
|
-
|
|
186
|
-
const db = client.db()
|
|
187
|
-
|
|
292
|
+
let client = null
|
|
188
293
|
try {
|
|
189
|
-
const
|
|
294
|
+
const url = ${replaceSecretReference(connectionString)}
|
|
295
|
+
client = new MongoClient(url, {
|
|
296
|
+
connectTimeoutMS: 30000,
|
|
297
|
+
serverSelectionTimeoutMS: 30000
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
await client.connect()
|
|
301
|
+
const db = client.db(${JSON.stringify(database)})
|
|
190
302
|
const collection = db.collection('${tableName}')
|
|
303
|
+
|
|
304
|
+
const { query, queryColumns, filters } = req.query
|
|
191
305
|
const filter = {}
|
|
192
306
|
|
|
193
307
|
if (query) {
|
|
@@ -195,7 +309,8 @@ async function getCount(req, res) {
|
|
|
195
309
|
|
|
196
310
|
if (queryColumns) {
|
|
197
311
|
// Use specified columns
|
|
198
|
-
|
|
312
|
+
const parsed = safeJSONParse(queryColumns)
|
|
313
|
+
columns = Array.isArray(parsed) ? parsed : [parsed]
|
|
199
314
|
} else {
|
|
200
315
|
// Fallback: Get all field names from a sample document
|
|
201
316
|
try {
|
|
@@ -216,12 +331,8 @@ async function getCount(req, res) {
|
|
|
216
331
|
}
|
|
217
332
|
}
|
|
218
333
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
for (const f of parsedFilters) {
|
|
222
|
-
filter[f.column] = f.value
|
|
223
|
-
}
|
|
224
|
-
}
|
|
334
|
+
// Apply filters using helper function
|
|
335
|
+
processFilters(filters, filter)
|
|
225
336
|
|
|
226
337
|
const count = await collection.countDocuments(filter)
|
|
227
338
|
|
|
@@ -237,6 +348,14 @@ async function getCount(req, res) {
|
|
|
237
348
|
error: error.message || 'Failed to get count',
|
|
238
349
|
timestamp: Date.now()
|
|
239
350
|
})
|
|
351
|
+
} finally {
|
|
352
|
+
if (client) {
|
|
353
|
+
try {
|
|
354
|
+
await client.close()
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error('Error closing MongoDB client:', error)
|
|
357
|
+
}
|
|
358
|
+
}
|
|
240
359
|
}
|
|
241
360
|
}
|
|
242
361
|
`
|
package/src/fetchers/mysql.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
replaceSecretReference,
|
|
3
|
+
generateDateFormatterCode,
|
|
4
|
+
generateSafeJSONParseCode,
|
|
5
|
+
} from '../utils'
|
|
2
6
|
|
|
3
7
|
interface MySQLConfig {
|
|
4
8
|
host?: string
|
|
@@ -57,11 +61,68 @@ const getConnection = () => {
|
|
|
57
61
|
})
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
${generateSafeJSONParseCode()}
|
|
65
|
+
|
|
66
|
+
// Helper function to process filters and build conditions
|
|
67
|
+
const processFilters = (filters, conditions, queryParams) => {
|
|
68
|
+
if (!filters) return
|
|
69
|
+
|
|
70
|
+
const parsedFilters = safeJSONParse(filters)
|
|
71
|
+
|
|
72
|
+
if (Array.isArray(parsedFilters)) {
|
|
73
|
+
parsedFilters.forEach((filter) => {
|
|
74
|
+
if (!filter.source || filter.destination === undefined) return
|
|
75
|
+
|
|
76
|
+
const field = mysql.escapeId(filter.source)
|
|
77
|
+
const value = filter.destination
|
|
78
|
+
const operand = filter.operand || '='
|
|
79
|
+
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
if (value.length === 0) return
|
|
82
|
+
const placeholders = value.map(() => '?').join(', ')
|
|
83
|
+
queryParams.push(...value)
|
|
84
|
+
if (operand === '!=') {
|
|
85
|
+
conditions.push(\`\${field} NOT IN (\${placeholders})\`)
|
|
86
|
+
} else {
|
|
87
|
+
conditions.push(\`\${field} IN (\${placeholders})\`)
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
if (value === null) {
|
|
91
|
+
if (operand === '=') {
|
|
92
|
+
conditions.push(\`\${field} IS NULL\`)
|
|
93
|
+
} else if (operand === '!=') {
|
|
94
|
+
conditions.push(\`\${field} IS NOT NULL\`)
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
// Validate operator to prevent SQL injection
|
|
98
|
+
const validOps = ['=', '!=', '>', '<', '>=', '<=']
|
|
99
|
+
const sqlOperator = validOps.includes(operand) ? operand : '='
|
|
100
|
+
conditions.push(\`\${field} \${sqlOperator} ?\`)
|
|
101
|
+
queryParams.push(value)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
} else {
|
|
106
|
+
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
107
|
+
if (Array.isArray(value)) {
|
|
108
|
+
const placeholders = value.map(() => '?').join(', ')
|
|
109
|
+
queryParams.push(...value)
|
|
110
|
+
conditions.push(\`\${mysql.escapeId(key)} IN (\${placeholders})\`)
|
|
111
|
+
} else {
|
|
112
|
+
conditions.push(\`\${mysql.escapeId(key)} = ?\`)
|
|
113
|
+
queryParams.push(value)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
${generateDateFormatterCode()}
|
|
120
|
+
|
|
60
121
|
export default async function handler(req, res) {
|
|
61
122
|
const connection = await getConnection()
|
|
62
123
|
|
|
63
124
|
try {
|
|
64
|
-
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
|
|
125
|
+
const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, sorts, offset } = req.query
|
|
65
126
|
|
|
66
127
|
const conditions = []
|
|
67
128
|
const queryParams = []
|
|
@@ -71,7 +132,7 @@ export default async function handler(req, res) {
|
|
|
71
132
|
|
|
72
133
|
if (queryColumns) {
|
|
73
134
|
// Use specified columns
|
|
74
|
-
columns =
|
|
135
|
+
columns = safeJSONParse(queryColumns)
|
|
75
136
|
} else {
|
|
76
137
|
// Fallback: Get all columns from information_schema
|
|
77
138
|
try {
|
|
@@ -95,19 +156,8 @@ export default async function handler(req, res) {
|
|
|
95
156
|
}
|
|
96
157
|
}
|
|
97
158
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
Object.entries(parsedFilters).forEach(([key, value]) => {
|
|
101
|
-
if (Array.isArray(value)) {
|
|
102
|
-
const placeholders = value.map(() => '?').join(', ')
|
|
103
|
-
queryParams.push(...value)
|
|
104
|
-
conditions.push(\`\${mysql.escapeId(key)} IN (\${placeholders})\`)
|
|
105
|
-
} else {
|
|
106
|
-
conditions.push(\`\${mysql.escapeId(key)} = ?\`)
|
|
107
|
-
queryParams.push(value)
|
|
108
|
-
}
|
|
109
|
-
})
|
|
110
|
-
}
|
|
159
|
+
// Apply filters using helper function
|
|
160
|
+
processFilters(filters, conditions, queryParams)
|
|
111
161
|
|
|
112
162
|
let sql = \`SELECT * FROM \${mysql.escapeId('${tableName}')}\`
|
|
113
163
|
|
|
@@ -115,7 +165,21 @@ export default async function handler(req, res) {
|
|
|
115
165
|
sql += \` WHERE \${conditions.join(' AND ')}\`
|
|
116
166
|
}
|
|
117
167
|
|
|
118
|
-
|
|
168
|
+
// Handle sorts - new array format
|
|
169
|
+
if (sorts) {
|
|
170
|
+
const parsedSorts = safeJSONParse(sorts)
|
|
171
|
+
if (Array.isArray(parsedSorts) && parsedSorts.length > 0) {
|
|
172
|
+
const orderClauses = parsedSorts.map((sort) => {
|
|
173
|
+
if (!sort.field) return null
|
|
174
|
+
const order = sort.order?.toUpperCase() === 'DESC' ? 'DESC' : 'ASC'
|
|
175
|
+
return \`\${mysql.escapeId(sort.field)} \${order}\`
|
|
176
|
+
}).filter(Boolean)
|
|
177
|
+
|
|
178
|
+
if (orderClauses.length > 0) {
|
|
179
|
+
sql += \` ORDER BY \${orderClauses.join(', ')}\`
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} else if (sortBy) {
|
|
119
183
|
sql += \` ORDER BY \${mysql.escapeId(sortBy)} \${sortOrder?.toUpperCase() || 'ASC'}\`
|
|
120
184
|
}
|
|
121
185
|
|
|
@@ -135,7 +199,7 @@ export default async function handler(req, res) {
|
|
|
135
199
|
const plainRows = rowArray.map((row) =>
|
|
136
200
|
row && typeof row.toJSON === 'function' ? row.toJSON() : row
|
|
137
201
|
)
|
|
138
|
-
const safeData = JSON.parse(JSON.stringify(plainRows))
|
|
202
|
+
const safeData = JSON.parse(JSON.stringify(plainRows, dateReplacer))
|
|
139
203
|
|
|
140
204
|
return res.status(200).json({
|
|
141
205
|
success: true,
|
|
@@ -182,7 +246,8 @@ async function getCount(req, res) {
|
|
|
182
246
|
|
|
183
247
|
if (queryColumns) {
|
|
184
248
|
// Use specified columns
|
|
185
|
-
|
|
249
|
+
const parsed = safeJSONParse(queryColumns)
|
|
250
|
+
columns = Array.isArray(parsed) ? parsed : [parsed]
|
|
186
251
|
} else {
|
|
187
252
|
// Fallback: Get all columns from information_schema
|
|
188
253
|
try {
|
|
@@ -206,13 +271,8 @@ async function getCount(req, res) {
|
|
|
206
271
|
}
|
|
207
272
|
}
|
|
208
273
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
for (const filter of parsedFilters) {
|
|
212
|
-
conditions.push(\`\${filter.column} \${filter.operator} ?\`)
|
|
213
|
-
queryParams.push(filter.value)
|
|
214
|
-
}
|
|
215
|
-
}
|
|
274
|
+
// Apply filters using helper function
|
|
275
|
+
processFilters(filters, conditions, queryParams)
|
|
216
276
|
|
|
217
277
|
let countSql = \`SELECT COUNT(*) as count FROM ${tableName}\`
|
|
218
278
|
if (conditions.length > 0) {
|