@teleporthq/teleport-plugin-next-data-source 0.42.1 → 0.42.3

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.
Files changed (59) hide show
  1. package/dist/cjs/count-fetchers.d.ts.map +1 -1
  2. package/dist/cjs/count-fetchers.js +1 -1
  3. package/dist/cjs/count-fetchers.js.map +1 -1
  4. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
  5. package/dist/cjs/fetchers/clickhouse.js +1 -1
  6. package/dist/cjs/fetchers/clickhouse.js.map +1 -1
  7. package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
  8. package/dist/cjs/fetchers/firestore.js +1 -1
  9. package/dist/cjs/fetchers/firestore.js.map +1 -1
  10. package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
  11. package/dist/cjs/fetchers/javascript.js +1 -1
  12. package/dist/cjs/fetchers/javascript.js.map +1 -1
  13. package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
  14. package/dist/cjs/fetchers/redshift.js +3 -1
  15. package/dist/cjs/fetchers/redshift.js.map +1 -1
  16. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  17. package/dist/cjs/fetchers/rest-api.js +2 -2
  18. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  19. package/dist/cjs/fetchers/turso.d.ts.map +1 -1
  20. package/dist/cjs/fetchers/turso.js +1 -1
  21. package/dist/cjs/fetchers/turso.js.map +1 -1
  22. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  23. package/dist/cjs/pagination-plugin.js +151 -119
  24. package/dist/cjs/pagination-plugin.js.map +1 -1
  25. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  26. package/dist/esm/count-fetchers.d.ts.map +1 -1
  27. package/dist/esm/count-fetchers.js +1 -1
  28. package/dist/esm/count-fetchers.js.map +1 -1
  29. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
  30. package/dist/esm/fetchers/clickhouse.js +1 -1
  31. package/dist/esm/fetchers/clickhouse.js.map +1 -1
  32. package/dist/esm/fetchers/firestore.d.ts.map +1 -1
  33. package/dist/esm/fetchers/firestore.js +1 -1
  34. package/dist/esm/fetchers/firestore.js.map +1 -1
  35. package/dist/esm/fetchers/javascript.d.ts.map +1 -1
  36. package/dist/esm/fetchers/javascript.js +1 -1
  37. package/dist/esm/fetchers/javascript.js.map +1 -1
  38. package/dist/esm/fetchers/redshift.d.ts.map +1 -1
  39. package/dist/esm/fetchers/redshift.js +3 -1
  40. package/dist/esm/fetchers/redshift.js.map +1 -1
  41. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  42. package/dist/esm/fetchers/rest-api.js +2 -2
  43. package/dist/esm/fetchers/rest-api.js.map +1 -1
  44. package/dist/esm/fetchers/turso.d.ts.map +1 -1
  45. package/dist/esm/fetchers/turso.js +1 -1
  46. package/dist/esm/fetchers/turso.js.map +1 -1
  47. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  48. package/dist/esm/pagination-plugin.js +151 -119
  49. package/dist/esm/pagination-plugin.js.map +1 -1
  50. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +2 -2
  52. package/src/count-fetchers.ts +2 -1
  53. package/src/fetchers/clickhouse.ts +12 -6
  54. package/src/fetchers/firestore.ts +45 -13
  55. package/src/fetchers/javascript.ts +48 -13
  56. package/src/fetchers/redshift.ts +32 -9
  57. package/src/fetchers/rest-api.ts +68 -6
  58. package/src/fetchers/turso.ts +46 -16
  59. package/src/pagination-plugin.ts +308 -257
@@ -85,12 +85,20 @@ export default async function handler(req, res) {
85
85
  })
86
86
  }
87
87
 
88
- if (query && queryColumns) {
89
- const columns = JSON.parse(queryColumns)
90
- for (const column of columns) {
91
- queryRef = queryRef
92
- .where(column, '>=', query)
93
- .where(column, '<=', query + '\\uf8ff')
88
+ let usePostFiltering = false
89
+
90
+ if (query) {
91
+ if (queryColumns) {
92
+ const columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
93
+ for (const column of columns) {
94
+ queryRef = queryRef
95
+ .where(column, '>=', query)
96
+ .where(column, '<=', query + '\\uf8ff')
97
+ }
98
+ } else {
99
+ // Firestore doesn't support full-text search without queryColumns
100
+ // We'll fetch all data and filter in JavaScript
101
+ usePostFiltering = true
94
102
  }
95
103
  }
96
104
 
@@ -100,17 +108,20 @@ export default async function handler(req, res) {
100
108
  }
101
109
 
102
110
  const limitValue = limit || perPage
103
- if (limitValue) {
104
- queryRef = queryRef.limit(parseInt(limitValue))
105
- }
106
-
107
111
  const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage && parseInt(page) > 1 ? (parseInt(page) - 1) * parseInt(perPage) : undefined)
108
- if (offsetValue !== undefined) {
109
- queryRef = queryRef.offset(offsetValue)
112
+
113
+ // Only apply pagination at query level if not post-filtering
114
+ if (!usePostFiltering) {
115
+ if (limitValue) {
116
+ queryRef = queryRef.limit(parseInt(limitValue))
117
+ }
118
+ if (offsetValue !== undefined) {
119
+ queryRef = queryRef.offset(offsetValue)
120
+ }
110
121
  }
111
122
 
112
123
  const snapshot = await queryRef.get()
113
- const documents = []
124
+ let documents = []
114
125
  snapshot.forEach((doc) => {
115
126
  documents.push({
116
127
  id: doc.id,
@@ -118,6 +129,27 @@ export default async function handler(req, res) {
118
129
  })
119
130
  })
120
131
 
132
+ // Apply post-filtering if needed
133
+ if (usePostFiltering && query) {
134
+ const searchQuery = query.toLowerCase()
135
+ documents = documents.filter((item) => {
136
+ try {
137
+ const stringified = JSON.stringify(item).toLowerCase()
138
+ return stringified.includes(searchQuery)
139
+ } catch {
140
+ return false
141
+ }
142
+ })
143
+
144
+ // Apply pagination after filtering
145
+ if (limitValue) {
146
+ const start = offsetValue || 0
147
+ documents = documents.slice(start, start + parseInt(limitValue))
148
+ } else if (offsetValue) {
149
+ documents = documents.slice(offsetValue)
150
+ }
151
+ }
152
+
121
153
  const safeData = JSON.parse(JSON.stringify(documents))
122
154
 
123
155
  return res.status(200).json({
@@ -37,28 +37,31 @@ export const generateJavaScriptFetcher = (config: Record<string, unknown>): stri
37
37
  const jsConfig = config as JavaScriptConfig
38
38
  return `export default async function handler(req, res) {
39
39
  try {
40
- const { limit, offset, page, perPage, query, queryColumns } = req.query
40
+ const { limit, offset, page, perPage, query, queryColumns, sortBy, sortOrder, filters } = req.query
41
41
 
42
42
  const code = ${JSON.stringify(jsConfig.code)}
43
43
  const executeCode = new Function('return ' + code)
44
44
  let data = executeCode()
45
45
 
46
46
  if (Array.isArray(data)) {
47
- if (query) {
47
+ // 1. Apply search filter
48
+ if (query && query.trim()) {
48
49
  const searchQuery = query.toLowerCase()
49
50
 
50
51
  if (queryColumns) {
51
- // Search specific columns
52
- const columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
53
- data = data.filter(item => {
54
- return columns.some(col => {
55
- const value = item[col]
56
- if (value === null || value === undefined) return false
57
- return String(value).toLowerCase().includes(searchQuery)
52
+ try {
53
+ const columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
54
+ data = data.filter(item => {
55
+ return columns.some(col => {
56
+ const value = item[col]
57
+ if (value === null || value === undefined) return false
58
+ return String(value).toLowerCase().includes(searchQuery)
59
+ })
58
60
  })
59
- })
61
+ } catch (err) {
62
+ console.error('Error parsing queryColumns:', err)
63
+ }
60
64
  } else {
61
- // Search across all fields by stringifying the entire record
62
65
  data = data.filter(item => {
63
66
  try {
64
67
  const stringified = JSON.stringify(item).toLowerCase()
@@ -70,11 +73,43 @@ export const generateJavaScriptFetcher = (config: Record<string, unknown>): stri
70
73
  }
71
74
  }
72
75
 
76
+ // 2. Apply custom filters
77
+ if (filters) {
78
+ try {
79
+ const parsedFilters = typeof filters === 'string' ? JSON.parse(filters) : filters
80
+ data = data.filter((item) => {
81
+ return Object.entries(parsedFilters).every(([key, value]) => {
82
+ if (Array.isArray(value)) {
83
+ return value.includes(item[key])
84
+ }
85
+ return item[key] === value
86
+ })
87
+ })
88
+ } catch (err) {
89
+ console.error('Error parsing filters:', err)
90
+ }
91
+ }
92
+
93
+ // 3. Apply sorting
94
+ if (sortBy && sortBy.trim()) {
95
+ data.sort((a, b) => {
96
+ const aVal = a[sortBy]
97
+ const bVal = b[sortBy]
98
+ const sortOrderValue = sortOrder?.toLowerCase() === 'desc' ? -1 : 1
99
+ if (aVal < bVal) return -sortOrderValue
100
+ if (aVal > bVal) return sortOrderValue
101
+ return 0
102
+ })
103
+ }
104
+
105
+ // 4. Apply pagination
73
106
  const limitValue = limit || perPage
74
- const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : 0)
107
+ const pageValue = page ? Math.max(1, parseInt(page)) : undefined
108
+ const offsetValue = offset !== undefined ? Math.max(0, parseInt(offset)) : (pageValue && perPage ? (pageValue - 1) * Math.max(1, parseInt(perPage)) : 0)
75
109
 
76
110
  if (limitValue) {
77
- data = data.slice(offsetValue, offsetValue + parseInt(limitValue))
111
+ const limitInt = Math.max(1, parseInt(limitValue))
112
+ data = data.slice(offsetValue, offsetValue + limitInt)
78
113
  } else if (offsetValue > 0) {
79
114
  data = data.slice(offsetValue)
80
115
  }
@@ -66,15 +66,38 @@ export default async function handler(req, res) {
66
66
  const queryParams = []
67
67
  let paramIndex = 1
68
68
 
69
- if (query && queryColumns) {
70
- const columns = JSON.parse(queryColumns)
71
- const searchConditions = columns.map((col) => {
72
- const condition = \`\${col}::text ILIKE $\${paramIndex}\`
73
- paramIndex++
74
- return condition
75
- })
76
- columns.forEach(() => queryParams.push(\`%\${query}%\`))
77
- conditions.push(\`(\${searchConditions.join(' OR ')})\`)
69
+ if (query) {
70
+ let columns = []
71
+
72
+ if (queryColumns) {
73
+ columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
74
+ } else {
75
+ // Fallback: Get all columns from information_schema
76
+ try {
77
+ const schemaQuery = 'SELECT column_name FROM information_schema.columns WHERE table_name = $1' +
78
+ ${schema ? `' AND table_schema = $2'` : `''`} +
79
+ ' ORDER BY ordinal_position'
80
+ const schemaParams = ${
81
+ schema
82
+ ? `[${JSON.stringify(tableName)}, ${JSON.stringify(schema)}]`
83
+ : `[${JSON.stringify(tableName)}]`
84
+ }
85
+ const schemaResult = await pool.query(schemaQuery, schemaParams)
86
+ columns = schemaResult.rows.map(row => row.column_name)
87
+ } catch (schemaError) {
88
+ console.warn('Failed to fetch column names from information_schema:', schemaError.message)
89
+ }
90
+ }
91
+
92
+ if (columns.length > 0) {
93
+ const searchConditions = columns.map((col) => {
94
+ const condition = \`\${col}::text ILIKE $\${paramIndex}\`
95
+ paramIndex++
96
+ return condition
97
+ })
98
+ columns.forEach(() => queryParams.push(\`%\${query}%\`))
99
+ conditions.push(\`(\${searchConditions.join(' OR ')})\`)
100
+ }
78
101
  }
79
102
 
80
103
  if (filters) {
@@ -77,7 +77,7 @@ export const generateRESTAPIFetcher = (config: Record<string, unknown>): string
77
77
 
78
78
  export default async function handler(req, res) {
79
79
  try {
80
- const { offset, limit } = req.query
80
+ const { query, queryColumns, limit, page, perPage, sortBy, sortOrder, filters, offset } = req.query
81
81
 
82
82
  const url = ${JSON.stringify(restConfig.url)}
83
83
  const method = ${JSON.stringify(restConfig.method || 'GET')}
@@ -116,13 +116,75 @@ export default async function handler(req, res) {
116
116
 
117
117
  let data = await response.json()
118
118
 
119
- // Apply offset and limit if data is an array and parameters are provided
119
+ // Apply filtering, sorting, and pagination if data is an array
120
120
  if (Array.isArray(data)) {
121
- const offsetValue = offset !== undefined ? parseInt(offset) : 0
122
- const limitValue = limit !== undefined ? parseInt(limit) : undefined
121
+ // 1. Apply search filter
122
+ if (query && query.trim()) {
123
+ const searchQuery = query.toLowerCase()
124
+
125
+ if (queryColumns) {
126
+ try {
127
+ const columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
128
+ data = data.filter((item) => {
129
+ return columns.some((col) => {
130
+ const value = item[col]
131
+ if (value === null || value === undefined) return false
132
+ return String(value).toLowerCase().includes(searchQuery)
133
+ })
134
+ })
135
+ } catch (err) {
136
+ console.error('Error parsing queryColumns:', err)
137
+ }
138
+ } else {
139
+ // Search across all fields
140
+ data = data.filter((item) => {
141
+ try {
142
+ const stringified = JSON.stringify(item).toLowerCase()
143
+ return stringified.includes(searchQuery)
144
+ } catch {
145
+ return false
146
+ }
147
+ })
148
+ }
149
+ }
150
+
151
+ // 2. Apply custom filters
152
+ if (filters) {
153
+ try {
154
+ const parsedFilters = typeof filters === 'string' ? JSON.parse(filters) : filters
155
+ data = data.filter((item) => {
156
+ return Object.entries(parsedFilters).every(([key, value]) => {
157
+ if (Array.isArray(value)) {
158
+ return value.includes(item[key])
159
+ }
160
+ return item[key] === value
161
+ })
162
+ })
163
+ } catch (err) {
164
+ console.error('Error parsing filters:', err)
165
+ }
166
+ }
167
+
168
+ // 3. Apply sorting
169
+ if (sortBy && sortBy.trim()) {
170
+ data.sort((a, b) => {
171
+ const aVal = a[sortBy]
172
+ const bVal = b[sortBy]
173
+ const sortOrderValue = sortOrder?.toLowerCase() === 'desc' ? -1 : 1
174
+ if (aVal < bVal) return -sortOrderValue
175
+ if (aVal > bVal) return sortOrderValue
176
+ return 0
177
+ })
178
+ }
179
+
180
+ // 4. Apply pagination
181
+ const limitValue = limit || perPage
182
+ const pageValue = page ? Math.max(1, parseInt(page)) : undefined
183
+ const offsetValue = offset !== undefined ? Math.max(0, parseInt(offset)) : (pageValue && perPage ? (pageValue - 1) * Math.max(1, parseInt(perPage)) : 0)
123
184
 
124
- if (limitValue !== undefined) {
125
- data = data.slice(offsetValue, offsetValue + limitValue)
185
+ if (limitValue) {
186
+ const limitInt = Math.max(1, parseInt(limitValue))
187
+ data = data.slice(offsetValue, offsetValue + limitInt)
126
188
  } else if (offsetValue > 0) {
127
189
  data = data.slice(offsetValue)
128
190
  }
@@ -48,14 +48,20 @@ export default async function handler(req, res) {
48
48
  let sql = \`SELECT * FROM ${tableName}\`
49
49
  const whereClauses = []
50
50
  const queryParams = []
51
+ let searchQueryColumns = null
51
52
 
52
- if (query && queryColumns) {
53
- const columns = JSON.parse(queryColumns)
54
- const searchConditions = columns.map((col) => \`\${col} LIKE ?\`)
55
- whereClauses.push(\`(\${searchConditions.join(' OR ')})\`)
56
- columns.forEach(() => {
57
- queryParams.push(\`%\${query}%\`)
58
- })
53
+ if (query) {
54
+ if (queryColumns) {
55
+ const columns = typeof queryColumns === 'string' ? JSON.parse(queryColumns) : (Array.isArray(queryColumns) ? queryColumns : [queryColumns])
56
+ const searchConditions = columns.map((col) => \`\${col} LIKE ?\`)
57
+ whereClauses.push(\`(\${searchConditions.join(' OR ')})\`)
58
+ columns.forEach(() => {
59
+ queryParams.push(\`%\${query}%\`)
60
+ })
61
+ } else {
62
+ // Store query for post-filtering if columns not specified
63
+ searchQueryColumns = query
64
+ }
59
65
  }
60
66
 
61
67
  if (filters) {
@@ -84,14 +90,17 @@ export default async function handler(req, res) {
84
90
  const limitValue = limit || perPage
85
91
  const offsetValue = offset !== undefined ? parseInt(offset) : (page && perPage ? (parseInt(page) - 1) * parseInt(perPage) : undefined)
86
92
 
87
- if (limitValue) {
88
- sql += \` LIMIT ?\`
89
- queryParams.push(parseInt(limitValue))
90
- }
91
-
92
- if (offsetValue !== undefined) {
93
- sql += \` OFFSET ?\`
94
- queryParams.push(offsetValue)
93
+ // Only apply SQL pagination if we're not doing post-filtering
94
+ if (!searchQueryColumns) {
95
+ if (limitValue) {
96
+ sql += \` LIMIT ?\`
97
+ queryParams.push(parseInt(limitValue))
98
+ }
99
+
100
+ if (offsetValue !== undefined) {
101
+ sql += \` OFFSET ?\`
102
+ queryParams.push(offsetValue)
103
+ }
95
104
  }
96
105
 
97
106
  const result = await client.execute({
@@ -99,7 +108,7 @@ export default async function handler(req, res) {
99
108
  args: queryParams
100
109
  })
101
110
 
102
- const data = result.rows.map((row) => {
111
+ let data = result.rows.map((row) => {
103
112
  const obj = {}
104
113
  result.columns.forEach((col, idx) => {
105
114
  obj[col] = row[col]
@@ -107,6 +116,27 @@ export default async function handler(req, res) {
107
116
  return obj
108
117
  })
109
118
 
119
+ // Apply post-filtering for search without queryColumns
120
+ if (searchQueryColumns) {
121
+ const searchQuery = searchQueryColumns.toLowerCase()
122
+ data = data.filter((item) => {
123
+ try {
124
+ const stringified = JSON.stringify(item).toLowerCase()
125
+ return stringified.includes(searchQuery)
126
+ } catch {
127
+ return false
128
+ }
129
+ })
130
+
131
+ // Apply pagination after filtering
132
+ if (limitValue) {
133
+ const start = offsetValue || 0
134
+ data = data.slice(start, start + parseInt(limitValue))
135
+ } else if (offsetValue) {
136
+ data = data.slice(offsetValue)
137
+ }
138
+ }
139
+
110
140
  const safeData = JSON.parse(JSON.stringify(data))
111
141
 
112
142
  return res.status(200).json({