@boostercloud/framework-provider-azure 3.4.1 → 3.4.3-debug.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.
@@ -21,45 +21,133 @@ async function search(cosmosDb, config, containerName, filters, limit, afterCurs
21
21
  const filterExpression = buildFilterExpression(filters);
22
22
  const projectionsExpression = buildProjections(projections);
23
23
  const queryDefinition = `SELECT ${projectionsExpression} FROM c ${filterExpression !== '' ? `WHERE ${filterExpression}` : filterExpression}`;
24
- const queryWithOrder = queryDefinition + buildOrderExpression(order);
25
- let finalQuery = queryWithOrder;
26
- if (paginatedVersion && limit) {
27
- finalQuery += ` OFFSET ${(afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) || 0} LIMIT ${limit} `;
28
- }
29
- else {
30
- if (limit) {
31
- finalQuery += ` OFFSET 0 LIMIT ${limit} `;
32
- }
33
- }
24
+ const finalQuery = queryDefinition + buildOrderExpression(order);
34
25
  const querySpec = {
35
26
  query: finalQuery,
36
27
  parameters: buildExpressionAttributeValues(filters),
37
28
  };
38
29
  logger.debug('Running search with the following params: \n', JSON.stringify(querySpec));
39
- let { resources } = await cosmosDb
40
- .database(config.resourceNames.applicationStack)
41
- .container(containerName)
42
- .items.query(querySpec)
43
- .fetchAll();
44
- resources = nestProperties(resources);
45
- resources = resources.map((resource) => ({
46
- ...resource,
47
- boosterMetadata: {
48
- ...resource.boosterMetadata,
49
- optimisticConcurrencyValue: resource._etag,
50
- },
51
- }));
30
+ const container = cosmosDb.database(config.resourceNames.applicationStack).container(containerName);
52
31
  if (paginatedVersion) {
32
+ const isDistinctQuery = /SELECT\s+DISTINCT\s+/i.test(finalQuery);
33
+ // Azure Cosmos DB continuation token compatibility rules:
34
+ // - Regular queries: Always use continuation tokens
35
+ // - DISTINCT queries: Always use OFFSET/LIMIT fallback (continuation tokens unreliable even with ORDER BY)
36
+ // - Legacy cursors: Numeric cursor.id values must use OFFSET/LIMIT for backward compatibility
37
+ const canUseContinuationToken = !isDistinctQuery;
38
+ const hasLegacyCursor = typeof (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) === 'string' && /^\d+$/.test(afterCursor.id);
39
+ logger.debug('PAGINATION DEBUG - Initial analysis:', {
40
+ isDistinctQuery,
41
+ canUseContinuationToken,
42
+ hasLegacyCursor,
43
+ afterCursor,
44
+ limit,
45
+ finalQuery,
46
+ });
47
+ // Use Cosmos DB's continuation token pagination
48
+ const feedOptions = {};
49
+ if (limit) {
50
+ feedOptions.maxItemCount = limit;
51
+ }
52
+ // Extract continuation token from the cursor (backward compatibility)
53
+ if (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.continuationToken) {
54
+ feedOptions.continuationToken = afterCursor.continuationToken;
55
+ logger.debug('PAGINATION DEBUG - Using provided continuation token:', {
56
+ continuationToken: afterCursor.continuationToken,
57
+ feedOptions,
58
+ });
59
+ }
60
+ else if (!canUseContinuationToken || hasLegacyCursor) {
61
+ // Legacy cursor format - fallback to OFFSET for backward compatibility
62
+ const offset = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) ? parseInt(afterCursor.id) : 0;
63
+ let legacyQuery = `${finalQuery} OFFSET ${offset}`;
64
+ if (limit) {
65
+ legacyQuery += ` LIMIT ${limit} `;
66
+ }
67
+ const legacyQuerySpec = { ...querySpec, query: legacyQuery };
68
+ logger.debug('PAGINATION DEBUG - Using LEGACY OFFSET/LIMIT approach:', {
69
+ reason: !canUseContinuationToken ? 'DISTINCT query detected' : 'Legacy numeric cursor detected',
70
+ offset,
71
+ legacyQuery,
72
+ legacyQuerySpec,
73
+ });
74
+ const { resources } = await container.items.query(legacyQuerySpec).fetchAll();
75
+ const processedResources = processResources(resources);
76
+ logger.debug('PAGINATION DEBUG - Legacy query results:', {
77
+ resourcesCount: (resources === null || resources === void 0 ? void 0 : resources.length) || 0,
78
+ processedResourcesCount: processedResources.length,
79
+ nextCursor: { id: (offset + processedResources.length).toString() },
80
+ });
81
+ return {
82
+ items: processedResources !== null && processedResources !== void 0 ? processedResources : [],
83
+ count: processedResources.length,
84
+ cursor: {
85
+ id: (offset + processedResources.length).toString(),
86
+ },
87
+ };
88
+ }
89
+ logger.debug('PAGINATION DEBUG - About to execute continuation token query with feedOptions:', feedOptions);
90
+ const queryIterator = container.items.query(querySpec, feedOptions);
91
+ const { resources, continuationToken } = await queryIterator.fetchNext();
92
+ logger.debug('PAGINATION DEBUG - Cosmos SDK response:', {
93
+ resourcesCount: (resources === null || resources === void 0 ? void 0 : resources.length) || 0,
94
+ continuationTokenReceived: !!continuationToken,
95
+ continuationTokenValue: continuationToken,
96
+ continuationTokenType: typeof continuationToken,
97
+ continuationTokenLength: continuationToken === null || continuationToken === void 0 ? void 0 : continuationToken.length,
98
+ });
99
+ const finalResources = processResources(resources || []);
100
+ let cursor;
101
+ if (continuationToken) {
102
+ cursor = { continuationToken };
103
+ logger.debug('PAGINATION DEBUG - Setting cursor with continuation token:', cursor);
104
+ }
105
+ else if (finalResources.length > 0) {
106
+ const currentOffset = (afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) && !isNaN(parseInt(afterCursor.id)) ? parseInt(afterCursor.id) : 0;
107
+ cursor = { id: (currentOffset + finalResources.length).toString() }; // Use the length of the results to calculate the next id
108
+ logger.debug('PAGINATION DEBUG - No continuation token, setting fallback cursor:', cursor);
109
+ }
110
+ else {
111
+ logger.debug('PAGINATION DEBUG - No continuation token and no resources, no cursor set');
112
+ }
113
+ logger.debug('PAGINATION DEBUG - Final response:', {
114
+ itemsCount: finalResources.length,
115
+ cursor,
116
+ hasMoreResults: !!continuationToken,
117
+ });
53
118
  return {
54
- items: resources !== null && resources !== void 0 ? resources : [],
55
- count: resources.length,
56
- cursor: { id: ((limit ? limit : 1) + ((afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) ? parseInt(afterCursor === null || afterCursor === void 0 ? void 0 : afterCursor.id) : 0)).toString() },
119
+ items: finalResources,
120
+ count: finalResources.length,
121
+ cursor,
57
122
  };
58
123
  }
59
124
  else {
60
- return resources !== null && resources !== void 0 ? resources : [];
125
+ // Non-paginated version - apply limit but fetch all results
126
+ let finalQueryForNonPaginated = finalQuery;
127
+ if (limit) {
128
+ finalQueryForNonPaginated += ` OFFSET 0 LIMIT ${limit} `;
129
+ }
130
+ const nonPaginatedQuerySpec = { ...querySpec, query: finalQueryForNonPaginated };
131
+ const { resources } = await container.items.query(nonPaginatedQuerySpec).fetchAll();
132
+ const processedResources = processResources(resources);
133
+ return processedResources !== null && processedResources !== void 0 ? processedResources : [];
61
134
  }
62
135
  }
136
+ /**
137
+ * Processes raw Cosmos DB resources by nesting properties and adding Booster metadata
138
+ * @param resources - The raw resources to process
139
+ * @returns An array of processed resources with nested properties and Booster metadata
140
+ */
141
+ function processResources(resources) {
142
+ const nestedResources = nestProperties(resources);
143
+ return nestedResources.map((resource) => ({
144
+ ...resource,
145
+ boosterMetadata: {
146
+ ...resource.boosterMetadata,
147
+ optimisticConcurrencyValue: resource._etag,
148
+ },
149
+ }));
150
+ }
63
151
  function buildFilterExpression(filters, usedPlaceholders = []) {
64
152
  return Object.entries(filters)
65
153
  .map(([propName, filter]) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boostercloud/framework-provider-azure",
3
- "version": "3.4.1",
3
+ "version": "3.4.3-debug.3",
4
4
  "description": "Handle Booster's integration with Azure",
5
5
  "keywords": [
6
6
  "framework-provider-azure"
@@ -27,14 +27,14 @@
27
27
  "@azure/functions": "^1.2.2",
28
28
  "@azure/identity": "~4.7.0",
29
29
  "@azure/event-hubs": "5.11.1",
30
- "@boostercloud/framework-common-helpers": "^3.4.1",
31
- "@boostercloud/framework-types": "^3.4.1",
30
+ "@boostercloud/framework-common-helpers": "^3.4.3",
31
+ "@boostercloud/framework-types": "^3.4.3",
32
32
  "tslib": "^2.4.0",
33
33
  "@effect-ts/core": "^0.60.4",
34
34
  "@azure/web-pubsub": "~1.1.0"
35
35
  },
36
36
  "devDependencies": {
37
- "@boostercloud/eslint-config": "^3.4.1",
37
+ "@boostercloud/eslint-config": "^3.4.3",
38
38
  "@types/chai": "4.2.18",
39
39
  "@types/chai-as-promised": "7.1.4",
40
40
  "@types/faker": "5.1.5",
@@ -61,16 +61,27 @@
61
61
  "typescript": "5.7.3",
62
62
  "eslint-plugin-unicorn": "~44.0.2"
63
63
  },
64
- "bugs": {
65
- "url": "https://github.com/boostercloud/booster/issues"
66
- },
67
64
  "scripts": {
68
65
  "format": "prettier --write --ext '.js,.ts' **/*.ts **/*/*.ts",
69
66
  "lint:check": "eslint --ext '.js,.ts' **/*.ts",
70
67
  "lint:fix": "eslint --quiet --fix --ext '.js,.ts' **/*.ts",
71
68
  "build": "tsc -b tsconfig.json",
72
69
  "clean": "rimraf ./dist tsconfig.tsbuildinfo",
70
+ "prepack": "tsc -b tsconfig.json",
73
71
  "test:provider-azure": "npm run test",
74
72
  "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\""
73
+ },
74
+ "bugs": {
75
+ "url": "https://github.com/boostercloud/booster/issues"
76
+ },
77
+ "pnpm": {
78
+ "overrides": {
79
+ "pac-resolver@<5.0.0": ">=5.0.0",
80
+ "underscore@>=1.3.2 <1.12.1": ">=1.13.6",
81
+ "node-fetch@<2.6.7": ">=2.6.7",
82
+ "ws@>=7.0.0 <7.4.6": ">=7.4.6",
83
+ "nanoid@>=3.0.0 <3.1.31": ">=3.1.31",
84
+ "node-fetch@<2.6.1": ">=2.6.1"
85
+ }
75
86
  }
76
- }
87
+ }