@teleporthq/teleport-plugin-next-data-source 0.42.9 → 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.
Files changed (160) hide show
  1. package/__tests__/csv-header-detection.test.ts +212 -0
  2. package/__tests__/validation.test.ts +33 -2
  3. package/dist/cjs/data-source-fetchers.d.ts +2 -2
  4. package/dist/cjs/data-source-fetchers.d.ts.map +1 -1
  5. package/dist/cjs/data-source-fetchers.js +30 -7
  6. package/dist/cjs/data-source-fetchers.js.map +1 -1
  7. package/dist/cjs/fetchers/airtable.d.ts.map +1 -1
  8. package/dist/cjs/fetchers/airtable.js +1 -1
  9. package/dist/cjs/fetchers/airtable.js.map +1 -1
  10. package/dist/cjs/fetchers/clickhouse.d.ts.map +1 -1
  11. package/dist/cjs/fetchers/clickhouse.js +1 -1
  12. package/dist/cjs/fetchers/clickhouse.js.map +1 -1
  13. package/dist/cjs/fetchers/csv-file.d.ts.map +1 -1
  14. package/dist/cjs/fetchers/csv-file.js +22 -3
  15. package/dist/cjs/fetchers/csv-file.js.map +1 -1
  16. package/dist/cjs/fetchers/firestore.d.ts.map +1 -1
  17. package/dist/cjs/fetchers/firestore.js +1 -1
  18. package/dist/cjs/fetchers/firestore.js.map +1 -1
  19. package/dist/cjs/fetchers/google-sheets.d.ts.map +1 -1
  20. package/dist/cjs/fetchers/google-sheets.js +6 -1
  21. package/dist/cjs/fetchers/google-sheets.js.map +1 -1
  22. package/dist/cjs/fetchers/javascript.d.ts.map +1 -1
  23. package/dist/cjs/fetchers/javascript.js +1 -1
  24. package/dist/cjs/fetchers/javascript.js.map +1 -1
  25. package/dist/cjs/fetchers/mariadb.d.ts.map +1 -1
  26. package/dist/cjs/fetchers/mariadb.js +3 -3
  27. package/dist/cjs/fetchers/mariadb.js.map +1 -1
  28. package/dist/cjs/fetchers/mongodb.d.ts +1 -1
  29. package/dist/cjs/fetchers/mongodb.d.ts.map +1 -1
  30. package/dist/cjs/fetchers/mongodb.js +11 -3
  31. package/dist/cjs/fetchers/mongodb.js.map +1 -1
  32. package/dist/cjs/fetchers/mysql.d.ts.map +1 -1
  33. package/dist/cjs/fetchers/mysql.js +2 -2
  34. package/dist/cjs/fetchers/mysql.js.map +1 -1
  35. package/dist/cjs/fetchers/postgresql.d.ts.map +1 -1
  36. package/dist/cjs/fetchers/postgresql.js +3 -3
  37. package/dist/cjs/fetchers/postgresql.js.map +1 -1
  38. package/dist/cjs/fetchers/redis.d.ts.map +1 -1
  39. package/dist/cjs/fetchers/redis.js +1 -1
  40. package/dist/cjs/fetchers/redis.js.map +1 -1
  41. package/dist/cjs/fetchers/redshift.d.ts.map +1 -1
  42. package/dist/cjs/fetchers/redshift.js +2 -2
  43. package/dist/cjs/fetchers/redshift.js.map +1 -1
  44. package/dist/cjs/fetchers/rest-api.d.ts.map +1 -1
  45. package/dist/cjs/fetchers/rest-api.js +2 -2
  46. package/dist/cjs/fetchers/rest-api.js.map +1 -1
  47. package/dist/cjs/fetchers/static-collection.d.ts.map +1 -1
  48. package/dist/cjs/fetchers/static-collection.js +1 -1
  49. package/dist/cjs/fetchers/static-collection.js.map +1 -1
  50. package/dist/cjs/fetchers/supabase.d.ts.map +1 -1
  51. package/dist/cjs/fetchers/supabase.js +2 -2
  52. package/dist/cjs/fetchers/supabase.js.map +1 -1
  53. package/dist/cjs/fetchers/turso.d.ts.map +1 -1
  54. package/dist/cjs/fetchers/turso.js +1 -1
  55. package/dist/cjs/fetchers/turso.js.map +1 -1
  56. package/dist/cjs/fetchers/utils/header-detection.d.ts +2 -0
  57. package/dist/cjs/fetchers/utils/header-detection.d.ts.map +1 -0
  58. package/dist/cjs/fetchers/utils/header-detection.js +8 -0
  59. package/dist/cjs/fetchers/utils/header-detection.js.map +1 -0
  60. package/dist/cjs/index.d.ts.map +1 -1
  61. package/dist/cjs/index.js +168 -4
  62. package/dist/cjs/index.js.map +1 -1
  63. package/dist/cjs/pagination-plugin.d.ts.map +1 -1
  64. package/dist/cjs/pagination-plugin.js +320 -65
  65. package/dist/cjs/pagination-plugin.js.map +1 -1
  66. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  67. package/dist/cjs/utils.d.ts +2 -0
  68. package/dist/cjs/utils.d.ts.map +1 -1
  69. package/dist/cjs/utils.js +214 -46
  70. package/dist/cjs/utils.js.map +1 -1
  71. package/dist/esm/data-source-fetchers.d.ts +2 -2
  72. package/dist/esm/data-source-fetchers.d.ts.map +1 -1
  73. package/dist/esm/data-source-fetchers.js +29 -6
  74. package/dist/esm/data-source-fetchers.js.map +1 -1
  75. package/dist/esm/fetchers/airtable.d.ts.map +1 -1
  76. package/dist/esm/fetchers/airtable.js +2 -2
  77. package/dist/esm/fetchers/airtable.js.map +1 -1
  78. package/dist/esm/fetchers/clickhouse.d.ts.map +1 -1
  79. package/dist/esm/fetchers/clickhouse.js +2 -2
  80. package/dist/esm/fetchers/clickhouse.js.map +1 -1
  81. package/dist/esm/fetchers/csv-file.d.ts.map +1 -1
  82. package/dist/esm/fetchers/csv-file.js +23 -4
  83. package/dist/esm/fetchers/csv-file.js.map +1 -1
  84. package/dist/esm/fetchers/firestore.d.ts.map +1 -1
  85. package/dist/esm/fetchers/firestore.js +2 -2
  86. package/dist/esm/fetchers/firestore.js.map +1 -1
  87. package/dist/esm/fetchers/google-sheets.d.ts.map +1 -1
  88. package/dist/esm/fetchers/google-sheets.js +6 -1
  89. package/dist/esm/fetchers/google-sheets.js.map +1 -1
  90. package/dist/esm/fetchers/javascript.d.ts.map +1 -1
  91. package/dist/esm/fetchers/javascript.js +2 -2
  92. package/dist/esm/fetchers/javascript.js.map +1 -1
  93. package/dist/esm/fetchers/mariadb.d.ts.map +1 -1
  94. package/dist/esm/fetchers/mariadb.js +4 -4
  95. package/dist/esm/fetchers/mariadb.js.map +1 -1
  96. package/dist/esm/fetchers/mongodb.d.ts +1 -1
  97. package/dist/esm/fetchers/mongodb.d.ts.map +1 -1
  98. package/dist/esm/fetchers/mongodb.js +12 -4
  99. package/dist/esm/fetchers/mongodb.js.map +1 -1
  100. package/dist/esm/fetchers/mysql.d.ts.map +1 -1
  101. package/dist/esm/fetchers/mysql.js +3 -3
  102. package/dist/esm/fetchers/mysql.js.map +1 -1
  103. package/dist/esm/fetchers/postgresql.d.ts.map +1 -1
  104. package/dist/esm/fetchers/postgresql.js +4 -4
  105. package/dist/esm/fetchers/postgresql.js.map +1 -1
  106. package/dist/esm/fetchers/redis.d.ts.map +1 -1
  107. package/dist/esm/fetchers/redis.js +2 -2
  108. package/dist/esm/fetchers/redis.js.map +1 -1
  109. package/dist/esm/fetchers/redshift.d.ts.map +1 -1
  110. package/dist/esm/fetchers/redshift.js +3 -3
  111. package/dist/esm/fetchers/redshift.js.map +1 -1
  112. package/dist/esm/fetchers/rest-api.d.ts.map +1 -1
  113. package/dist/esm/fetchers/rest-api.js +3 -3
  114. package/dist/esm/fetchers/rest-api.js.map +1 -1
  115. package/dist/esm/fetchers/static-collection.d.ts.map +1 -1
  116. package/dist/esm/fetchers/static-collection.js +2 -2
  117. package/dist/esm/fetchers/static-collection.js.map +1 -1
  118. package/dist/esm/fetchers/supabase.d.ts.map +1 -1
  119. package/dist/esm/fetchers/supabase.js +3 -3
  120. package/dist/esm/fetchers/supabase.js.map +1 -1
  121. package/dist/esm/fetchers/turso.d.ts.map +1 -1
  122. package/dist/esm/fetchers/turso.js +2 -2
  123. package/dist/esm/fetchers/turso.js.map +1 -1
  124. package/dist/esm/fetchers/utils/header-detection.d.ts +2 -0
  125. package/dist/esm/fetchers/utils/header-detection.d.ts.map +1 -0
  126. package/dist/esm/fetchers/utils/header-detection.js +4 -0
  127. package/dist/esm/fetchers/utils/header-detection.js.map +1 -0
  128. package/dist/esm/index.d.ts.map +1 -1
  129. package/dist/esm/index.js +169 -5
  130. package/dist/esm/index.js.map +1 -1
  131. package/dist/esm/pagination-plugin.d.ts.map +1 -1
  132. package/dist/esm/pagination-plugin.js +320 -65
  133. package/dist/esm/pagination-plugin.js.map +1 -1
  134. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  135. package/dist/esm/utils.d.ts +2 -0
  136. package/dist/esm/utils.d.ts.map +1 -1
  137. package/dist/esm/utils.js +211 -45
  138. package/dist/esm/utils.js.map +1 -1
  139. package/package.json +2 -2
  140. package/src/data-source-fetchers.ts +29 -13
  141. package/src/fetchers/airtable.ts +78 -30
  142. package/src/fetchers/clickhouse.ts +85 -18
  143. package/src/fetchers/csv-file.ts +254 -29
  144. package/src/fetchers/firestore.ts +62 -12
  145. package/src/fetchers/google-sheets.ts +147 -30
  146. package/src/fetchers/javascript.ts +102 -23
  147. package/src/fetchers/mariadb.ts +82 -25
  148. package/src/fetchers/mongodb.ts +153 -36
  149. package/src/fetchers/mysql.ts +83 -25
  150. package/src/fetchers/postgresql.ts +86 -26
  151. package/src/fetchers/redis.ts +40 -4
  152. package/src/fetchers/redshift.ts +84 -17
  153. package/src/fetchers/rest-api.ts +101 -24
  154. package/src/fetchers/static-collection.ts +96 -18
  155. package/src/fetchers/supabase.ts +175 -53
  156. package/src/fetchers/turso.ts +84 -17
  157. package/src/fetchers/utils/header-detection.ts +200 -0
  158. package/src/index.ts +248 -2
  159. package/src/pagination-plugin.ts +708 -191
  160. package/src/utils.ts +344 -38
@@ -7,6 +7,7 @@ import {
7
7
  import * as types from '@babel/types'
8
8
  import { StringUtils } from '@teleporthq/teleport-shared'
9
9
  import { generateSafeFileName } from './utils'
10
+ import { generateDataSourceFetcherWithCore } from './data-source-fetchers'
10
11
 
11
12
  // ==================== UIDL-FIRST STATE MANAGEMENT ====================
12
13
  // This module uses a UIDL-first approach: we scan the UIDL FIRST to identify
@@ -34,6 +35,12 @@ interface DataSourceUsage {
34
35
  searchDebounce: number
35
36
  // Query columns from resource params
36
37
  queryColumns: string[]
38
+ // Sorts from resource params
39
+ // tslint:disable-next-line:no-any
40
+ sorts: any[]
41
+ // Filters from resource params
42
+ // tslint:disable-next-line:no-any
43
+ filters: any[]
37
44
  // Computed category
38
45
  category: 'paginated+search' | 'paginated-only' | 'search-only' | 'plain'
39
46
  }
@@ -103,6 +110,18 @@ function buildStateRegistry(uidlNode: any): StateRegistry {
103
110
  queryColumns = parentDataSource.resourceParams.queryColumns.content
104
111
  }
105
112
 
113
+ // Extract sorts from parent's resource params
114
+ let sorts: any[] = []
115
+ if (parentDataSource.resourceParams?.sorts?.content) {
116
+ sorts = parentDataSource.resourceParams.sorts.content
117
+ }
118
+
119
+ // Extract filters from parent's resource params
120
+ let filters: any[] = []
121
+ if (parentDataSource.resourceParams?.filters?.content) {
122
+ filters = parentDataSource.resourceParams.filters.content
123
+ }
124
+
106
125
  // Extract limit from parent's resource params (for plain array mappers)
107
126
  let limit = 0
108
127
  if (parentDataSource.resourceParams?.limit?.content) {
@@ -127,6 +146,8 @@ function buildStateRegistry(uidlNode: any): StateRegistry {
127
146
  searchEnabled: !!content.searchEnabled,
128
147
  searchDebounce: content.searchDebounce || 300,
129
148
  queryColumns,
149
+ sorts,
150
+ filters,
130
151
  category: 'plain',
131
152
  }
132
153
 
@@ -266,6 +287,7 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
266
287
  }
267
288
 
268
289
  // Check if this is a page or component
290
+ // Pages have getStaticProps, components don't
269
291
  const getStaticPropsChunk = chunks.find((chunk) => chunk.name === 'getStaticProps')
270
292
  const isPage = !!getStaticPropsChunk
271
293
 
@@ -502,6 +524,64 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
502
524
  )
503
525
  )
504
526
  }
527
+ // Add sorts to count fetch params if present
528
+ if (usage.sorts && usage.sorts.length > 0) {
529
+ urlParams.push(
530
+ types.objectProperty(
531
+ types.identifier('sorts'),
532
+ types.callExpression(
533
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
534
+ [
535
+ types.arrayExpression(
536
+ usage.sorts.map((sort: any) =>
537
+ types.objectExpression([
538
+ types.objectProperty(
539
+ types.identifier('field'),
540
+ types.stringLiteral(sort.field || '')
541
+ ),
542
+ types.objectProperty(
543
+ types.identifier('order'),
544
+ types.stringLiteral(sort.order || '')
545
+ ),
546
+ ])
547
+ )
548
+ ),
549
+ ]
550
+ )
551
+ )
552
+ )
553
+ }
554
+ // Add filters to count fetch params if present
555
+ if (usage.filters && usage.filters.length > 0) {
556
+ urlParams.push(
557
+ types.objectProperty(
558
+ types.identifier('filters'),
559
+ types.callExpression(
560
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
561
+ [
562
+ types.arrayExpression(
563
+ usage.filters.map((filter: any) =>
564
+ types.objectExpression([
565
+ types.objectProperty(
566
+ types.identifier('source'),
567
+ types.stringLiteral(filter.source || '')
568
+ ),
569
+ types.objectProperty(
570
+ types.identifier('destination'),
571
+ types.stringLiteral(filter.destination || '')
572
+ ),
573
+ types.objectProperty(
574
+ types.identifier('operand'),
575
+ types.stringLiteral(filter.operand || '')
576
+ ),
577
+ ])
578
+ )
579
+ ),
580
+ ]
581
+ )
582
+ )
583
+ )
584
+ }
505
585
 
506
586
  // Build the count fetch effect body
507
587
  const countFetchEffectBody: types.Statement[] = []
@@ -931,14 +1011,12 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
931
1011
  updateDataProviderForPaginationOnly(dp, usage, vars, fileName)
932
1012
  } else if (usage.category === 'search-only') {
933
1013
  updateDataProviderForSearchOnly(dp, usage, vars, fileName)
934
- } else {
935
- updateDataProviderForPlain(dp, vars)
1014
+ } else if (usage.category === 'plain') {
1015
+ updateDataProviderForPlain(dp, fileName)
936
1016
  }
937
1017
 
938
- // Create API route if needed
939
- if (usage.category !== 'plain') {
940
- ensureAPIRouteExists(options.extractedResources, usage)
941
- }
1018
+ // Create API route for all categories (including 'plain' for components)
1019
+ ensureAPIRouteExists(options.extractedResources, usage, options.dataSources)
942
1020
  })
943
1021
 
944
1022
  // STEP 3.5: Handle DataProviders WITHOUT repeaters (data-source-item type)
@@ -991,7 +1069,7 @@ export const createNextArrayMapperPaginationPlugin: ComponentPluginFactory<{}> =
991
1069
 
992
1070
  // STEP 6: Update getStaticProps if this is a page
993
1071
  if (isPage) {
994
- updateGetStaticProps(chunks, registry)
1072
+ updateGetStaticProps(chunks, registry, dependencies)
995
1073
  }
996
1074
 
997
1075
  return structure
@@ -1239,6 +1317,66 @@ function updateDataProviderForPaginatedSearch(
1239
1317
  )
1240
1318
  }
1241
1319
 
1320
+ // Add sorts if present
1321
+ if (usage.sorts && usage.sorts.length > 0) {
1322
+ paramsProps.push(
1323
+ types.objectProperty(
1324
+ types.identifier('sorts'),
1325
+ types.callExpression(
1326
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1327
+ [
1328
+ types.arrayExpression(
1329
+ usage.sorts.map((sort: any) =>
1330
+ types.objectExpression([
1331
+ types.objectProperty(
1332
+ types.identifier('field'),
1333
+ types.stringLiteral(sort.field || '')
1334
+ ),
1335
+ types.objectProperty(
1336
+ types.identifier('order'),
1337
+ types.stringLiteral(sort.order || '')
1338
+ ),
1339
+ ])
1340
+ )
1341
+ ),
1342
+ ]
1343
+ )
1344
+ )
1345
+ )
1346
+ }
1347
+
1348
+ // Add filters if present
1349
+ if (usage.filters && usage.filters.length > 0) {
1350
+ paramsProps.push(
1351
+ types.objectProperty(
1352
+ types.identifier('filters'),
1353
+ types.callExpression(
1354
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1355
+ [
1356
+ types.arrayExpression(
1357
+ usage.filters.map((filter: any) =>
1358
+ types.objectExpression([
1359
+ types.objectProperty(
1360
+ types.identifier('source'),
1361
+ types.stringLiteral(filter.source || '')
1362
+ ),
1363
+ types.objectProperty(
1364
+ types.identifier('destination'),
1365
+ types.stringLiteral(filter.destination || '')
1366
+ ),
1367
+ types.objectProperty(
1368
+ types.identifier('operand'),
1369
+ types.stringLiteral(filter.operand || '')
1370
+ ),
1371
+ ])
1372
+ )
1373
+ ),
1374
+ ]
1375
+ )
1376
+ )
1377
+ )
1378
+ }
1379
+
1242
1380
  dp.openingElement.attributes.push(
1243
1381
  types.jsxAttribute(
1244
1382
  types.jsxIdentifier('params'),
@@ -1342,22 +1480,79 @@ function updateDataProviderForPaginationOnly(
1342
1480
  )
1343
1481
  )
1344
1482
 
1483
+ // Build params properties
1484
+ const paramsProps: types.ObjectProperty[] = [
1485
+ types.objectProperty(types.identifier('page'), types.identifier(vars.pageStateVar)),
1486
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage)),
1487
+ ]
1488
+
1489
+ // Add sorts if present
1490
+ if (usage.sorts && usage.sorts.length > 0) {
1491
+ paramsProps.push(
1492
+ types.objectProperty(
1493
+ types.identifier('sorts'),
1494
+ types.callExpression(
1495
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1496
+ [
1497
+ types.arrayExpression(
1498
+ usage.sorts.map((sort: any) =>
1499
+ types.objectExpression([
1500
+ types.objectProperty(
1501
+ types.identifier('field'),
1502
+ types.stringLiteral(sort.field || '')
1503
+ ),
1504
+ types.objectProperty(
1505
+ types.identifier('order'),
1506
+ types.stringLiteral(sort.order || '')
1507
+ ),
1508
+ ])
1509
+ )
1510
+ ),
1511
+ ]
1512
+ )
1513
+ )
1514
+ )
1515
+ }
1516
+
1517
+ // Add filters if present
1518
+ if (usage.filters && usage.filters.length > 0) {
1519
+ paramsProps.push(
1520
+ types.objectProperty(
1521
+ types.identifier('filters'),
1522
+ types.callExpression(
1523
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1524
+ [
1525
+ types.arrayExpression(
1526
+ usage.filters.map((filter: any) =>
1527
+ types.objectExpression([
1528
+ types.objectProperty(
1529
+ types.identifier('source'),
1530
+ types.stringLiteral(filter.source || '')
1531
+ ),
1532
+ types.objectProperty(
1533
+ types.identifier('destination'),
1534
+ types.stringLiteral(filter.destination || '')
1535
+ ),
1536
+ types.objectProperty(
1537
+ types.identifier('operand'),
1538
+ types.stringLiteral(filter.operand || '')
1539
+ ),
1540
+ ])
1541
+ )
1542
+ ),
1543
+ ]
1544
+ )
1545
+ )
1546
+ )
1547
+ }
1548
+
1345
1549
  // Add params
1346
1550
  dp.openingElement.attributes.push(
1347
1551
  types.jsxAttribute(
1348
1552
  types.jsxIdentifier('params'),
1349
1553
  types.jsxExpressionContainer(
1350
1554
  types.callExpression(types.identifier('useMemo'), [
1351
- types.arrowFunctionExpression(
1352
- [],
1353
- types.objectExpression([
1354
- types.objectProperty(types.identifier('page'), types.identifier(vars.pageStateVar)),
1355
- types.objectProperty(
1356
- types.identifier('perPage'),
1357
- types.numericLiteral(usage.perPage)
1358
- ),
1359
- ])
1360
- ),
1555
+ types.arrowFunctionExpression([], types.objectExpression(paramsProps)),
1361
1556
  types.arrayExpression([types.identifier(vars.pageStateVar)]),
1362
1557
  ])
1363
1558
  )
@@ -1448,6 +1643,66 @@ function updateDataProviderForSearchOnly(
1448
1643
  )
1449
1644
  }
1450
1645
 
1646
+ // Add sorts if present
1647
+ if (usage.sorts && usage.sorts.length > 0) {
1648
+ paramsProps.push(
1649
+ types.objectProperty(
1650
+ types.identifier('sorts'),
1651
+ types.callExpression(
1652
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1653
+ [
1654
+ types.arrayExpression(
1655
+ usage.sorts.map((sort: any) =>
1656
+ types.objectExpression([
1657
+ types.objectProperty(
1658
+ types.identifier('field'),
1659
+ types.stringLiteral(sort.field || '')
1660
+ ),
1661
+ types.objectProperty(
1662
+ types.identifier('order'),
1663
+ types.stringLiteral(sort.order || '')
1664
+ ),
1665
+ ])
1666
+ )
1667
+ ),
1668
+ ]
1669
+ )
1670
+ )
1671
+ )
1672
+ }
1673
+
1674
+ // Add filters if present
1675
+ if (usage.filters && usage.filters.length > 0) {
1676
+ paramsProps.push(
1677
+ types.objectProperty(
1678
+ types.identifier('filters'),
1679
+ types.callExpression(
1680
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
1681
+ [
1682
+ types.arrayExpression(
1683
+ usage.filters.map((filter: any) =>
1684
+ types.objectExpression([
1685
+ types.objectProperty(
1686
+ types.identifier('source'),
1687
+ types.stringLiteral(filter.source || '')
1688
+ ),
1689
+ types.objectProperty(
1690
+ types.identifier('destination'),
1691
+ types.stringLiteral(filter.destination || '')
1692
+ ),
1693
+ types.objectProperty(
1694
+ types.identifier('operand'),
1695
+ types.stringLiteral(filter.operand || '')
1696
+ ),
1697
+ ])
1698
+ )
1699
+ ),
1700
+ ]
1701
+ )
1702
+ )
1703
+ )
1704
+ }
1705
+
1451
1706
  dp.openingElement.attributes.push(
1452
1707
  types.jsxAttribute(
1453
1708
  types.jsxIdentifier('params'),
@@ -1506,29 +1761,76 @@ function updateDataProviderForSearchOnly(
1506
1761
  )
1507
1762
  }
1508
1763
 
1509
- function updateDataProviderForPlain(dp: any, vars: ReturnType<typeof getStateVarsForUsage>): void {
1764
+ function updateDataProviderForPlain(dp: any, fileName: string): void {
1510
1765
  const attrs = dp.openingElement.attributes
1511
1766
 
1512
- // Remove params and fetchData - plain mappers only use initialData
1513
- dp.openingElement.attributes = attrs.filter(
1514
- (attr: any) => !['params', 'fetchData'].includes(attr.name?.name)
1767
+ // Check if fetchData already exists
1768
+ const hasFetchData = attrs.some(
1769
+ (attr: any) => attr.type === 'JSXAttribute' && attr.name?.name === 'fetchData'
1515
1770
  )
1516
1771
 
1517
- // Update initialData to use correct prop
1518
- const existingInitialData = dp.openingElement.attributes.find(
1519
- (attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'initialData'
1772
+ // If no fetchData, add it
1773
+ if (!hasFetchData) {
1774
+ attrs.push(createFetchDataAttribute(fileName))
1775
+ }
1776
+
1777
+ // Check if persistDataDuringLoading already exists
1778
+ const hasPersistData = attrs.some(
1779
+ (attr: any) => attr.type === 'JSXAttribute' && attr.name?.name === 'persistDataDuringLoading'
1520
1780
  )
1521
1781
 
1522
- if (existingInitialData) {
1523
- existingInitialData.value = types.jsxExpressionContainer(
1524
- types.optionalMemberExpression(
1525
- types.identifier('props'),
1526
- types.identifier(vars.propsPrefix),
1527
- false,
1528
- true
1782
+ // If no persistDataDuringLoading, add it
1783
+ if (!hasPersistData) {
1784
+ attrs.push(
1785
+ types.jsxAttribute(
1786
+ types.jsxIdentifier('persistDataDuringLoading'),
1787
+ types.jsxExpressionContainer(types.booleanLiteral(true))
1529
1788
  )
1530
1789
  )
1531
1790
  }
1791
+
1792
+ // Find the params attribute
1793
+ const paramsAttrIndex = attrs.findIndex(
1794
+ (attr: any) => attr.type === 'JSXAttribute' && attr.name.name === 'params'
1795
+ )
1796
+
1797
+ if (paramsAttrIndex === -1) {
1798
+ return
1799
+ }
1800
+
1801
+ const paramsAttr = attrs[paramsAttrIndex] as types.JSXAttribute
1802
+
1803
+ // Check if params is already wrapped in useMemo
1804
+ if (
1805
+ paramsAttr.value?.type === 'JSXExpressionContainer' &&
1806
+ paramsAttr.value.expression.type === 'CallExpression' &&
1807
+ (paramsAttr.value.expression.callee as types.Identifier)?.name === 'useMemo'
1808
+ ) {
1809
+ return
1810
+ }
1811
+
1812
+ // Get the current params value expression
1813
+ let paramsExpression: types.Expression | null = null
1814
+
1815
+ if (paramsAttr.value?.type === 'JSXExpressionContainer') {
1816
+ paramsExpression = paramsAttr.value.expression as types.Expression
1817
+ }
1818
+
1819
+ if (!paramsExpression) {
1820
+ return
1821
+ }
1822
+
1823
+ // Wrap params in useMemo with empty dependencies array
1824
+ const memoizedParams = types.callExpression(types.identifier('useMemo'), [
1825
+ types.arrowFunctionExpression([], paramsExpression),
1826
+ types.arrayExpression([]),
1827
+ ])
1828
+
1829
+ // Replace the params attribute
1830
+ attrs[paramsAttrIndex] = types.jsxAttribute(
1831
+ types.jsxIdentifier('params'),
1832
+ types.jsxExpressionContainer(memoizedParams)
1833
+ )
1532
1834
  }
1533
1835
 
1534
1836
  function stabilizeDataProviderWithoutRepeater(dp: any): void {
@@ -1942,7 +2244,11 @@ function wirePaginationButtons(
1942
2244
  }
1943
2245
  }
1944
2246
 
1945
- function ensureAPIRouteExists(extractedResources: any, usage: DataSourceUsage): void {
2247
+ function ensureAPIRouteExists(
2248
+ extractedResources: any,
2249
+ usage: DataSourceUsage,
2250
+ dataSources: Record<string, any>
2251
+ ): void {
1946
2252
  // Generate file name for the API route
1947
2253
  const fileName = generateSafeFileName(
1948
2254
  usage.resourceDefinition.dataSourceType,
@@ -1950,40 +2256,67 @@ function ensureAPIRouteExists(extractedResources: any, usage: DataSourceUsage):
1950
2256
  usage.resourceDefinition.dataSourceId
1951
2257
  )
1952
2258
 
1953
- // Check if the utils data source file exists - if so, create API routes that re-export from it
1954
- if (extractedResources[`utils/${fileName}`]) {
1955
- // Create main data API route if not exists
1956
- if (!extractedResources[`api/${fileName}`]) {
1957
- const apiRouteCode = `import dataSourceModule from '../../utils/data-sources/${fileName}'
2259
+ // Check if the utils data source file exists - if not, create it
2260
+ if (!extractedResources[`utils/${fileName}`]) {
2261
+ // Get the data source from dataSources
2262
+ const dataSource = dataSources[usage.resourceDefinition.dataSourceId]
2263
+ if (dataSource) {
2264
+ try {
2265
+ // Generate the utils file with fetchData, fetchCount, handler, and getCount
2266
+ const fetcherCode = generateDataSourceFetcherWithCore(
2267
+ dataSource,
2268
+ usage.resourceDefinition.tableName || 'data'
2269
+ )
2270
+
2271
+ extractedResources[`utils/${fileName}`] = {
2272
+ fileName,
2273
+ fileType: FileType.JS,
2274
+ path: ['utils', 'data-sources'],
2275
+ content: fetcherCode,
2276
+ }
2277
+ } catch (error) {
2278
+ // If generation fails, skip
2279
+ return
2280
+ }
2281
+ }
2282
+ }
2283
+
2284
+ // Now create API routes that re-export from the utils file
2285
+ // Create main data API route if not exists
2286
+ if (!extractedResources[`api/${fileName}`]) {
2287
+ const apiRouteCode = `import dataSourceModule from '../../utils/data-sources/${fileName}'
1958
2288
 
1959
2289
  export default dataSourceModule.handler
1960
2290
  `
1961
- extractedResources[`api/${fileName}`] = {
1962
- fileName,
1963
- fileType: FileType.JS,
1964
- path: ['pages', 'api'],
1965
- content: apiRouteCode,
1966
- }
2291
+ extractedResources[`api/${fileName}`] = {
2292
+ fileName,
2293
+ fileType: FileType.JS,
2294
+ path: ['pages', 'api'],
2295
+ content: apiRouteCode,
1967
2296
  }
2297
+ }
1968
2298
 
1969
- // Create count API route if not exists (needed for paginated+search cases)
1970
- const countFileName = `${fileName}-count`
1971
- if (!extractedResources[`api/${countFileName}`]) {
1972
- const countApiRouteCode = `import dataSourceModule from '../../utils/data-sources/${fileName}'
2299
+ // Create count API route if not exists (needed for paginated+search cases)
2300
+ const countFileName = `${fileName}-count`
2301
+ if (!extractedResources[`api/${countFileName}`]) {
2302
+ const countApiRouteCode = `import dataSourceModule from '../../utils/data-sources/${fileName}'
1973
2303
 
1974
2304
  export default dataSourceModule.getCount
1975
2305
  `
1976
- extractedResources[`api/${countFileName}`] = {
1977
- fileName: countFileName,
1978
- fileType: FileType.JS,
1979
- path: ['pages', 'api'],
1980
- content: countApiRouteCode,
1981
- }
2306
+ extractedResources[`api/${countFileName}`] = {
2307
+ fileName: countFileName,
2308
+ fileType: FileType.JS,
2309
+ path: ['pages', 'api'],
2310
+ content: countApiRouteCode,
1982
2311
  }
1983
2312
  }
1984
2313
  }
1985
2314
 
1986
- function updateGetStaticProps(chunks: any[], registry: StateRegistry): void {
2315
+ function updateGetStaticProps(
2316
+ chunks: any[],
2317
+ registry: StateRegistry,
2318
+ dependencies: Record<string, any>
2319
+ ): void {
1987
2320
  const getStaticPropsChunk = chunks.find((c) => c.name === 'getStaticProps')
1988
2321
  if (!getStaticPropsChunk || getStaticPropsChunk.type !== ChunkType.AST) {
1989
2322
  return
@@ -2046,181 +2379,365 @@ function updateGetStaticProps(chunks: any[], registry: StateRegistry): void {
2046
2379
  // Track unique data sources for count fetching
2047
2380
  const dataSourcesNeedingCount = new Set<string>()
2048
2381
 
2049
- registry.usages.forEach((usage) => {
2050
- const vars = getStateVarsForUsage(usage)
2051
- const fileName = generateSafeFileName(
2052
- usage.resourceDefinition.dataSourceType,
2053
- usage.resourceDefinition.tableName,
2054
- usage.resourceDefinition.dataSourceId
2055
- )
2056
- // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
2057
- const fetcherImportName = StringUtils.dashCaseToCamelCase(fileName)
2382
+ // Only process usages that need pagination or search functionality
2383
+ // Non-paginated, non-search usages are handled by the main plugin
2384
+ registry.usages
2385
+ .filter((u) => u.paginated || u.searchEnabled)
2386
+ .forEach((usage) => {
2387
+ const vars = getStateVarsForUsage(usage)
2388
+ const fileName = generateSafeFileName(
2389
+ usage.resourceDefinition.dataSourceType,
2390
+ usage.resourceDefinition.tableName,
2391
+ usage.resourceDefinition.dataSourceId
2392
+ )
2393
+ // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
2394
+ const fetcherImportName = StringUtils.dashCaseToCamelCase(fileName)
2058
2395
 
2059
- // Add fetch call
2060
- const fetchParams: types.ObjectProperty[] = []
2396
+ // Add fetch call
2397
+ const fetchParams: types.ObjectProperty[] = []
2061
2398
 
2062
- if (usage.paginated) {
2063
- // For paginated array mappers, add page and perPage
2064
- fetchParams.push(types.objectProperty(types.identifier('page'), types.numericLiteral(1)))
2065
- fetchParams.push(
2066
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage))
2067
- )
2068
- } else if (usage.perPage > 0) {
2069
- // For non-paginated array mappers with a limit, add the limit as perPage
2070
- // This ensures the initial data fetch respects the limit from the UIDL
2071
- fetchParams.push(
2072
- types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage))
2073
- )
2074
- }
2075
- if (usage.queryColumns.length > 0) {
2076
- fetchParams.push(
2077
- types.objectProperty(
2078
- types.identifier('queryColumns'),
2079
- types.callExpression(
2080
- types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
2081
- [types.arrayExpression(usage.queryColumns.map((c) => types.stringLiteral(c)))]
2399
+ if (usage.paginated) {
2400
+ // For paginated array mappers, add page and perPage
2401
+ fetchParams.push(types.objectProperty(types.identifier('page'), types.numericLiteral(1)))
2402
+ fetchParams.push(
2403
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage))
2404
+ )
2405
+ } else if (usage.perPage > 0) {
2406
+ // For non-paginated array mappers with a limit, add the limit as perPage
2407
+ // This ensures the initial data fetch respects the limit from the UIDL
2408
+ fetchParams.push(
2409
+ types.objectProperty(types.identifier('perPage'), types.numericLiteral(usage.perPage))
2410
+ )
2411
+ }
2412
+ if (usage.queryColumns.length > 0) {
2413
+ fetchParams.push(
2414
+ types.objectProperty(
2415
+ types.identifier('queryColumns'),
2416
+ types.callExpression(
2417
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
2418
+ [types.arrayExpression(usage.queryColumns.map((c) => types.stringLiteral(c)))]
2419
+ )
2082
2420
  )
2083
2421
  )
2084
- )
2085
- }
2086
-
2087
- // Check if this fetch already exists
2088
- const existingFetchIndex = arrayPattern.elements.findIndex(
2089
- (el: any) => el?.type === 'Identifier' && el.name === vars.propsPrefix
2090
- )
2091
-
2092
- if (existingFetchIndex === -1) {
2093
- arrayPattern.elements.push(types.identifier(vars.propsPrefix))
2422
+ }
2094
2423
 
2095
- fetchesArray.elements.push(
2096
- types.callExpression(
2097
- types.memberExpression(
2424
+ // Add sorts if present
2425
+ if (usage.sorts && usage.sorts.length > 0) {
2426
+ fetchParams.push(
2427
+ types.objectProperty(
2428
+ types.identifier('sorts'),
2098
2429
  types.callExpression(
2099
- types.memberExpression(
2100
- types.identifier(fetcherImportName),
2101
- types.identifier('fetchData')
2102
- ),
2103
- [types.objectExpression(fetchParams)]
2104
- ),
2105
- types.identifier('catch')
2106
- ),
2107
- [
2108
- types.arrowFunctionExpression(
2109
- [types.identifier('error')],
2110
- types.blockStatement([
2111
- types.expressionStatement(
2112
- types.callExpression(
2113
- types.memberExpression(types.identifier('console'), types.identifier('error')),
2114
- [
2115
- types.stringLiteral(`Error fetching ${vars.propsPrefix}:`),
2116
- types.identifier('error'),
2117
- ]
2430
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
2431
+ [
2432
+ types.arrayExpression(
2433
+ usage.sorts.map((sort: any) =>
2434
+ types.objectExpression([
2435
+ types.objectProperty(
2436
+ types.identifier('field'),
2437
+ types.stringLiteral(sort.field || '')
2438
+ ),
2439
+ types.objectProperty(
2440
+ types.identifier('order'),
2441
+ types.stringLiteral(sort.order || '')
2442
+ ),
2443
+ ])
2118
2444
  )
2119
2445
  ),
2120
- types.returnStatement(types.arrayExpression([])),
2121
- ])
2122
- ),
2123
- ]
2446
+ ]
2447
+ )
2448
+ )
2124
2449
  )
2125
- )
2450
+ }
2126
2451
 
2127
- // Add to props
2128
- propsObj.properties.push(
2129
- types.objectProperty(types.identifier(vars.propsPrefix), types.identifier(vars.propsPrefix))
2130
- )
2131
- }
2452
+ // Add filters if present
2453
+ if (usage.filters && usage.filters.length > 0) {
2454
+ fetchParams.push(
2455
+ types.objectProperty(
2456
+ types.identifier('filters'),
2457
+ types.callExpression(
2458
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
2459
+ [
2460
+ types.arrayExpression(
2461
+ usage.filters.map((filter: any) =>
2462
+ types.objectExpression([
2463
+ types.objectProperty(
2464
+ types.identifier('source'),
2465
+ types.stringLiteral(filter.source || '')
2466
+ ),
2467
+ types.objectProperty(
2468
+ types.identifier('destination'),
2469
+ types.stringLiteral(filter.destination || '')
2470
+ ),
2471
+ types.objectProperty(
2472
+ types.identifier('operand'),
2473
+ types.stringLiteral(filter.operand || '')
2474
+ ),
2475
+ ])
2476
+ )
2477
+ ),
2478
+ ]
2479
+ )
2480
+ )
2481
+ )
2482
+ }
2132
2483
 
2133
- // Track for count fetching
2134
- if (usage.paginated) {
2135
- dataSourcesNeedingCount.add(
2136
- `${usage.resourceDefinition.dataSourceType}:${usage.resourceDefinition.tableName}:${usage.resourceDefinition.dataSourceId}`
2484
+ // Check if this fetch already exists
2485
+ const existingFetchIndex = arrayPattern.elements.findIndex(
2486
+ (el: any) => el?.type === 'Identifier' && el.name === vars.propsPrefix
2137
2487
  )
2138
- }
2139
-
2140
- // Add maxPages calculation for paginated
2141
- if (usage.paginated) {
2142
- const maxPagesPropName = `${vars.propsPrefix}_maxPages`
2143
- const countVarName = `${usage.dataSourceIdentifier}_count`
2144
2488
 
2145
- // Check if maxPages calculation already exists
2146
- const existingMaxPages = tryBlock.body.find(
2147
- (s: any) =>
2148
- s.type === 'VariableDeclaration' && s.declarations?.[0]?.id?.name === maxPagesPropName
2149
- )
2489
+ if (existingFetchIndex === -1) {
2490
+ arrayPattern.elements.push(types.identifier(vars.propsPrefix))
2150
2491
 
2151
- if (!existingMaxPages) {
2152
- // Insert maxPages calculation before return
2153
- const returnIndex = tryBlock.body.indexOf(returnStmt)
2154
- tryBlock.body.splice(
2155
- returnIndex,
2156
- 0,
2157
- types.variableDeclaration('const', [
2158
- types.variableDeclarator(
2159
- types.identifier(maxPagesPropName),
2492
+ fetchesArray.elements.push(
2493
+ types.callExpression(
2494
+ types.memberExpression(
2160
2495
  types.callExpression(
2161
- types.memberExpression(types.identifier('Math'), types.identifier('ceil')),
2162
- [
2163
- types.binaryExpression(
2164
- '/',
2165
- types.logicalExpression(
2166
- '||',
2167
- types.identifier(countVarName),
2168
- types.numericLiteral(0)
2169
- ),
2170
- types.numericLiteral(usage.perPage)
2171
- ),
2172
- ]
2173
- )
2496
+ types.memberExpression(
2497
+ types.identifier(fetcherImportName),
2498
+ types.identifier('fetchData')
2499
+ ),
2500
+ [types.objectExpression(fetchParams)]
2501
+ ),
2502
+ types.identifier('catch')
2174
2503
  ),
2175
- ])
2504
+ [
2505
+ types.arrowFunctionExpression(
2506
+ [types.identifier('error')],
2507
+ types.blockStatement([
2508
+ types.expressionStatement(
2509
+ types.callExpression(
2510
+ types.memberExpression(
2511
+ types.identifier('console'),
2512
+ types.identifier('error')
2513
+ ),
2514
+ [
2515
+ types.stringLiteral(`Error fetching ${vars.propsPrefix}:`),
2516
+ types.identifier('error'),
2517
+ ]
2518
+ )
2519
+ ),
2520
+ types.returnStatement(types.arrayExpression([])),
2521
+ ])
2522
+ ),
2523
+ ]
2524
+ )
2176
2525
  )
2177
2526
 
2178
- // Add maxPages to props
2527
+ // Add import dependency for the fetcher
2528
+ if (!dependencies[fetcherImportName]) {
2529
+ dependencies[fetcherImportName] = {
2530
+ type: 'local',
2531
+ path: `../utils/data-sources/${fileName}`,
2532
+ }
2533
+ }
2534
+
2535
+ // Add to props
2179
2536
  propsObj.properties.push(
2180
2537
  types.objectProperty(
2181
- types.identifier(maxPagesPropName),
2182
- types.identifier(maxPagesPropName)
2538
+ types.identifier(vars.propsPrefix),
2539
+ types.identifier(vars.propsPrefix)
2183
2540
  )
2184
2541
  )
2185
2542
  }
2186
- }
2187
- })
2543
+
2544
+ // Track for count fetching
2545
+ if (usage.paginated) {
2546
+ dataSourcesNeedingCount.add(
2547
+ `${usage.resourceDefinition.dataSourceType}:${usage.resourceDefinition.tableName}:${usage.resourceDefinition.dataSourceId}`
2548
+ )
2549
+ }
2550
+
2551
+ // Add maxPages calculation for paginated
2552
+ if (usage.paginated) {
2553
+ const maxPagesPropName = `${vars.propsPrefix}_maxPages`
2554
+ // Use filter-specific count variable if usage has filters
2555
+ const hasFilters = usage.filters && usage.filters.length > 0
2556
+ const countVarName = hasFilters
2557
+ ? `${usage.dataSourceIdentifier}_ds_${usage.index}_count`
2558
+ : `${usage.dataSourceIdentifier}_count`
2559
+
2560
+ // Check if maxPages calculation already exists
2561
+ const existingMaxPages = tryBlock.body.find(
2562
+ (s: any) =>
2563
+ s.type === 'VariableDeclaration' && s.declarations?.[0]?.id?.name === maxPagesPropName
2564
+ )
2565
+
2566
+ if (!existingMaxPages) {
2567
+ // Insert maxPages calculation before return
2568
+ const returnIndex = tryBlock.body.indexOf(returnStmt)
2569
+ tryBlock.body.splice(
2570
+ returnIndex,
2571
+ 0,
2572
+ types.variableDeclaration('const', [
2573
+ types.variableDeclarator(
2574
+ types.identifier(maxPagesPropName),
2575
+ types.callExpression(
2576
+ types.memberExpression(types.identifier('Math'), types.identifier('ceil')),
2577
+ [
2578
+ types.binaryExpression(
2579
+ '/',
2580
+ types.logicalExpression(
2581
+ '||',
2582
+ types.identifier(countVarName),
2583
+ types.numericLiteral(0)
2584
+ ),
2585
+ types.numericLiteral(usage.perPage)
2586
+ ),
2587
+ ]
2588
+ )
2589
+ ),
2590
+ ])
2591
+ )
2592
+
2593
+ // Add maxPages to props
2594
+ propsObj.properties.push(
2595
+ types.objectProperty(
2596
+ types.identifier(maxPagesPropName),
2597
+ types.identifier(maxPagesPropName)
2598
+ )
2599
+ )
2600
+ }
2601
+ }
2602
+ })
2188
2603
 
2189
2604
  // Add count fetches for unique data sources
2605
+ // Group usages by filters to determine which need separate count fetches
2606
+ const processedCountKeys = new Set<string>()
2607
+
2190
2608
  dataSourcesNeedingCount.forEach((key) => {
2191
2609
  const [dataSourceType, tableName, dataSourceId] = key.split(':')
2192
2610
  const fileName = generateSafeFileName(dataSourceType, tableName, dataSourceId)
2193
- // Use consistent import name generation (matches extractDataSourceIntoGetStaticProps)
2194
2611
  const fetcherImportName = StringUtils.dashCaseToCamelCase(fileName)
2195
2612
 
2196
- // Find usage to get dataSourceIdentifier
2197
- const usage = registry.usages.find(
2613
+ // Find all paginated usages for this data source
2614
+ const usagesForDataSource = registry.usages.filter(
2198
2615
  (u) =>
2199
2616
  u.resourceDefinition.dataSourceId === dataSourceId &&
2200
- u.resourceDefinition.tableName === tableName
2617
+ u.resourceDefinition.tableName === tableName &&
2618
+ u.paginated
2201
2619
  )
2202
- if (!usage) {
2620
+
2621
+ if (usagesForDataSource.length === 0) {
2203
2622
  return
2204
2623
  }
2205
2624
 
2206
- const countVarName = `${usage.dataSourceIdentifier}_count`
2625
+ // Group usages by their filters (stringify for comparison)
2626
+ const usagesByFilters = new Map<string, DataSourceUsage[]>()
2627
+ for (const usage of usagesForDataSource) {
2628
+ const filtersKey = JSON.stringify(usage.filters || [])
2629
+ const existing = usagesByFilters.get(filtersKey) || []
2630
+ existing.push(usage)
2631
+ usagesByFilters.set(filtersKey, existing)
2632
+ }
2207
2633
 
2208
- // Check if count fetch already exists
2209
- const existingCount = arrayPattern.elements.findIndex(
2210
- (el: any) => el?.type === 'Identifier' && el.name === countVarName
2211
- )
2634
+ // Generate count fetches for each unique filter configuration
2635
+ usagesByFilters.forEach((usages, filtersKey) => {
2636
+ const firstUsage = usages[0]
2637
+ const hasFilters = firstUsage.filters && firstUsage.filters.length > 0
2212
2638
 
2213
- if (existingCount === -1) {
2214
- arrayPattern.elements.push(types.identifier(countVarName))
2215
- fetchesArray.elements.push(
2216
- types.callExpression(
2217
- types.memberExpression(
2218
- types.identifier(fetcherImportName),
2219
- types.identifier('fetchCount')
2220
- ),
2221
- []
2222
- )
2639
+ // Create unique count variable name based on filters
2640
+ const countVarName = hasFilters
2641
+ ? `${firstUsage.dataSourceIdentifier}_ds_${firstUsage.index}_count`
2642
+ : `${firstUsage.dataSourceIdentifier}_count`
2643
+
2644
+ // Check if this count was already processed
2645
+ const countKey = `${key}:${filtersKey}`
2646
+ if (processedCountKeys.has(countKey)) {
2647
+ return
2648
+ }
2649
+ processedCountKeys.add(countKey)
2650
+
2651
+ // Check if count fetch already exists
2652
+ const existingCount = arrayPattern.elements.findIndex(
2653
+ (el: any) => el?.type === 'Identifier' && el.name === countVarName
2223
2654
  )
2224
- }
2655
+
2656
+ if (existingCount === -1) {
2657
+ arrayPattern.elements.push(types.identifier(countVarName))
2658
+
2659
+ // Build count params if filters exist
2660
+ const countParams: types.ObjectProperty[] = []
2661
+ if (hasFilters) {
2662
+ countParams.push(
2663
+ types.objectProperty(
2664
+ types.identifier('filters'),
2665
+ types.callExpression(
2666
+ types.memberExpression(types.identifier('JSON'), types.identifier('stringify')),
2667
+ [
2668
+ types.arrayExpression(
2669
+ firstUsage.filters.map((f: any) =>
2670
+ types.objectExpression([
2671
+ types.objectProperty(
2672
+ types.identifier('source'),
2673
+ types.stringLiteral(f.source)
2674
+ ),
2675
+ types.objectProperty(
2676
+ types.identifier('destination'),
2677
+ types.stringLiteral(f.destination)
2678
+ ),
2679
+ types.objectProperty(
2680
+ types.identifier('operand'),
2681
+ types.stringLiteral(f.operand)
2682
+ ),
2683
+ ])
2684
+ )
2685
+ ),
2686
+ ]
2687
+ )
2688
+ )
2689
+ )
2690
+ }
2691
+
2692
+ fetchesArray.elements.push(
2693
+ types.callExpression(
2694
+ types.memberExpression(
2695
+ types.callExpression(
2696
+ types.memberExpression(
2697
+ types.identifier(fetcherImportName),
2698
+ types.identifier('fetchCount')
2699
+ ),
2700
+ countParams.length > 0 ? [types.objectExpression(countParams)] : []
2701
+ ),
2702
+ types.identifier('catch')
2703
+ ),
2704
+ [
2705
+ types.arrowFunctionExpression(
2706
+ [types.identifier('error')],
2707
+ types.blockStatement([
2708
+ types.expressionStatement(
2709
+ types.callExpression(
2710
+ types.memberExpression(
2711
+ types.identifier('console'),
2712
+ types.identifier('error')
2713
+ ),
2714
+ [
2715
+ types.stringLiteral(`Error fetching ${countVarName}:`),
2716
+ types.identifier('error'),
2717
+ ]
2718
+ )
2719
+ ),
2720
+ types.returnStatement(types.numericLiteral(0)),
2721
+ ])
2722
+ ),
2723
+ ]
2724
+ )
2725
+ )
2726
+
2727
+ // Store which usages use this count variable for maxPages calculation
2728
+ for (const usage of usages) {
2729
+ // tslint:disable-next-line:no-any
2730
+ ;(usage as any).countVarName = countVarName
2731
+ }
2732
+
2733
+ // Add import dependency for the fetcher
2734
+ if (!dependencies[fetcherImportName]) {
2735
+ dependencies[fetcherImportName] = {
2736
+ type: 'local',
2737
+ path: `../utils/data-sources/${fileName}`,
2738
+ }
2739
+ }
2740
+ }
2741
+ })
2225
2742
  })
2226
2743
  }