adaptic-backend 1.0.340 → 1.0.342

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 (122) hide show
  1. package/Account.cjs +2670 -2264
  2. package/Account.d.ts +19 -2
  3. package/Action.cjs +1195 -839
  4. package/Action.d.ts +19 -2
  5. package/Alert.cjs +2651 -2347
  6. package/Alert.d.ts +19 -2
  7. package/Allocation.cjs +2631 -2304
  8. package/Allocation.d.ts +19 -2
  9. package/AlpacaAccount.cjs +2654 -2104
  10. package/AlpacaAccount.d.ts +19 -2
  11. package/Asset.cjs +2611 -1544
  12. package/Asset.d.ts +19 -2
  13. package/Authenticator.cjs +2603 -2290
  14. package/Authenticator.d.ts +19 -2
  15. package/Customer.cjs +2506 -2220
  16. package/Customer.d.ts +19 -2
  17. package/EconomicEvent.cjs +708 -367
  18. package/EconomicEvent.d.ts +19 -2
  19. package/MarketSentiment.cjs +691 -340
  20. package/MarketSentiment.d.ts +19 -2
  21. package/NewsArticle.cjs +2114 -1655
  22. package/NewsArticle.d.ts +19 -2
  23. package/NewsArticleAssetSentiment.cjs +1873 -1564
  24. package/NewsArticleAssetSentiment.d.ts +19 -2
  25. package/ScheduledOptionOrder.cjs +607 -316
  26. package/ScheduledOptionOrder.d.ts +19 -2
  27. package/Session.cjs +2592 -2294
  28. package/Session.d.ts +19 -2
  29. package/Trade.cjs +1261 -795
  30. package/Trade.d.ts +19 -2
  31. package/User.cjs +2432 -2013
  32. package/User.d.ts +19 -2
  33. package/VerificationToken.cjs +637 -328
  34. package/VerificationToken.d.ts +19 -2
  35. package/esm/Account.d.ts +19 -2
  36. package/esm/Account.d.ts.map +1 -1
  37. package/esm/Account.js.map +1 -1
  38. package/esm/Account.mjs +2661 -2262
  39. package/esm/Action.d.ts +19 -2
  40. package/esm/Action.d.ts.map +1 -1
  41. package/esm/Action.js.map +1 -1
  42. package/esm/Action.mjs +1186 -837
  43. package/esm/Alert.d.ts +19 -2
  44. package/esm/Alert.d.ts.map +1 -1
  45. package/esm/Alert.js.map +1 -1
  46. package/esm/Alert.mjs +2642 -2345
  47. package/esm/Allocation.d.ts +19 -2
  48. package/esm/Allocation.d.ts.map +1 -1
  49. package/esm/Allocation.js.map +1 -1
  50. package/esm/Allocation.mjs +2622 -2302
  51. package/esm/AlpacaAccount.d.ts +19 -2
  52. package/esm/AlpacaAccount.d.ts.map +1 -1
  53. package/esm/AlpacaAccount.js.map +1 -1
  54. package/esm/AlpacaAccount.mjs +2645 -2102
  55. package/esm/Asset.d.ts +19 -2
  56. package/esm/Asset.d.ts.map +1 -1
  57. package/esm/Asset.js.map +1 -1
  58. package/esm/Asset.mjs +2602 -1542
  59. package/esm/Authenticator.d.ts +19 -2
  60. package/esm/Authenticator.d.ts.map +1 -1
  61. package/esm/Authenticator.js.map +1 -1
  62. package/esm/Authenticator.mjs +2594 -2288
  63. package/esm/Customer.d.ts +19 -2
  64. package/esm/Customer.d.ts.map +1 -1
  65. package/esm/Customer.js.map +1 -1
  66. package/esm/Customer.mjs +2497 -2218
  67. package/esm/EconomicEvent.d.ts +19 -2
  68. package/esm/EconomicEvent.d.ts.map +1 -1
  69. package/esm/EconomicEvent.js.map +1 -1
  70. package/esm/EconomicEvent.mjs +699 -365
  71. package/esm/MarketSentiment.d.ts +19 -2
  72. package/esm/MarketSentiment.d.ts.map +1 -1
  73. package/esm/MarketSentiment.js.map +1 -1
  74. package/esm/MarketSentiment.mjs +682 -338
  75. package/esm/NewsArticle.d.ts +19 -2
  76. package/esm/NewsArticle.d.ts.map +1 -1
  77. package/esm/NewsArticle.js.map +1 -1
  78. package/esm/NewsArticle.mjs +2105 -1653
  79. package/esm/NewsArticleAssetSentiment.d.ts +19 -2
  80. package/esm/NewsArticleAssetSentiment.d.ts.map +1 -1
  81. package/esm/NewsArticleAssetSentiment.js.map +1 -1
  82. package/esm/NewsArticleAssetSentiment.mjs +1864 -1562
  83. package/esm/ScheduledOptionOrder.d.ts +19 -2
  84. package/esm/ScheduledOptionOrder.d.ts.map +1 -1
  85. package/esm/ScheduledOptionOrder.js.map +1 -1
  86. package/esm/ScheduledOptionOrder.mjs +598 -314
  87. package/esm/Session.d.ts +19 -2
  88. package/esm/Session.d.ts.map +1 -1
  89. package/esm/Session.js.map +1 -1
  90. package/esm/Session.mjs +2583 -2292
  91. package/esm/Trade.d.ts +19 -2
  92. package/esm/Trade.d.ts.map +1 -1
  93. package/esm/Trade.js.map +1 -1
  94. package/esm/Trade.mjs +1252 -793
  95. package/esm/User.d.ts +19 -2
  96. package/esm/User.d.ts.map +1 -1
  97. package/esm/User.js.map +1 -1
  98. package/esm/User.mjs +2423 -2011
  99. package/esm/VerificationToken.d.ts +19 -2
  100. package/esm/VerificationToken.d.ts.map +1 -1
  101. package/esm/VerificationToken.js.map +1 -1
  102. package/esm/VerificationToken.mjs +628 -326
  103. package/esm/generated/typegraphql-prisma/enhance.js.map +1 -1
  104. package/esm/generated/typegraphql-prisma/enhance.mjs +1 -1
  105. package/esm/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.d.ts +1 -1
  106. package/esm/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.d.ts.map +1 -1
  107. package/esm/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.js.map +1 -1
  108. package/esm/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.mjs +7 -7
  109. package/esm/prismaClient.d.ts +4 -5
  110. package/esm/prismaClient.d.ts.map +1 -1
  111. package/esm/prismaClient.js.map +1 -1
  112. package/esm/prismaClient.mjs +13 -11
  113. package/generated/typegraphql-prisma/enhance.cjs +1 -1
  114. package/generated/typegraphql-prisma/enhance.js.map +1 -1
  115. package/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.cjs +6 -6
  116. package/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.d.ts +1 -1
  117. package/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.d.ts.map +1 -1
  118. package/generated/typegraphql-prisma/resolvers/inputs/AccountWhereUniqueInput.js.map +1 -1
  119. package/package.json +1 -1
  120. package/prismaClient.cjs +13 -11
  121. package/prismaClient.d.ts +4 -5
  122. package/server.cjs +37 -5
package/esm/Trade.mjs CHANGED
@@ -52,894 +52,1353 @@ export const Trade = {
52
52
  * @param client - Apollo Client instance.
53
53
  * @returns The created Trade or null.
54
54
  */
55
+ /**
56
+ * Create a new Trade record.
57
+ * Enhanced with connection resilience against Prisma connection errors.
58
+ * @param props - Properties for the new record.
59
+ * @param globalClient - Apollo Client instance.
60
+ * @returns The created Trade or null.
61
+ */
55
62
  async create(props, globalClient) {
56
- const [modules, client] = await Promise.all([
57
- getApolloModules(),
58
- globalClient
59
- ? Promise.resolve(globalClient)
60
- : importedClient
61
- ]);
62
- const { gql, ApolloError } = modules;
63
- const CREATE_ONE_TRADE = gql `
64
- mutation createOneTrade($data: TradeCreateInput!) {
65
- createOneTrade(data: $data) {
66
- ${selectionSet}
67
- }
68
- }
69
- `;
70
- const variables = {
71
- data: {
72
- alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
73
- signal: props.signal !== undefined ? props.signal : undefined,
74
- strategy: props.strategy !== undefined ? props.strategy : undefined,
75
- analysis: props.analysis !== undefined ? props.analysis : undefined,
76
- summary: props.summary !== undefined ? props.summary : undefined,
77
- confidence: props.confidence !== undefined ? props.confidence : undefined,
78
- timestamp: props.timestamp !== undefined ? props.timestamp : undefined,
79
- status: props.status !== undefined ? props.status : undefined,
80
- symbol: props.symbol !== undefined ? props.symbol : undefined,
81
- entryPrice: props.entryPrice !== undefined ? props.entryPrice : undefined,
82
- exitPrice: props.exitPrice !== undefined ? props.exitPrice : undefined,
83
- entryQty: props.entryQty !== undefined ? props.entryQty : undefined,
84
- exitQty: props.exitQty !== undefined ? props.exitQty : undefined,
85
- entryValue: props.entryValue !== undefined ? props.entryValue : undefined,
86
- exitValue: props.exitValue !== undefined ? props.exitValue : undefined,
87
- entryTime: props.entryTime !== undefined ? props.entryTime : undefined,
88
- exitTime: props.exitTime !== undefined ? props.exitTime : undefined,
89
- pnlAmount: props.pnlAmount !== undefined ? props.pnlAmount : undefined,
90
- pnlPercent: props.pnlPercent !== undefined ? props.pnlPercent : undefined,
91
- durationMinutes: props.durationMinutes !== undefined ? props.durationMinutes : undefined,
92
- marketPhase: props.marketPhase !== undefined ? props.marketPhase : undefined,
93
- marketVolatility: props.marketVolatility !== undefined ? props.marketVolatility : undefined,
94
- thresholdsJson: props.thresholdsJson !== undefined ? props.thresholdsJson : undefined,
95
- actions: props.actions ?
96
- Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && 'id' in item && Object.keys(item).length === 1) ? {
97
- connect: props.actions.map((item) => ({
98
- id: item.id
99
- }))
100
- }
101
- : { connectOrCreate: props.actions.map((item) => ({
102
- where: {
103
- id: item.id !== undefined ? item.id : undefined,
104
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
105
- tradeId: item.tradeId !== undefined ? {
106
- equals: item.tradeId
107
- } : undefined,
108
- },
109
- create: {
110
- sequence: item.sequence !== undefined ? item.sequence : undefined,
111
- type: item.type !== undefined ? item.type : undefined,
112
- primary: item.primary !== undefined ? item.primary : undefined,
113
- note: item.note !== undefined ? item.note : undefined,
114
- status: item.status !== undefined ? item.status : undefined,
115
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
116
- },
117
- }))
118
- } : undefined,
119
- },
120
- };
121
- const filteredVariables = removeUndefinedProps(variables);
122
- try {
123
- const response = await client.mutate({ mutation: CREATE_ONE_TRADE, variables: filteredVariables });
124
- if (response.errors && response.errors.length > 0)
125
- throw new Error(response.errors[0].message);
126
- if (response && response.data && response.data.createOneTrade) {
127
- return response.data.createOneTrade;
63
+ // Maximum number of retries for database connection issues
64
+ const MAX_RETRIES = 3;
65
+ let retryCount = 0;
66
+ let lastError = null;
67
+ // Retry loop to handle potential database connection issues
68
+ while (retryCount < MAX_RETRIES) {
69
+ try {
70
+ const [modules, client] = await Promise.all([
71
+ getApolloModules(),
72
+ globalClient
73
+ ? Promise.resolve(globalClient)
74
+ : importedClient
75
+ ]);
76
+ const { gql, ApolloError } = modules;
77
+ const CREATE_ONE_TRADE = gql `
78
+ mutation createOneTrade($data: TradeCreateInput!) {
79
+ createOneTrade(data: $data) {
80
+ ${selectionSet}
81
+ }
82
+ }
83
+ `;
84
+ const variables = {
85
+ data: {
86
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
87
+ signal: props.signal !== undefined ? props.signal : undefined,
88
+ strategy: props.strategy !== undefined ? props.strategy : undefined,
89
+ analysis: props.analysis !== undefined ? props.analysis : undefined,
90
+ summary: props.summary !== undefined ? props.summary : undefined,
91
+ confidence: props.confidence !== undefined ? props.confidence : undefined,
92
+ timestamp: props.timestamp !== undefined ? props.timestamp : undefined,
93
+ status: props.status !== undefined ? props.status : undefined,
94
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
95
+ entryPrice: props.entryPrice !== undefined ? props.entryPrice : undefined,
96
+ exitPrice: props.exitPrice !== undefined ? props.exitPrice : undefined,
97
+ entryQty: props.entryQty !== undefined ? props.entryQty : undefined,
98
+ exitQty: props.exitQty !== undefined ? props.exitQty : undefined,
99
+ entryValue: props.entryValue !== undefined ? props.entryValue : undefined,
100
+ exitValue: props.exitValue !== undefined ? props.exitValue : undefined,
101
+ entryTime: props.entryTime !== undefined ? props.entryTime : undefined,
102
+ exitTime: props.exitTime !== undefined ? props.exitTime : undefined,
103
+ pnlAmount: props.pnlAmount !== undefined ? props.pnlAmount : undefined,
104
+ pnlPercent: props.pnlPercent !== undefined ? props.pnlPercent : undefined,
105
+ durationMinutes: props.durationMinutes !== undefined ? props.durationMinutes : undefined,
106
+ marketPhase: props.marketPhase !== undefined ? props.marketPhase : undefined,
107
+ marketVolatility: props.marketVolatility !== undefined ? props.marketVolatility : undefined,
108
+ thresholdsJson: props.thresholdsJson !== undefined ? props.thresholdsJson : undefined,
109
+ actions: props.actions ?
110
+ Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && 'id' in item && Object.keys(item).length === 1) ? {
111
+ connect: props.actions.map((item) => ({
112
+ id: item.id
113
+ }))
114
+ }
115
+ : { connectOrCreate: props.actions.map((item) => ({
116
+ where: {
117
+ id: item.id !== undefined ? item.id : undefined,
118
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
119
+ tradeId: item.tradeId !== undefined ? {
120
+ equals: item.tradeId
121
+ } : undefined,
122
+ },
123
+ create: {
124
+ sequence: item.sequence !== undefined ? item.sequence : undefined,
125
+ type: item.type !== undefined ? item.type : undefined,
126
+ primary: item.primary !== undefined ? item.primary : undefined,
127
+ note: item.note !== undefined ? item.note : undefined,
128
+ status: item.status !== undefined ? item.status : undefined,
129
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
130
+ },
131
+ }))
132
+ } : undefined,
133
+ },
134
+ };
135
+ const filteredVariables = removeUndefinedProps(variables);
136
+ const response = await client.mutate({
137
+ mutation: CREATE_ONE_TRADE,
138
+ variables: filteredVariables,
139
+ // Don't cache mutations, but ensure we're using the freshest context
140
+ fetchPolicy: 'no-cache'
141
+ });
142
+ if (response.errors && response.errors.length > 0)
143
+ throw new Error(response.errors[0].message);
144
+ if (response && response.data && response.data.createOneTrade) {
145
+ return response.data.createOneTrade;
146
+ }
147
+ else {
148
+ return null;
149
+ }
128
150
  }
129
- else {
130
- return null;
151
+ catch (error) {
152
+ lastError = error;
153
+ // Check if this is a database connection error that we should retry
154
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
155
+ error.message?.includes('Cannot reach database server') ||
156
+ error.message?.includes('Connection timed out') ||
157
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
158
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
159
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
160
+ retryCount++;
161
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
162
+ console.warn("Database connection error, retrying...");
163
+ await new Promise(resolve => setTimeout(resolve, delay));
164
+ continue;
165
+ }
166
+ // Log the error and rethrow
167
+ console.error("Database error occurred:", error);
168
+ throw error;
131
169
  }
132
170
  }
133
- catch (error) {
134
- console.error('Error in createOneTrade:', error);
135
- throw error;
136
- }
171
+ // If we exhausted retries, throw the last error
172
+ throw lastError;
137
173
  },
138
174
  /**
139
175
  * Create multiple Trade records.
176
+ * Enhanced with connection resilience against Prisma connection errors.
140
177
  * @param props - Array of Trade objects for the new records.
141
178
  * @param globalClient - Apollo Client instance.
142
179
  * @returns The count of created records or null.
143
180
  */
144
181
  async createMany(props, globalClient) {
145
- const [modules, client] = await Promise.all([
146
- getApolloModules(),
147
- globalClient
148
- ? Promise.resolve(globalClient)
149
- : importedClient
150
- ]);
151
- const { gql, ApolloError } = modules;
152
- const CREATE_MANY_TRADE = gql `
153
- mutation createManyTrade($data: [TradeCreateManyInput!]!) {
154
- createManyTrade(data: $data) {
155
- count
156
- }
157
- }`;
158
- const variables = {
159
- data: props.map(prop => ({
160
- alpacaAccountId: prop.alpacaAccountId !== undefined ? prop.alpacaAccountId : undefined,
161
- signal: prop.signal !== undefined ? prop.signal : undefined,
162
- strategy: prop.strategy !== undefined ? prop.strategy : undefined,
163
- analysis: prop.analysis !== undefined ? prop.analysis : undefined,
164
- summary: prop.summary !== undefined ? prop.summary : undefined,
165
- confidence: prop.confidence !== undefined ? prop.confidence : undefined,
166
- timestamp: prop.timestamp !== undefined ? prop.timestamp : undefined,
167
- status: prop.status !== undefined ? prop.status : undefined,
168
- symbol: prop.symbol !== undefined ? prop.symbol : undefined,
169
- entryPrice: prop.entryPrice !== undefined ? prop.entryPrice : undefined,
170
- exitPrice: prop.exitPrice !== undefined ? prop.exitPrice : undefined,
171
- entryQty: prop.entryQty !== undefined ? prop.entryQty : undefined,
172
- exitQty: prop.exitQty !== undefined ? prop.exitQty : undefined,
173
- entryValue: prop.entryValue !== undefined ? prop.entryValue : undefined,
174
- exitValue: prop.exitValue !== undefined ? prop.exitValue : undefined,
175
- entryTime: prop.entryTime !== undefined ? prop.entryTime : undefined,
176
- exitTime: prop.exitTime !== undefined ? prop.exitTime : undefined,
177
- pnlAmount: prop.pnlAmount !== undefined ? prop.pnlAmount : undefined,
178
- pnlPercent: prop.pnlPercent !== undefined ? prop.pnlPercent : undefined,
179
- durationMinutes: prop.durationMinutes !== undefined ? prop.durationMinutes : undefined,
180
- marketPhase: prop.marketPhase !== undefined ? prop.marketPhase : undefined,
181
- marketVolatility: prop.marketVolatility !== undefined ? prop.marketVolatility : undefined,
182
- thresholdsJson: prop.thresholdsJson !== undefined ? prop.thresholdsJson : undefined,
183
- })),
184
- };
185
- const filteredVariables = removeUndefinedProps(variables);
186
- try {
187
- const response = await client.mutate({ mutation: CREATE_MANY_TRADE, variables: filteredVariables });
188
- if (response.errors && response.errors.length > 0)
189
- throw new Error(response.errors[0].message);
190
- if (response && response.data && response.data.createManyTrade) {
191
- return response.data.createManyTrade;
182
+ // Maximum number of retries for database connection issues
183
+ const MAX_RETRIES = 3;
184
+ let retryCount = 0;
185
+ let lastError = null;
186
+ // Retry loop to handle potential database connection issues
187
+ while (retryCount < MAX_RETRIES) {
188
+ try {
189
+ const [modules, client] = await Promise.all([
190
+ getApolloModules(),
191
+ globalClient
192
+ ? Promise.resolve(globalClient)
193
+ : importedClient
194
+ ]);
195
+ const { gql, ApolloError } = modules;
196
+ const CREATE_MANY_TRADE = gql `
197
+ mutation createManyTrade($data: [TradeCreateManyInput!]!) {
198
+ createManyTrade(data: $data) {
199
+ count
192
200
  }
193
- else {
194
- return null;
201
+ }`;
202
+ const variables = {
203
+ data: props.map(prop => ({
204
+ alpacaAccountId: prop.alpacaAccountId !== undefined ? prop.alpacaAccountId : undefined,
205
+ signal: prop.signal !== undefined ? prop.signal : undefined,
206
+ strategy: prop.strategy !== undefined ? prop.strategy : undefined,
207
+ analysis: prop.analysis !== undefined ? prop.analysis : undefined,
208
+ summary: prop.summary !== undefined ? prop.summary : undefined,
209
+ confidence: prop.confidence !== undefined ? prop.confidence : undefined,
210
+ timestamp: prop.timestamp !== undefined ? prop.timestamp : undefined,
211
+ status: prop.status !== undefined ? prop.status : undefined,
212
+ symbol: prop.symbol !== undefined ? prop.symbol : undefined,
213
+ entryPrice: prop.entryPrice !== undefined ? prop.entryPrice : undefined,
214
+ exitPrice: prop.exitPrice !== undefined ? prop.exitPrice : undefined,
215
+ entryQty: prop.entryQty !== undefined ? prop.entryQty : undefined,
216
+ exitQty: prop.exitQty !== undefined ? prop.exitQty : undefined,
217
+ entryValue: prop.entryValue !== undefined ? prop.entryValue : undefined,
218
+ exitValue: prop.exitValue !== undefined ? prop.exitValue : undefined,
219
+ entryTime: prop.entryTime !== undefined ? prop.entryTime : undefined,
220
+ exitTime: prop.exitTime !== undefined ? prop.exitTime : undefined,
221
+ pnlAmount: prop.pnlAmount !== undefined ? prop.pnlAmount : undefined,
222
+ pnlPercent: prop.pnlPercent !== undefined ? prop.pnlPercent : undefined,
223
+ durationMinutes: prop.durationMinutes !== undefined ? prop.durationMinutes : undefined,
224
+ marketPhase: prop.marketPhase !== undefined ? prop.marketPhase : undefined,
225
+ marketVolatility: prop.marketVolatility !== undefined ? prop.marketVolatility : undefined,
226
+ thresholdsJson: prop.thresholdsJson !== undefined ? prop.thresholdsJson : undefined,
227
+ })),
228
+ };
229
+ const filteredVariables = removeUndefinedProps(variables);
230
+ const response = await client.mutate({
231
+ mutation: CREATE_MANY_TRADE,
232
+ variables: filteredVariables,
233
+ // Don't cache mutations, but ensure we're using the freshest context
234
+ fetchPolicy: 'no-cache'
235
+ });
236
+ if (response.errors && response.errors.length > 0)
237
+ throw new Error(response.errors[0].message);
238
+ if (response && response.data && response.data.createManyTrade) {
239
+ return response.data.createManyTrade;
240
+ }
241
+ else {
242
+ return null;
243
+ }
244
+ }
245
+ catch (error) {
246
+ lastError = error;
247
+ // Check if this is a database connection error that we should retry
248
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
249
+ error.message?.includes('Cannot reach database server') ||
250
+ error.message?.includes('Connection timed out') ||
251
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
252
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
253
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
254
+ retryCount++;
255
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
256
+ console.warn("Database connection error, retrying...");
257
+ await new Promise(resolve => setTimeout(resolve, delay));
258
+ continue;
259
+ }
260
+ // Log the error and rethrow
261
+ console.error("Database error occurred:", error);
262
+ throw error;
195
263
  }
196
264
  }
197
- catch (error) {
198
- console.error('Error in createManyTrade:', error);
199
- throw error;
200
- }
265
+ // If we exhausted retries, throw the last error
266
+ throw lastError;
201
267
  },
202
268
  /**
203
269
  * Update a single Trade record.
270
+ * Enhanced with connection resilience against Prisma connection errors.
204
271
  * @param props - Properties to update.
205
272
  * @param globalClient - Apollo Client instance.
206
273
  * @returns The updated Trade or null.
207
274
  */
208
275
  async update(props, globalClient) {
209
- const [modules, client] = await Promise.all([
210
- getApolloModules(),
211
- globalClient
212
- ? Promise.resolve(globalClient)
213
- : importedClient
214
- ]);
215
- const { gql, ApolloError } = modules;
216
- const UPDATE_ONE_TRADE = gql `
217
- mutation updateOneTrade($data: TradeUpdateInput!, $where: TradeWhereUniqueInput!) {
218
- updateOneTrade(data: $data, where: $where) {
219
- ${selectionSet}
220
- }
221
- }`;
222
- const variables = {
223
- where: {
224
- id: props.id !== undefined ? props.id : undefined,
225
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
226
- equals: props.alpacaAccountId
227
- } : undefined,
228
- symbol: props.symbol !== undefined ? {
229
- equals: props.symbol
230
- } : undefined,
231
- },
232
- data: {
233
- id: props.id !== undefined ? {
234
- set: props.id
235
- } : undefined,
236
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
237
- set: props.alpacaAccountId
238
- } : undefined,
239
- signal: props.signal !== undefined ? {
240
- set: props.signal
241
- } : undefined,
242
- strategy: props.strategy !== undefined ? {
243
- set: props.strategy
244
- } : undefined,
245
- analysis: props.analysis !== undefined ? {
246
- set: props.analysis
247
- } : undefined,
248
- summary: props.summary !== undefined ? {
249
- set: props.summary
250
- } : undefined,
251
- confidence: props.confidence !== undefined ? {
252
- set: props.confidence
253
- } : undefined,
254
- timestamp: props.timestamp !== undefined ? {
255
- set: props.timestamp
256
- } : undefined,
257
- createdAt: props.createdAt !== undefined ? {
258
- set: props.createdAt
259
- } : undefined,
260
- updatedAt: props.updatedAt !== undefined ? {
261
- set: props.updatedAt
262
- } : undefined,
263
- status: props.status !== undefined ? {
264
- set: props.status
265
- } : undefined,
266
- symbol: props.symbol !== undefined ? {
267
- set: props.symbol
268
- } : undefined,
269
- entryPrice: props.entryPrice !== undefined ? {
270
- set: props.entryPrice
271
- } : undefined,
272
- exitPrice: props.exitPrice !== undefined ? {
273
- set: props.exitPrice
274
- } : undefined,
275
- entryQty: props.entryQty !== undefined ? {
276
- set: props.entryQty
277
- } : undefined,
278
- exitQty: props.exitQty !== undefined ? {
279
- set: props.exitQty
280
- } : undefined,
281
- entryValue: props.entryValue !== undefined ? {
282
- set: props.entryValue
283
- } : undefined,
284
- exitValue: props.exitValue !== undefined ? {
285
- set: props.exitValue
286
- } : undefined,
287
- entryTime: props.entryTime !== undefined ? {
288
- set: props.entryTime
289
- } : undefined,
290
- exitTime: props.exitTime !== undefined ? {
291
- set: props.exitTime
292
- } : undefined,
293
- pnlAmount: props.pnlAmount !== undefined ? {
294
- set: props.pnlAmount
295
- } : undefined,
296
- pnlPercent: props.pnlPercent !== undefined ? {
297
- set: props.pnlPercent
298
- } : undefined,
299
- durationMinutes: props.durationMinutes !== undefined ? {
300
- set: props.durationMinutes
301
- } : undefined,
302
- marketPhase: props.marketPhase !== undefined ? {
303
- set: props.marketPhase
304
- } : undefined,
305
- marketVolatility: props.marketVolatility !== undefined ? {
306
- set: props.marketVolatility
307
- } : undefined,
308
- thresholdsJson: props.thresholdsJson !== undefined ? {
309
- set: props.thresholdsJson
310
- } : undefined,
311
- actions: props.actions ?
312
- Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
313
- connect: props.actions.map((item) => ({
314
- id: item.id
315
- }))
316
- } : { upsert: props.actions.map((item) => ({
317
- where: {
318
- id: item.id !== undefined ? item.id : undefined,
319
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
320
- tradeId: item.tradeId !== undefined ? {
321
- equals: item.tradeId
322
- } : undefined,
323
- },
324
- update: {
325
- id: item.id !== undefined ? {
326
- set: item.id
327
- } : undefined,
328
- sequence: item.sequence !== undefined ? {
329
- set: item.sequence
330
- } : undefined,
331
- type: item.type !== undefined ? {
332
- set: item.type
333
- } : undefined,
334
- primary: item.primary !== undefined ? {
335
- set: item.primary
336
- } : undefined,
337
- note: item.note !== undefined ? {
338
- set: item.note
339
- } : undefined,
340
- status: item.status !== undefined ? {
341
- set: item.status
342
- } : undefined,
343
- alpacaOrderId: item.alpacaOrderId !== undefined ? {
344
- set: item.alpacaOrderId
345
- } : undefined,
346
- },
347
- create: {
348
- sequence: item.sequence !== undefined ? item.sequence : undefined,
349
- type: item.type !== undefined ? item.type : undefined,
350
- primary: item.primary !== undefined ? item.primary : undefined,
351
- note: item.note !== undefined ? item.note : undefined,
352
- status: item.status !== undefined ? item.status : undefined,
353
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
354
- },
355
- }))
356
- } : undefined,
357
- },
358
- };
359
- const filteredVariables = removeUndefinedProps(variables);
360
- try {
361
- const response = await client.mutate({ mutation: UPDATE_ONE_TRADE, variables: filteredVariables });
362
- if (response.errors && response.errors.length > 0)
363
- throw new Error(response.errors[0].message);
364
- if (response && response.data && response.data.updateOneTrade) {
365
- return response.data.updateOneTrade;
276
+ // Maximum number of retries for database connection issues
277
+ const MAX_RETRIES = 3;
278
+ let retryCount = 0;
279
+ let lastError = null;
280
+ // Retry loop to handle potential database connection issues
281
+ while (retryCount < MAX_RETRIES) {
282
+ try {
283
+ const [modules, client] = await Promise.all([
284
+ getApolloModules(),
285
+ globalClient
286
+ ? Promise.resolve(globalClient)
287
+ : importedClient
288
+ ]);
289
+ const { gql, ApolloError } = modules;
290
+ const UPDATE_ONE_TRADE = gql `
291
+ mutation updateOneTrade($data: TradeUpdateInput!, $where: TradeWhereUniqueInput!) {
292
+ updateOneTrade(data: $data, where: $where) {
293
+ ${selectionSet}
294
+ }
295
+ }`;
296
+ const variables = {
297
+ where: {
298
+ id: props.id !== undefined ? props.id : undefined,
299
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
300
+ signal: props.signal !== undefined ? {
301
+ equals: props.signal
302
+ } : undefined,
303
+ strategy: props.strategy !== undefined ? {
304
+ equals: props.strategy
305
+ } : undefined,
306
+ analysis: props.analysis !== undefined ? {
307
+ equals: props.analysis
308
+ } : undefined,
309
+ summary: props.summary !== undefined ? {
310
+ equals: props.summary
311
+ } : undefined,
312
+ confidence: props.confidence !== undefined ? {
313
+ equals: props.confidence
314
+ } : undefined,
315
+ timestamp: props.timestamp !== undefined ? {
316
+ equals: props.timestamp
317
+ } : undefined,
318
+ createdAt: props.createdAt !== undefined ? {
319
+ equals: props.createdAt
320
+ } : undefined,
321
+ updatedAt: props.updatedAt !== undefined ? {
322
+ equals: props.updatedAt
323
+ } : undefined,
324
+ status: props.status !== undefined ? {
325
+ equals: props.status
326
+ } : undefined,
327
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
328
+ entryTime: props.entryTime !== undefined ? {
329
+ equals: props.entryTime
330
+ } : undefined,
331
+ exitTime: props.exitTime !== undefined ? {
332
+ equals: props.exitTime
333
+ } : undefined,
334
+ marketPhase: props.marketPhase !== undefined ? {
335
+ equals: props.marketPhase
336
+ } : undefined,
337
+ marketVolatility: props.marketVolatility !== undefined ? {
338
+ equals: props.marketVolatility
339
+ } : undefined,
340
+ thresholdsJson: props.thresholdsJson !== undefined ? {
341
+ equals: props.thresholdsJson
342
+ } : undefined,
343
+ },
344
+ data: {
345
+ id: props.id !== undefined ? {
346
+ set: props.id
347
+ } : undefined,
348
+ alpacaAccountId: props.alpacaAccountId !== undefined ? {
349
+ set: props.alpacaAccountId
350
+ } : undefined,
351
+ signal: props.signal !== undefined ? {
352
+ set: props.signal
353
+ } : undefined,
354
+ strategy: props.strategy !== undefined ? {
355
+ set: props.strategy
356
+ } : undefined,
357
+ analysis: props.analysis !== undefined ? {
358
+ set: props.analysis
359
+ } : undefined,
360
+ summary: props.summary !== undefined ? {
361
+ set: props.summary
362
+ } : undefined,
363
+ confidence: props.confidence !== undefined ? {
364
+ set: props.confidence
365
+ } : undefined,
366
+ timestamp: props.timestamp !== undefined ? {
367
+ set: props.timestamp
368
+ } : undefined,
369
+ createdAt: props.createdAt !== undefined ? {
370
+ set: props.createdAt
371
+ } : undefined,
372
+ updatedAt: props.updatedAt !== undefined ? {
373
+ set: props.updatedAt
374
+ } : undefined,
375
+ status: props.status !== undefined ? {
376
+ set: props.status
377
+ } : undefined,
378
+ symbol: props.symbol !== undefined ? {
379
+ set: props.symbol
380
+ } : undefined,
381
+ entryPrice: props.entryPrice !== undefined ? {
382
+ set: props.entryPrice
383
+ } : undefined,
384
+ exitPrice: props.exitPrice !== undefined ? {
385
+ set: props.exitPrice
386
+ } : undefined,
387
+ entryQty: props.entryQty !== undefined ? {
388
+ set: props.entryQty
389
+ } : undefined,
390
+ exitQty: props.exitQty !== undefined ? {
391
+ set: props.exitQty
392
+ } : undefined,
393
+ entryValue: props.entryValue !== undefined ? {
394
+ set: props.entryValue
395
+ } : undefined,
396
+ exitValue: props.exitValue !== undefined ? {
397
+ set: props.exitValue
398
+ } : undefined,
399
+ entryTime: props.entryTime !== undefined ? {
400
+ set: props.entryTime
401
+ } : undefined,
402
+ exitTime: props.exitTime !== undefined ? {
403
+ set: props.exitTime
404
+ } : undefined,
405
+ pnlAmount: props.pnlAmount !== undefined ? {
406
+ set: props.pnlAmount
407
+ } : undefined,
408
+ pnlPercent: props.pnlPercent !== undefined ? {
409
+ set: props.pnlPercent
410
+ } : undefined,
411
+ durationMinutes: props.durationMinutes !== undefined ? {
412
+ set: props.durationMinutes
413
+ } : undefined,
414
+ marketPhase: props.marketPhase !== undefined ? {
415
+ set: props.marketPhase
416
+ } : undefined,
417
+ marketVolatility: props.marketVolatility !== undefined ? {
418
+ set: props.marketVolatility
419
+ } : undefined,
420
+ thresholdsJson: props.thresholdsJson !== undefined ? {
421
+ set: props.thresholdsJson
422
+ } : undefined,
423
+ actions: props.actions ?
424
+ Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
425
+ connect: props.actions.map((item) => ({
426
+ id: item.id
427
+ }))
428
+ } : { upsert: props.actions.map((item) => ({
429
+ where: {
430
+ id: item.id !== undefined ? item.id : undefined,
431
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
432
+ tradeId: item.tradeId !== undefined ? {
433
+ equals: item.tradeId
434
+ } : undefined,
435
+ },
436
+ update: {
437
+ id: item.id !== undefined ? {
438
+ set: item.id
439
+ } : undefined,
440
+ sequence: item.sequence !== undefined ? {
441
+ set: item.sequence
442
+ } : undefined,
443
+ type: item.type !== undefined ? {
444
+ set: item.type
445
+ } : undefined,
446
+ primary: item.primary !== undefined ? {
447
+ set: item.primary
448
+ } : undefined,
449
+ note: item.note !== undefined ? {
450
+ set: item.note
451
+ } : undefined,
452
+ status: item.status !== undefined ? {
453
+ set: item.status
454
+ } : undefined,
455
+ alpacaOrderId: item.alpacaOrderId !== undefined ? {
456
+ set: item.alpacaOrderId
457
+ } : undefined,
458
+ },
459
+ create: {
460
+ sequence: item.sequence !== undefined ? item.sequence : undefined,
461
+ type: item.type !== undefined ? item.type : undefined,
462
+ primary: item.primary !== undefined ? item.primary : undefined,
463
+ note: item.note !== undefined ? item.note : undefined,
464
+ status: item.status !== undefined ? item.status : undefined,
465
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
466
+ },
467
+ }))
468
+ } : undefined,
469
+ },
470
+ };
471
+ const filteredVariables = removeUndefinedProps(variables);
472
+ const response = await client.mutate({
473
+ mutation: UPDATE_ONE_TRADE,
474
+ variables: filteredVariables,
475
+ // Don't cache mutations, but ensure we're using the freshest context
476
+ fetchPolicy: 'no-cache'
477
+ });
478
+ if (response.errors && response.errors.length > 0)
479
+ throw new Error(response.errors[0].message);
480
+ if (response && response.data && response.data.updateOneTrade) {
481
+ return response.data.updateOneTrade;
482
+ }
483
+ else {
484
+ return null;
485
+ }
366
486
  }
367
- else {
368
- return null;
487
+ catch (error) {
488
+ lastError = error;
489
+ // Check if this is a database connection error that we should retry
490
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
491
+ error.message?.includes('Cannot reach database server') ||
492
+ error.message?.includes('Connection timed out') ||
493
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
494
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
495
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
496
+ retryCount++;
497
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
498
+ console.warn("Database connection error, retrying...");
499
+ await new Promise(resolve => setTimeout(resolve, delay));
500
+ continue;
501
+ }
502
+ // Log the error and rethrow
503
+ console.error("Database error occurred:", error);
504
+ throw error;
369
505
  }
370
506
  }
371
- catch (error) {
372
- console.error('Error in updateOneTrade:', error);
373
- throw error;
374
- }
507
+ // If we exhausted retries, throw the last error
508
+ throw lastError;
375
509
  },
376
510
  /**
377
511
  * Upsert a single Trade record.
512
+ * Enhanced with connection resilience against Prisma connection errors.
378
513
  * @param props - Properties to update.
379
514
  * @param globalClient - Apollo Client instance.
380
515
  * @returns The updated Trade or null.
381
516
  */
382
517
  async upsert(props, globalClient) {
383
- const [modules, client] = await Promise.all([
384
- getApolloModules(),
385
- globalClient
386
- ? Promise.resolve(globalClient)
387
- : importedClient
388
- ]);
389
- const { gql, ApolloError } = modules;
390
- const UPSERT_ONE_TRADE = gql `
391
- mutation upsertOneTrade($where: TradeWhereUniqueInput!, $create: TradeCreateInput!, $update: TradeUpdateInput!) {
392
- upsertOneTrade(where: $where, create: $create, update: $update) {
393
- ${selectionSet}
394
- }
395
- }`;
396
- const variables = {
397
- where: {
398
- id: props.id !== undefined ? props.id : undefined,
399
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
400
- equals: props.alpacaAccountId
401
- } : undefined,
402
- symbol: props.symbol !== undefined ? {
403
- equals: props.symbol
404
- } : undefined,
405
- },
406
- create: {
407
- alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
408
- signal: props.signal !== undefined ? props.signal : undefined,
409
- strategy: props.strategy !== undefined ? props.strategy : undefined,
410
- analysis: props.analysis !== undefined ? props.analysis : undefined,
411
- summary: props.summary !== undefined ? props.summary : undefined,
412
- confidence: props.confidence !== undefined ? props.confidence : undefined,
413
- timestamp: props.timestamp !== undefined ? props.timestamp : undefined,
414
- status: props.status !== undefined ? props.status : undefined,
415
- symbol: props.symbol !== undefined ? props.symbol : undefined,
416
- entryPrice: props.entryPrice !== undefined ? props.entryPrice : undefined,
417
- exitPrice: props.exitPrice !== undefined ? props.exitPrice : undefined,
418
- entryQty: props.entryQty !== undefined ? props.entryQty : undefined,
419
- exitQty: props.exitQty !== undefined ? props.exitQty : undefined,
420
- entryValue: props.entryValue !== undefined ? props.entryValue : undefined,
421
- exitValue: props.exitValue !== undefined ? props.exitValue : undefined,
422
- entryTime: props.entryTime !== undefined ? props.entryTime : undefined,
423
- exitTime: props.exitTime !== undefined ? props.exitTime : undefined,
424
- pnlAmount: props.pnlAmount !== undefined ? props.pnlAmount : undefined,
425
- pnlPercent: props.pnlPercent !== undefined ? props.pnlPercent : undefined,
426
- durationMinutes: props.durationMinutes !== undefined ? props.durationMinutes : undefined,
427
- marketPhase: props.marketPhase !== undefined ? props.marketPhase : undefined,
428
- marketVolatility: props.marketVolatility !== undefined ? props.marketVolatility : undefined,
429
- thresholdsJson: props.thresholdsJson !== undefined ? props.thresholdsJson : undefined,
430
- actions: props.actions ?
431
- Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && 'id' in item && Object.keys(item).length === 1) ? {
432
- connect: props.actions.map((item) => ({
433
- id: item.id
434
- }))
435
- }
436
- : { connectOrCreate: props.actions.map((item) => ({
437
- where: {
438
- id: item.id !== undefined ? item.id : undefined,
439
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
440
- tradeId: item.tradeId !== undefined ? {
441
- equals: item.tradeId
442
- } : undefined,
443
- },
444
- create: {
445
- sequence: item.sequence !== undefined ? item.sequence : undefined,
446
- type: item.type !== undefined ? item.type : undefined,
447
- primary: item.primary !== undefined ? item.primary : undefined,
448
- note: item.note !== undefined ? item.note : undefined,
449
- status: item.status !== undefined ? item.status : undefined,
450
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
451
- },
452
- }))
453
- } : undefined,
454
- },
455
- update: {
456
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
457
- set: props.alpacaAccountId
458
- } : undefined,
459
- signal: props.signal !== undefined ? {
460
- set: props.signal
461
- } : undefined,
462
- strategy: props.strategy !== undefined ? {
463
- set: props.strategy
464
- } : undefined,
465
- analysis: props.analysis !== undefined ? {
466
- set: props.analysis
467
- } : undefined,
468
- summary: props.summary !== undefined ? {
469
- set: props.summary
470
- } : undefined,
471
- confidence: props.confidence !== undefined ? {
472
- set: props.confidence
473
- } : undefined,
474
- timestamp: props.timestamp !== undefined ? {
475
- set: props.timestamp
476
- } : undefined,
477
- status: props.status !== undefined ? {
478
- set: props.status
479
- } : undefined,
480
- symbol: props.symbol !== undefined ? {
481
- set: props.symbol
482
- } : undefined,
483
- entryPrice: props.entryPrice !== undefined ? {
484
- set: props.entryPrice
485
- } : undefined,
486
- exitPrice: props.exitPrice !== undefined ? {
487
- set: props.exitPrice
488
- } : undefined,
489
- entryQty: props.entryQty !== undefined ? {
490
- set: props.entryQty
491
- } : undefined,
492
- exitQty: props.exitQty !== undefined ? {
493
- set: props.exitQty
494
- } : undefined,
495
- entryValue: props.entryValue !== undefined ? {
496
- set: props.entryValue
497
- } : undefined,
498
- exitValue: props.exitValue !== undefined ? {
499
- set: props.exitValue
500
- } : undefined,
501
- entryTime: props.entryTime !== undefined ? {
502
- set: props.entryTime
503
- } : undefined,
504
- exitTime: props.exitTime !== undefined ? {
505
- set: props.exitTime
506
- } : undefined,
507
- pnlAmount: props.pnlAmount !== undefined ? {
508
- set: props.pnlAmount
509
- } : undefined,
510
- pnlPercent: props.pnlPercent !== undefined ? {
511
- set: props.pnlPercent
512
- } : undefined,
513
- durationMinutes: props.durationMinutes !== undefined ? {
514
- set: props.durationMinutes
515
- } : undefined,
516
- marketPhase: props.marketPhase !== undefined ? {
517
- set: props.marketPhase
518
- } : undefined,
519
- marketVolatility: props.marketVolatility !== undefined ? {
520
- set: props.marketVolatility
521
- } : undefined,
522
- thresholdsJson: props.thresholdsJson !== undefined ? {
523
- set: props.thresholdsJson
524
- } : undefined,
525
- actions: props.actions ?
526
- Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
527
- connect: props.actions.map((item) => ({
528
- id: item.id
529
- }))
530
- } : { upsert: props.actions.map((item) => ({
531
- where: {
532
- id: item.id !== undefined ? item.id : undefined,
533
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
534
- tradeId: item.tradeId !== undefined ? {
535
- equals: item.tradeId
536
- } : undefined,
537
- },
538
- update: {
539
- id: item.id !== undefined ? {
540
- set: item.id
541
- } : undefined,
542
- sequence: item.sequence !== undefined ? {
543
- set: item.sequence
544
- } : undefined,
545
- type: item.type !== undefined ? {
546
- set: item.type
547
- } : undefined,
548
- primary: item.primary !== undefined ? {
549
- set: item.primary
550
- } : undefined,
551
- note: item.note !== undefined ? {
552
- set: item.note
553
- } : undefined,
554
- status: item.status !== undefined ? {
555
- set: item.status
556
- } : undefined,
557
- alpacaOrderId: item.alpacaOrderId !== undefined ? {
558
- set: item.alpacaOrderId
518
+ // Maximum number of retries for database connection issues
519
+ const MAX_RETRIES = 3;
520
+ let retryCount = 0;
521
+ let lastError = null;
522
+ // Retry loop to handle potential database connection issues
523
+ while (retryCount < MAX_RETRIES) {
524
+ try {
525
+ const [modules, client] = await Promise.all([
526
+ getApolloModules(),
527
+ globalClient
528
+ ? Promise.resolve(globalClient)
529
+ : importedClient
530
+ ]);
531
+ const { gql, ApolloError } = modules;
532
+ const UPSERT_ONE_TRADE = gql `
533
+ mutation upsertOneTrade($where: TradeWhereUniqueInput!, $create: TradeCreateInput!, $update: TradeUpdateInput!) {
534
+ upsertOneTrade(where: $where, create: $create, update: $update) {
535
+ ${selectionSet}
536
+ }
537
+ }`;
538
+ const variables = {
539
+ where: {
540
+ id: props.id !== undefined ? props.id : undefined,
541
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
542
+ signal: props.signal !== undefined ? {
543
+ equals: props.signal
544
+ } : undefined,
545
+ strategy: props.strategy !== undefined ? {
546
+ equals: props.strategy
547
+ } : undefined,
548
+ analysis: props.analysis !== undefined ? {
549
+ equals: props.analysis
550
+ } : undefined,
551
+ summary: props.summary !== undefined ? {
552
+ equals: props.summary
553
+ } : undefined,
554
+ confidence: props.confidence !== undefined ? {
555
+ equals: props.confidence
556
+ } : undefined,
557
+ timestamp: props.timestamp !== undefined ? {
558
+ equals: props.timestamp
559
+ } : undefined,
560
+ createdAt: props.createdAt !== undefined ? {
561
+ equals: props.createdAt
562
+ } : undefined,
563
+ updatedAt: props.updatedAt !== undefined ? {
564
+ equals: props.updatedAt
565
+ } : undefined,
566
+ status: props.status !== undefined ? {
567
+ equals: props.status
568
+ } : undefined,
569
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
570
+ entryTime: props.entryTime !== undefined ? {
571
+ equals: props.entryTime
572
+ } : undefined,
573
+ exitTime: props.exitTime !== undefined ? {
574
+ equals: props.exitTime
575
+ } : undefined,
576
+ marketPhase: props.marketPhase !== undefined ? {
577
+ equals: props.marketPhase
578
+ } : undefined,
579
+ marketVolatility: props.marketVolatility !== undefined ? {
580
+ equals: props.marketVolatility
581
+ } : undefined,
582
+ thresholdsJson: props.thresholdsJson !== undefined ? {
583
+ equals: props.thresholdsJson
584
+ } : undefined,
585
+ },
586
+ create: {
587
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
588
+ signal: props.signal !== undefined ? props.signal : undefined,
589
+ strategy: props.strategy !== undefined ? props.strategy : undefined,
590
+ analysis: props.analysis !== undefined ? props.analysis : undefined,
591
+ summary: props.summary !== undefined ? props.summary : undefined,
592
+ confidence: props.confidence !== undefined ? props.confidence : undefined,
593
+ timestamp: props.timestamp !== undefined ? props.timestamp : undefined,
594
+ status: props.status !== undefined ? props.status : undefined,
595
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
596
+ entryPrice: props.entryPrice !== undefined ? props.entryPrice : undefined,
597
+ exitPrice: props.exitPrice !== undefined ? props.exitPrice : undefined,
598
+ entryQty: props.entryQty !== undefined ? props.entryQty : undefined,
599
+ exitQty: props.exitQty !== undefined ? props.exitQty : undefined,
600
+ entryValue: props.entryValue !== undefined ? props.entryValue : undefined,
601
+ exitValue: props.exitValue !== undefined ? props.exitValue : undefined,
602
+ entryTime: props.entryTime !== undefined ? props.entryTime : undefined,
603
+ exitTime: props.exitTime !== undefined ? props.exitTime : undefined,
604
+ pnlAmount: props.pnlAmount !== undefined ? props.pnlAmount : undefined,
605
+ pnlPercent: props.pnlPercent !== undefined ? props.pnlPercent : undefined,
606
+ durationMinutes: props.durationMinutes !== undefined ? props.durationMinutes : undefined,
607
+ marketPhase: props.marketPhase !== undefined ? props.marketPhase : undefined,
608
+ marketVolatility: props.marketVolatility !== undefined ? props.marketVolatility : undefined,
609
+ thresholdsJson: props.thresholdsJson !== undefined ? props.thresholdsJson : undefined,
610
+ actions: props.actions ?
611
+ Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && 'id' in item && Object.keys(item).length === 1) ? {
612
+ connect: props.actions.map((item) => ({
613
+ id: item.id
614
+ }))
615
+ }
616
+ : { connectOrCreate: props.actions.map((item) => ({
617
+ where: {
618
+ id: item.id !== undefined ? item.id : undefined,
619
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
620
+ tradeId: item.tradeId !== undefined ? {
621
+ equals: item.tradeId
622
+ } : undefined,
623
+ },
624
+ create: {
625
+ sequence: item.sequence !== undefined ? item.sequence : undefined,
626
+ type: item.type !== undefined ? item.type : undefined,
627
+ primary: item.primary !== undefined ? item.primary : undefined,
628
+ note: item.note !== undefined ? item.note : undefined,
629
+ status: item.status !== undefined ? item.status : undefined,
630
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
631
+ },
632
+ }))
559
633
  } : undefined,
560
- },
561
- create: {
562
- sequence: item.sequence !== undefined ? item.sequence : undefined,
563
- type: item.type !== undefined ? item.type : undefined,
564
- primary: item.primary !== undefined ? item.primary : undefined,
565
- note: item.note !== undefined ? item.note : undefined,
566
- status: item.status !== undefined ? item.status : undefined,
567
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
568
- },
569
- }))
570
- } : undefined,
571
- },
572
- };
573
- const filteredVariables = removeUndefinedProps(variables);
574
- try {
575
- const response = await client.mutate({ mutation: UPSERT_ONE_TRADE, variables: filteredVariables });
576
- if (response.errors && response.errors.length > 0)
577
- throw new Error(response.errors[0].message);
578
- if (response && response.data && response.data.upsertOneTrade) {
579
- return response.data.upsertOneTrade;
634
+ },
635
+ update: {
636
+ alpacaAccountId: props.alpacaAccountId !== undefined ? {
637
+ set: props.alpacaAccountId
638
+ } : undefined,
639
+ signal: props.signal !== undefined ? {
640
+ set: props.signal
641
+ } : undefined,
642
+ strategy: props.strategy !== undefined ? {
643
+ set: props.strategy
644
+ } : undefined,
645
+ analysis: props.analysis !== undefined ? {
646
+ set: props.analysis
647
+ } : undefined,
648
+ summary: props.summary !== undefined ? {
649
+ set: props.summary
650
+ } : undefined,
651
+ confidence: props.confidence !== undefined ? {
652
+ set: props.confidence
653
+ } : undefined,
654
+ timestamp: props.timestamp !== undefined ? {
655
+ set: props.timestamp
656
+ } : undefined,
657
+ status: props.status !== undefined ? {
658
+ set: props.status
659
+ } : undefined,
660
+ symbol: props.symbol !== undefined ? {
661
+ set: props.symbol
662
+ } : undefined,
663
+ entryPrice: props.entryPrice !== undefined ? {
664
+ set: props.entryPrice
665
+ } : undefined,
666
+ exitPrice: props.exitPrice !== undefined ? {
667
+ set: props.exitPrice
668
+ } : undefined,
669
+ entryQty: props.entryQty !== undefined ? {
670
+ set: props.entryQty
671
+ } : undefined,
672
+ exitQty: props.exitQty !== undefined ? {
673
+ set: props.exitQty
674
+ } : undefined,
675
+ entryValue: props.entryValue !== undefined ? {
676
+ set: props.entryValue
677
+ } : undefined,
678
+ exitValue: props.exitValue !== undefined ? {
679
+ set: props.exitValue
680
+ } : undefined,
681
+ entryTime: props.entryTime !== undefined ? {
682
+ set: props.entryTime
683
+ } : undefined,
684
+ exitTime: props.exitTime !== undefined ? {
685
+ set: props.exitTime
686
+ } : undefined,
687
+ pnlAmount: props.pnlAmount !== undefined ? {
688
+ set: props.pnlAmount
689
+ } : undefined,
690
+ pnlPercent: props.pnlPercent !== undefined ? {
691
+ set: props.pnlPercent
692
+ } : undefined,
693
+ durationMinutes: props.durationMinutes !== undefined ? {
694
+ set: props.durationMinutes
695
+ } : undefined,
696
+ marketPhase: props.marketPhase !== undefined ? {
697
+ set: props.marketPhase
698
+ } : undefined,
699
+ marketVolatility: props.marketVolatility !== undefined ? {
700
+ set: props.marketVolatility
701
+ } : undefined,
702
+ thresholdsJson: props.thresholdsJson !== undefined ? {
703
+ set: props.thresholdsJson
704
+ } : undefined,
705
+ actions: props.actions ?
706
+ Array.isArray(props.actions) && props.actions.length > 0 && props.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
707
+ connect: props.actions.map((item) => ({
708
+ id: item.id
709
+ }))
710
+ } : { upsert: props.actions.map((item) => ({
711
+ where: {
712
+ id: item.id !== undefined ? item.id : undefined,
713
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
714
+ tradeId: item.tradeId !== undefined ? {
715
+ equals: item.tradeId
716
+ } : undefined,
717
+ },
718
+ update: {
719
+ id: item.id !== undefined ? {
720
+ set: item.id
721
+ } : undefined,
722
+ sequence: item.sequence !== undefined ? {
723
+ set: item.sequence
724
+ } : undefined,
725
+ type: item.type !== undefined ? {
726
+ set: item.type
727
+ } : undefined,
728
+ primary: item.primary !== undefined ? {
729
+ set: item.primary
730
+ } : undefined,
731
+ note: item.note !== undefined ? {
732
+ set: item.note
733
+ } : undefined,
734
+ status: item.status !== undefined ? {
735
+ set: item.status
736
+ } : undefined,
737
+ alpacaOrderId: item.alpacaOrderId !== undefined ? {
738
+ set: item.alpacaOrderId
739
+ } : undefined,
740
+ },
741
+ create: {
742
+ sequence: item.sequence !== undefined ? item.sequence : undefined,
743
+ type: item.type !== undefined ? item.type : undefined,
744
+ primary: item.primary !== undefined ? item.primary : undefined,
745
+ note: item.note !== undefined ? item.note : undefined,
746
+ status: item.status !== undefined ? item.status : undefined,
747
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
748
+ },
749
+ }))
750
+ } : undefined,
751
+ },
752
+ };
753
+ const filteredVariables = removeUndefinedProps(variables);
754
+ const response = await client.mutate({
755
+ mutation: UPSERT_ONE_TRADE,
756
+ variables: filteredVariables,
757
+ // Don't cache mutations, but ensure we're using the freshest context
758
+ fetchPolicy: 'no-cache'
759
+ });
760
+ if (response.errors && response.errors.length > 0)
761
+ throw new Error(response.errors[0].message);
762
+ if (response && response.data && response.data.upsertOneTrade) {
763
+ return response.data.upsertOneTrade;
764
+ }
765
+ else {
766
+ return null;
767
+ }
580
768
  }
581
- else {
582
- return null;
769
+ catch (error) {
770
+ lastError = error;
771
+ // Check if this is a database connection error that we should retry
772
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
773
+ error.message?.includes('Cannot reach database server') ||
774
+ error.message?.includes('Connection timed out') ||
775
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
776
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
777
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
778
+ retryCount++;
779
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
780
+ console.warn("Database connection error, retrying...");
781
+ await new Promise(resolve => setTimeout(resolve, delay));
782
+ continue;
783
+ }
784
+ // Log the error and rethrow
785
+ console.error("Database error occurred:", error);
786
+ throw error;
583
787
  }
584
788
  }
585
- catch (error) {
586
- console.error('Error in upsertOneTrade:', error);
587
- throw error;
588
- }
789
+ // If we exhausted retries, throw the last error
790
+ throw lastError;
589
791
  },
590
792
  /**
591
793
  * Update multiple Trade records.
794
+ * Enhanced with connection resilience against Prisma connection errors.
592
795
  * @param props - Array of Trade objects for the updated records.
593
796
  * @param globalClient - Apollo Client instance.
594
797
  * @returns The count of created records or null.
595
798
  */
596
799
  async updateMany(props, globalClient) {
597
- const [modules, client] = await Promise.all([
598
- getApolloModules(),
599
- globalClient
600
- ? Promise.resolve(globalClient)
601
- : importedClient
602
- ]);
603
- const { gql, ApolloError } = modules;
604
- const UPDATE_MANY_TRADE = gql `
605
- mutation updateManyTrade($data: [TradeCreateManyInput!]!) {
606
- updateManyTrade(data: $data) {
607
- count
608
- }
609
- }`;
610
- const variables = props.map(prop => ({
611
- where: {
612
- id: prop.id !== undefined ? prop.id : undefined,
613
- alpacaAccountId: prop.alpacaAccountId !== undefined ? {
614
- equals: prop.alpacaAccountId
615
- } : undefined,
616
- symbol: prop.symbol !== undefined ? {
617
- equals: prop.symbol
618
- } : undefined,
619
- },
620
- data: {
621
- id: prop.id !== undefined ? {
622
- set: prop.id
623
- } : undefined,
624
- alpacaAccountId: prop.alpacaAccountId !== undefined ? {
625
- set: prop.alpacaAccountId
626
- } : undefined,
627
- signal: prop.signal !== undefined ? {
628
- set: prop.signal
629
- } : undefined,
630
- strategy: prop.strategy !== undefined ? {
631
- set: prop.strategy
632
- } : undefined,
633
- analysis: prop.analysis !== undefined ? {
634
- set: prop.analysis
635
- } : undefined,
636
- summary: prop.summary !== undefined ? {
637
- set: prop.summary
638
- } : undefined,
639
- confidence: prop.confidence !== undefined ? {
640
- set: prop.confidence
641
- } : undefined,
642
- timestamp: prop.timestamp !== undefined ? {
643
- set: prop.timestamp
644
- } : undefined,
645
- createdAt: prop.createdAt !== undefined ? {
646
- set: prop.createdAt
647
- } : undefined,
648
- updatedAt: prop.updatedAt !== undefined ? {
649
- set: prop.updatedAt
650
- } : undefined,
651
- status: prop.status !== undefined ? {
652
- set: prop.status
653
- } : undefined,
654
- symbol: prop.symbol !== undefined ? {
655
- set: prop.symbol
656
- } : undefined,
657
- entryPrice: prop.entryPrice !== undefined ? {
658
- set: prop.entryPrice
659
- } : undefined,
660
- exitPrice: prop.exitPrice !== undefined ? {
661
- set: prop.exitPrice
662
- } : undefined,
663
- entryQty: prop.entryQty !== undefined ? {
664
- set: prop.entryQty
665
- } : undefined,
666
- exitQty: prop.exitQty !== undefined ? {
667
- set: prop.exitQty
668
- } : undefined,
669
- entryValue: prop.entryValue !== undefined ? {
670
- set: prop.entryValue
671
- } : undefined,
672
- exitValue: prop.exitValue !== undefined ? {
673
- set: prop.exitValue
674
- } : undefined,
675
- entryTime: prop.entryTime !== undefined ? {
676
- set: prop.entryTime
677
- } : undefined,
678
- exitTime: prop.exitTime !== undefined ? {
679
- set: prop.exitTime
680
- } : undefined,
681
- pnlAmount: prop.pnlAmount !== undefined ? {
682
- set: prop.pnlAmount
683
- } : undefined,
684
- pnlPercent: prop.pnlPercent !== undefined ? {
685
- set: prop.pnlPercent
686
- } : undefined,
687
- durationMinutes: prop.durationMinutes !== undefined ? {
688
- set: prop.durationMinutes
689
- } : undefined,
690
- marketPhase: prop.marketPhase !== undefined ? {
691
- set: prop.marketPhase
692
- } : undefined,
693
- marketVolatility: prop.marketVolatility !== undefined ? {
694
- set: prop.marketVolatility
695
- } : undefined,
696
- thresholdsJson: prop.thresholdsJson !== undefined ? {
697
- set: prop.thresholdsJson
698
- } : undefined,
699
- actions: prop.actions ?
700
- Array.isArray(prop.actions) && prop.actions.length > 0 && prop.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
701
- connect: prop.actions.map((item) => ({
702
- id: item.id
703
- }))
704
- } : { upsert: prop.actions.map((item) => ({
705
- where: {
706
- id: item.id !== undefined ? item.id : undefined,
707
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
708
- tradeId: item.tradeId !== undefined ? {
709
- equals: item.tradeId
710
- } : undefined,
711
- },
712
- update: {
713
- id: item.id !== undefined ? {
714
- set: item.id
715
- } : undefined,
716
- sequence: item.sequence !== undefined ? {
717
- set: item.sequence
718
- } : undefined,
719
- type: item.type !== undefined ? {
720
- set: item.type
721
- } : undefined,
722
- primary: item.primary !== undefined ? {
723
- set: item.primary
724
- } : undefined,
725
- note: item.note !== undefined ? {
726
- set: item.note
727
- } : undefined,
728
- status: item.status !== undefined ? {
729
- set: item.status
730
- } : undefined,
731
- alpacaOrderId: item.alpacaOrderId !== undefined ? {
732
- set: item.alpacaOrderId
733
- } : undefined,
734
- },
735
- create: {
736
- sequence: item.sequence !== undefined ? item.sequence : undefined,
737
- type: item.type !== undefined ? item.type : undefined,
738
- primary: item.primary !== undefined ? item.primary : undefined,
739
- note: item.note !== undefined ? item.note : undefined,
740
- status: item.status !== undefined ? item.status : undefined,
741
- alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
742
- },
743
- }))
744
- } : undefined,
745
- },
746
- }));
747
- const filteredVariables = removeUndefinedProps(variables);
748
- try {
749
- const response = await client.mutate({ mutation: UPDATE_MANY_TRADE, variables: filteredVariables });
750
- if (response.errors && response.errors.length > 0)
751
- throw new Error(response.errors[0].message);
752
- if (response && response.data && response.data.updateManyTrade) {
753
- return response.data.updateManyTrade;
800
+ // Maximum number of retries for database connection issues
801
+ const MAX_RETRIES = 3;
802
+ let retryCount = 0;
803
+ let lastError = null;
804
+ // Retry loop to handle potential database connection issues
805
+ while (retryCount < MAX_RETRIES) {
806
+ try {
807
+ const [modules, client] = await Promise.all([
808
+ getApolloModules(),
809
+ globalClient
810
+ ? Promise.resolve(globalClient)
811
+ : importedClient
812
+ ]);
813
+ const { gql, ApolloError } = modules;
814
+ const UPDATE_MANY_TRADE = gql `
815
+ mutation updateManyTrade($data: [TradeCreateManyInput!]!) {
816
+ updateManyTrade(data: $data) {
817
+ count
754
818
  }
755
- else {
756
- return null;
819
+ }`;
820
+ const variables = props.map(prop => ({
821
+ where: {
822
+ id: prop.id !== undefined ? prop.id : undefined,
823
+ alpacaAccountId: prop.alpacaAccountId !== undefined ? prop.alpacaAccountId : undefined,
824
+ signal: prop.signal !== undefined ? {
825
+ equals: prop.signal
826
+ } : undefined,
827
+ strategy: prop.strategy !== undefined ? {
828
+ equals: prop.strategy
829
+ } : undefined,
830
+ analysis: prop.analysis !== undefined ? {
831
+ equals: prop.analysis
832
+ } : undefined,
833
+ summary: prop.summary !== undefined ? {
834
+ equals: prop.summary
835
+ } : undefined,
836
+ confidence: prop.confidence !== undefined ? {
837
+ equals: prop.confidence
838
+ } : undefined,
839
+ timestamp: prop.timestamp !== undefined ? {
840
+ equals: prop.timestamp
841
+ } : undefined,
842
+ createdAt: prop.createdAt !== undefined ? {
843
+ equals: prop.createdAt
844
+ } : undefined,
845
+ updatedAt: prop.updatedAt !== undefined ? {
846
+ equals: prop.updatedAt
847
+ } : undefined,
848
+ status: prop.status !== undefined ? {
849
+ equals: prop.status
850
+ } : undefined,
851
+ symbol: prop.symbol !== undefined ? prop.symbol : undefined,
852
+ entryTime: prop.entryTime !== undefined ? {
853
+ equals: prop.entryTime
854
+ } : undefined,
855
+ exitTime: prop.exitTime !== undefined ? {
856
+ equals: prop.exitTime
857
+ } : undefined,
858
+ marketPhase: prop.marketPhase !== undefined ? {
859
+ equals: prop.marketPhase
860
+ } : undefined,
861
+ marketVolatility: prop.marketVolatility !== undefined ? {
862
+ equals: prop.marketVolatility
863
+ } : undefined,
864
+ thresholdsJson: prop.thresholdsJson !== undefined ? {
865
+ equals: prop.thresholdsJson
866
+ } : undefined,
867
+ },
868
+ data: {
869
+ id: prop.id !== undefined ? {
870
+ set: prop.id
871
+ } : undefined,
872
+ alpacaAccountId: prop.alpacaAccountId !== undefined ? {
873
+ set: prop.alpacaAccountId
874
+ } : undefined,
875
+ signal: prop.signal !== undefined ? {
876
+ set: prop.signal
877
+ } : undefined,
878
+ strategy: prop.strategy !== undefined ? {
879
+ set: prop.strategy
880
+ } : undefined,
881
+ analysis: prop.analysis !== undefined ? {
882
+ set: prop.analysis
883
+ } : undefined,
884
+ summary: prop.summary !== undefined ? {
885
+ set: prop.summary
886
+ } : undefined,
887
+ confidence: prop.confidence !== undefined ? {
888
+ set: prop.confidence
889
+ } : undefined,
890
+ timestamp: prop.timestamp !== undefined ? {
891
+ set: prop.timestamp
892
+ } : undefined,
893
+ createdAt: prop.createdAt !== undefined ? {
894
+ set: prop.createdAt
895
+ } : undefined,
896
+ updatedAt: prop.updatedAt !== undefined ? {
897
+ set: prop.updatedAt
898
+ } : undefined,
899
+ status: prop.status !== undefined ? {
900
+ set: prop.status
901
+ } : undefined,
902
+ symbol: prop.symbol !== undefined ? {
903
+ set: prop.symbol
904
+ } : undefined,
905
+ entryPrice: prop.entryPrice !== undefined ? {
906
+ set: prop.entryPrice
907
+ } : undefined,
908
+ exitPrice: prop.exitPrice !== undefined ? {
909
+ set: prop.exitPrice
910
+ } : undefined,
911
+ entryQty: prop.entryQty !== undefined ? {
912
+ set: prop.entryQty
913
+ } : undefined,
914
+ exitQty: prop.exitQty !== undefined ? {
915
+ set: prop.exitQty
916
+ } : undefined,
917
+ entryValue: prop.entryValue !== undefined ? {
918
+ set: prop.entryValue
919
+ } : undefined,
920
+ exitValue: prop.exitValue !== undefined ? {
921
+ set: prop.exitValue
922
+ } : undefined,
923
+ entryTime: prop.entryTime !== undefined ? {
924
+ set: prop.entryTime
925
+ } : undefined,
926
+ exitTime: prop.exitTime !== undefined ? {
927
+ set: prop.exitTime
928
+ } : undefined,
929
+ pnlAmount: prop.pnlAmount !== undefined ? {
930
+ set: prop.pnlAmount
931
+ } : undefined,
932
+ pnlPercent: prop.pnlPercent !== undefined ? {
933
+ set: prop.pnlPercent
934
+ } : undefined,
935
+ durationMinutes: prop.durationMinutes !== undefined ? {
936
+ set: prop.durationMinutes
937
+ } : undefined,
938
+ marketPhase: prop.marketPhase !== undefined ? {
939
+ set: prop.marketPhase
940
+ } : undefined,
941
+ marketVolatility: prop.marketVolatility !== undefined ? {
942
+ set: prop.marketVolatility
943
+ } : undefined,
944
+ thresholdsJson: prop.thresholdsJson !== undefined ? {
945
+ set: prop.thresholdsJson
946
+ } : undefined,
947
+ actions: prop.actions ?
948
+ Array.isArray(prop.actions) && prop.actions.length > 0 && prop.actions.every((item) => typeof item === 'object' && ('id' in item || 'symbol' in item) && Object.keys(item).length === 1) ? {
949
+ connect: prop.actions.map((item) => ({
950
+ id: item.id
951
+ }))
952
+ } : { upsert: prop.actions.map((item) => ({
953
+ where: {
954
+ id: item.id !== undefined ? item.id : undefined,
955
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
956
+ tradeId: item.tradeId !== undefined ? {
957
+ equals: item.tradeId
958
+ } : undefined,
959
+ },
960
+ update: {
961
+ id: item.id !== undefined ? {
962
+ set: item.id
963
+ } : undefined,
964
+ sequence: item.sequence !== undefined ? {
965
+ set: item.sequence
966
+ } : undefined,
967
+ type: item.type !== undefined ? {
968
+ set: item.type
969
+ } : undefined,
970
+ primary: item.primary !== undefined ? {
971
+ set: item.primary
972
+ } : undefined,
973
+ note: item.note !== undefined ? {
974
+ set: item.note
975
+ } : undefined,
976
+ status: item.status !== undefined ? {
977
+ set: item.status
978
+ } : undefined,
979
+ alpacaOrderId: item.alpacaOrderId !== undefined ? {
980
+ set: item.alpacaOrderId
981
+ } : undefined,
982
+ },
983
+ create: {
984
+ sequence: item.sequence !== undefined ? item.sequence : undefined,
985
+ type: item.type !== undefined ? item.type : undefined,
986
+ primary: item.primary !== undefined ? item.primary : undefined,
987
+ note: item.note !== undefined ? item.note : undefined,
988
+ status: item.status !== undefined ? item.status : undefined,
989
+ alpacaOrderId: item.alpacaOrderId !== undefined ? item.alpacaOrderId : undefined,
990
+ },
991
+ }))
992
+ } : undefined,
993
+ },
994
+ }));
995
+ const filteredVariables = removeUndefinedProps(variables);
996
+ const response = await client.mutate({
997
+ mutation: UPDATE_MANY_TRADE,
998
+ variables: filteredVariables,
999
+ // Don't cache mutations, but ensure we're using the freshest context
1000
+ fetchPolicy: 'no-cache'
1001
+ });
1002
+ if (response.errors && response.errors.length > 0)
1003
+ throw new Error(response.errors[0].message);
1004
+ if (response && response.data && response.data.updateManyTrade) {
1005
+ return response.data.updateManyTrade;
1006
+ }
1007
+ else {
1008
+ return null;
1009
+ }
1010
+ }
1011
+ catch (error) {
1012
+ lastError = error;
1013
+ // Check if this is a database connection error that we should retry
1014
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
1015
+ error.message?.includes('Cannot reach database server') ||
1016
+ error.message?.includes('Connection timed out') ||
1017
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
1018
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
1019
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
1020
+ retryCount++;
1021
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
1022
+ console.warn("Database connection error, retrying...");
1023
+ await new Promise(resolve => setTimeout(resolve, delay));
1024
+ continue;
1025
+ }
1026
+ // Log the error and rethrow
1027
+ console.error("Database error occurred:", error);
1028
+ throw error;
757
1029
  }
758
1030
  }
759
- catch (error) {
760
- console.error('Error in updateManyTrade:', error);
761
- throw error;
762
- }
1031
+ // If we exhausted retries, throw the last error
1032
+ throw lastError;
763
1033
  },
764
1034
  /**
765
1035
  * Delete a single Trade record.
766
- * @param props - Properties to update.
1036
+ * Enhanced with connection resilience against Prisma connection errors.
1037
+ * @param props - Properties to identify the record to delete.
767
1038
  * @param globalClient - Apollo Client instance.
768
1039
  * @returns The deleted Trade or null.
769
1040
  */
770
1041
  async delete(props, globalClient) {
771
- const [modules, client] = await Promise.all([
772
- getApolloModules(),
773
- globalClient
774
- ? Promise.resolve(globalClient)
775
- : importedClient
776
- ]);
777
- const { gql, ApolloError } = modules;
778
- const DELETE_ONE_TRADE = gql `
779
- mutation deleteOneTrade($where: TradeWhereUniqueInput!) {
780
- deleteOneTrade(where: $where) {
781
- id
782
- }
783
- }`;
784
- const variables = {
785
- where: {
786
- id: props.id ? props.id : undefined,
1042
+ // Maximum number of retries for database connection issues
1043
+ const MAX_RETRIES = 3;
1044
+ let retryCount = 0;
1045
+ let lastError = null;
1046
+ // Retry loop to handle potential database connection issues
1047
+ while (retryCount < MAX_RETRIES) {
1048
+ try {
1049
+ const [modules, client] = await Promise.all([
1050
+ getApolloModules(),
1051
+ globalClient
1052
+ ? Promise.resolve(globalClient)
1053
+ : importedClient
1054
+ ]);
1055
+ const { gql, ApolloError } = modules;
1056
+ const DELETE_ONE_TRADE = gql `
1057
+ mutation deleteOneTrade($where: TradeWhereUniqueInput!) {
1058
+ deleteOneTrade(where: $where) {
1059
+ id
787
1060
  }
788
- };
789
- const filteredVariables = removeUndefinedProps(variables);
790
- try {
791
- const response = await client.mutate({ mutation: DELETE_ONE_TRADE, variables: filteredVariables });
792
- if (response.errors && response.errors.length > 0)
793
- throw new Error(response.errors[0].message);
794
- if (response && response.data && response.data.deleteOneTrade) {
795
- return response.data.deleteOneTrade;
1061
+ }`;
1062
+ const variables = {
1063
+ where: {
1064
+ id: props.id ? props.id : undefined,
1065
+ }
1066
+ };
1067
+ const filteredVariables = removeUndefinedProps(variables);
1068
+ const response = await client.mutate({
1069
+ mutation: DELETE_ONE_TRADE,
1070
+ variables: filteredVariables,
1071
+ // Don't cache mutations, but ensure we're using the freshest context
1072
+ fetchPolicy: 'no-cache'
1073
+ });
1074
+ if (response.errors && response.errors.length > 0)
1075
+ throw new Error(response.errors[0].message);
1076
+ if (response && response.data && response.data.deleteOneTrade) {
1077
+ return response.data.deleteOneTrade;
1078
+ }
1079
+ else {
1080
+ return null;
1081
+ }
796
1082
  }
797
- else {
798
- return null;
1083
+ catch (error) {
1084
+ lastError = error;
1085
+ // Check if this is a database connection error that we should retry
1086
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
1087
+ error.message?.includes('Cannot reach database server') ||
1088
+ error.message?.includes('Connection timed out') ||
1089
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
1090
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
1091
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
1092
+ retryCount++;
1093
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
1094
+ console.warn("Database connection error, retrying...");
1095
+ await new Promise(resolve => setTimeout(resolve, delay));
1096
+ continue;
1097
+ }
1098
+ // Log the error and rethrow
1099
+ console.error("Database error occurred:", error);
1100
+ throw error;
799
1101
  }
800
1102
  }
801
- catch (error) {
802
- console.error('Error in deleteOneTrade:', error);
803
- throw error;
804
- }
1103
+ // If we exhausted retries, throw the last error
1104
+ throw lastError;
805
1105
  },
806
1106
  /**
807
1107
  * Retrieve a single Trade record by ID.
808
- * @param props - Properties to update.
1108
+ * Enhanced with connection resilience against Prisma connection errors.
1109
+ * @param props - Properties to identify the record.
809
1110
  * @param globalClient - Apollo Client instance.
1111
+ * @param whereInput - Optional custom where input.
810
1112
  * @returns The retrieved Trade or null.
811
1113
  */
812
1114
  async get(props, globalClient, whereInput) {
813
- const [modules, client] = await Promise.all([
814
- getApolloModules(),
815
- globalClient
816
- ? Promise.resolve(globalClient)
817
- : importedClient
818
- ]);
819
- const { gql, ApolloError } = modules;
820
- const GET_TRADE = gql `
821
- query getTrade($where: TradeWhereUniqueInput!) {
822
- getTrade(where: $where) {
823
- ${selectionSet}
824
- }
825
- }`;
826
- const variables = {
827
- where: whereInput ? whereInput : {
828
- id: props.id !== undefined ? props.id : undefined,
829
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
830
- equals: props.alpacaAccountId
831
- } : undefined,
832
- symbol: props.symbol !== undefined ? {
833
- equals: props.symbol
834
- } : undefined,
835
- },
836
- };
837
- const filteredVariables = removeUndefinedProps(variables);
838
- try {
839
- const response = await client.query({ query: GET_TRADE, variables: filteredVariables });
840
- if (response.errors && response.errors.length > 0)
841
- throw new Error(response.errors[0].message);
842
- return response.data?.getTrade ?? null;
843
- }
844
- catch (error) {
845
- if (error instanceof ApolloError && error.message === 'No Trade found') {
846
- return null;
1115
+ // Maximum number of retries for database connection issues
1116
+ const MAX_RETRIES = 3;
1117
+ let retryCount = 0;
1118
+ let lastError = null;
1119
+ // Retry loop to handle potential database connection issues
1120
+ while (retryCount < MAX_RETRIES) {
1121
+ try {
1122
+ const [modules, client] = await Promise.all([
1123
+ getApolloModules(),
1124
+ globalClient
1125
+ ? Promise.resolve(globalClient)
1126
+ : importedClient
1127
+ ]);
1128
+ const { gql, ApolloError } = modules;
1129
+ const GET_TRADE = gql `
1130
+ query getTrade($where: TradeWhereUniqueInput!) {
1131
+ getTrade(where: $where) {
1132
+ ${selectionSet}
1133
+ }
1134
+ }`;
1135
+ const variables = {
1136
+ where: whereInput ? whereInput : {
1137
+ id: props.id !== undefined ? props.id : undefined,
1138
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
1139
+ signal: props.signal !== undefined ? {
1140
+ equals: props.signal
1141
+ } : undefined,
1142
+ strategy: props.strategy !== undefined ? {
1143
+ equals: props.strategy
1144
+ } : undefined,
1145
+ analysis: props.analysis !== undefined ? {
1146
+ equals: props.analysis
1147
+ } : undefined,
1148
+ summary: props.summary !== undefined ? {
1149
+ equals: props.summary
1150
+ } : undefined,
1151
+ confidence: props.confidence !== undefined ? {
1152
+ equals: props.confidence
1153
+ } : undefined,
1154
+ timestamp: props.timestamp !== undefined ? {
1155
+ equals: props.timestamp
1156
+ } : undefined,
1157
+ createdAt: props.createdAt !== undefined ? {
1158
+ equals: props.createdAt
1159
+ } : undefined,
1160
+ updatedAt: props.updatedAt !== undefined ? {
1161
+ equals: props.updatedAt
1162
+ } : undefined,
1163
+ status: props.status !== undefined ? {
1164
+ equals: props.status
1165
+ } : undefined,
1166
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
1167
+ entryTime: props.entryTime !== undefined ? {
1168
+ equals: props.entryTime
1169
+ } : undefined,
1170
+ exitTime: props.exitTime !== undefined ? {
1171
+ equals: props.exitTime
1172
+ } : undefined,
1173
+ marketPhase: props.marketPhase !== undefined ? {
1174
+ equals: props.marketPhase
1175
+ } : undefined,
1176
+ marketVolatility: props.marketVolatility !== undefined ? {
1177
+ equals: props.marketVolatility
1178
+ } : undefined,
1179
+ thresholdsJson: props.thresholdsJson !== undefined ? {
1180
+ equals: props.thresholdsJson
1181
+ } : undefined,
1182
+ },
1183
+ };
1184
+ const filteredVariables = removeUndefinedProps(variables);
1185
+ const response = await client.query({
1186
+ query: GET_TRADE,
1187
+ variables: filteredVariables,
1188
+ fetchPolicy: 'network-only', // Force network request to avoid stale cache
1189
+ });
1190
+ if (response.errors && response.errors.length > 0)
1191
+ throw new Error(response.errors[0].message);
1192
+ return response.data?.getTrade ?? null;
847
1193
  }
848
- else {
849
- console.error('Error in getTrade:', error);
1194
+ catch (error) {
1195
+ lastError = error;
1196
+ // Check if this is a "No record found" error - this is an expected condition, not a failure
1197
+ if (error.message === 'No Trade found') {
1198
+ return null;
1199
+ }
1200
+ // Check if this is a database connection error that we should retry
1201
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
1202
+ error.message?.includes('Cannot reach database server') ||
1203
+ error.message?.includes('Connection timed out') ||
1204
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
1205
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
1206
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
1207
+ retryCount++;
1208
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
1209
+ console.warn("Database connection error, retrying...");
1210
+ await new Promise(resolve => setTimeout(resolve, delay));
1211
+ continue;
1212
+ }
1213
+ // Log the error and rethrow
1214
+ console.error("Database error occurred:", error);
850
1215
  throw error;
851
1216
  }
852
1217
  }
1218
+ // If we exhausted retries, throw the last error
1219
+ throw lastError;
853
1220
  },
854
1221
  /**
855
1222
  * Retrieve all Trades records.
1223
+ * Enhanced with connection resilience against Prisma connection errors.
856
1224
  * @param globalClient - Apollo Client instance.
857
1225
  * @returns An array of Trade records or null.
858
1226
  */
859
1227
  async getAll(globalClient) {
860
- const [modules, client] = await Promise.all([
861
- getApolloModules(),
862
- globalClient
863
- ? Promise.resolve(globalClient)
864
- : importedClient
865
- ]);
866
- const { gql, ApolloError } = modules;
867
- const GET_ALL_TRADE = gql `
868
- query getAllTrade {
869
- trades {
870
- ${selectionSet}
871
- }
872
- }`;
873
- try {
874
- const response = await client.query({ query: GET_ALL_TRADE });
875
- if (response.errors && response.errors.length > 0)
876
- throw new Error(response.errors[0].message);
877
- return response.data?.trades ?? null;
878
- }
879
- catch (error) {
880
- if (error instanceof ApolloError && error.message === 'No Trade found') {
881
- return null;
1228
+ // Maximum number of retries for database connection issues
1229
+ const MAX_RETRIES = 3;
1230
+ let retryCount = 0;
1231
+ let lastError = null;
1232
+ // Retry loop to handle potential database connection issues
1233
+ while (retryCount < MAX_RETRIES) {
1234
+ try {
1235
+ const [modules, client] = await Promise.all([
1236
+ getApolloModules(),
1237
+ globalClient
1238
+ ? Promise.resolve(globalClient)
1239
+ : importedClient
1240
+ ]);
1241
+ const { gql, ApolloError } = modules;
1242
+ const GET_ALL_TRADE = gql `
1243
+ query getAllTrade {
1244
+ trades {
1245
+ ${selectionSet}
1246
+ }
1247
+ }`;
1248
+ const response = await client.query({
1249
+ query: GET_ALL_TRADE,
1250
+ fetchPolicy: 'network-only', // Force network request to avoid stale cache
1251
+ });
1252
+ if (response.errors && response.errors.length > 0)
1253
+ throw new Error(response.errors[0].message);
1254
+ return response.data?.trades ?? null;
882
1255
  }
883
- else {
884
- console.error('Error in getTrade:', error);
1256
+ catch (error) {
1257
+ lastError = error;
1258
+ // Check if this is a "No record found" error - this is an expected condition, not a failure
1259
+ if (error.message === 'No Trade found') {
1260
+ return null;
1261
+ }
1262
+ // Check if this is a database connection error that we should retry
1263
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
1264
+ error.message?.includes('Cannot reach database server') ||
1265
+ error.message?.includes('Connection timed out') ||
1266
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
1267
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
1268
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
1269
+ retryCount++;
1270
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
1271
+ console.warn("Database connection error, retrying...");
1272
+ await new Promise(resolve => setTimeout(resolve, delay));
1273
+ continue;
1274
+ }
1275
+ // Log the error and rethrow
1276
+ console.error("Database error occurred:", error);
885
1277
  throw error;
886
1278
  }
887
1279
  }
1280
+ // If we exhausted retries, throw the last error
1281
+ throw lastError;
888
1282
  },
889
1283
  /**
890
1284
  * Find multiple Trade records based on conditions.
1285
+ * Enhanced with connection resilience against Prisma connection errors.
891
1286
  * @param props - Conditions to find records.
892
1287
  * @param globalClient - Apollo Client instance.
1288
+ * @param whereInput - Optional custom where input.
893
1289
  * @returns An array of found Trade records or null.
894
1290
  */
895
1291
  async findMany(props, globalClient, whereInput) {
896
- const [modules, client] = await Promise.all([
897
- getApolloModules(),
898
- globalClient
899
- ? Promise.resolve(globalClient)
900
- : importedClient
901
- ]);
902
- const { gql, ApolloError } = modules;
903
- const FIND_MANY_TRADE = gql `
904
- query findManyTrade($where: TradeWhereInput!) {
905
- trades(where: $where) {
906
- ${selectionSet}
907
- }
908
- }`;
909
- const variables = {
910
- where: whereInput ? whereInput : {
911
- id: props.id !== undefined ? {
912
- equals: props.id
913
- } : undefined,
914
- alpacaAccountId: props.alpacaAccountId !== undefined ? {
915
- equals: props.alpacaAccountId
916
- } : undefined,
917
- symbol: props.symbol !== undefined ? {
918
- equals: props.symbol
919
- } : undefined,
920
- },
921
- };
922
- const filteredVariables = removeUndefinedProps(variables);
923
- try {
924
- const response = await client.query({ query: FIND_MANY_TRADE, variables: filteredVariables });
925
- if (response.errors && response.errors.length > 0)
926
- throw new Error(response.errors[0].message);
927
- if (response && response.data && response.data.trades) {
928
- return response.data.trades;
1292
+ // Maximum number of retries for database connection issues
1293
+ const MAX_RETRIES = 3;
1294
+ let retryCount = 0;
1295
+ let lastError = null;
1296
+ // Retry loop to handle potential database connection issues
1297
+ while (retryCount < MAX_RETRIES) {
1298
+ try {
1299
+ const [modules, client] = await Promise.all([
1300
+ getApolloModules(),
1301
+ globalClient
1302
+ ? Promise.resolve(globalClient)
1303
+ : importedClient
1304
+ ]);
1305
+ const { gql, ApolloError } = modules;
1306
+ const FIND_MANY_TRADE = gql `
1307
+ query findManyTrade($where: TradeWhereInput!) {
1308
+ trades(where: $where) {
1309
+ ${selectionSet}
929
1310
  }
930
- else {
931
- return [];
932
- }
933
- }
934
- catch (error) {
935
- if (error instanceof ApolloError && error.message === 'No Trade found') {
936
- return null;
1311
+ }`;
1312
+ const variables = {
1313
+ where: whereInput ? whereInput : {
1314
+ id: props.id !== undefined ? props.id : undefined,
1315
+ alpacaAccountId: props.alpacaAccountId !== undefined ? props.alpacaAccountId : undefined,
1316
+ signal: props.signal !== undefined ? {
1317
+ equals: props.signal
1318
+ } : undefined,
1319
+ strategy: props.strategy !== undefined ? {
1320
+ equals: props.strategy
1321
+ } : undefined,
1322
+ analysis: props.analysis !== undefined ? {
1323
+ equals: props.analysis
1324
+ } : undefined,
1325
+ summary: props.summary !== undefined ? {
1326
+ equals: props.summary
1327
+ } : undefined,
1328
+ confidence: props.confidence !== undefined ? {
1329
+ equals: props.confidence
1330
+ } : undefined,
1331
+ timestamp: props.timestamp !== undefined ? {
1332
+ equals: props.timestamp
1333
+ } : undefined,
1334
+ createdAt: props.createdAt !== undefined ? {
1335
+ equals: props.createdAt
1336
+ } : undefined,
1337
+ updatedAt: props.updatedAt !== undefined ? {
1338
+ equals: props.updatedAt
1339
+ } : undefined,
1340
+ status: props.status !== undefined ? {
1341
+ equals: props.status
1342
+ } : undefined,
1343
+ symbol: props.symbol !== undefined ? props.symbol : undefined,
1344
+ entryTime: props.entryTime !== undefined ? {
1345
+ equals: props.entryTime
1346
+ } : undefined,
1347
+ exitTime: props.exitTime !== undefined ? {
1348
+ equals: props.exitTime
1349
+ } : undefined,
1350
+ marketPhase: props.marketPhase !== undefined ? {
1351
+ equals: props.marketPhase
1352
+ } : undefined,
1353
+ marketVolatility: props.marketVolatility !== undefined ? {
1354
+ equals: props.marketVolatility
1355
+ } : undefined,
1356
+ thresholdsJson: props.thresholdsJson !== undefined ? {
1357
+ equals: props.thresholdsJson
1358
+ } : undefined,
1359
+ },
1360
+ };
1361
+ const filteredVariables = removeUndefinedProps(variables);
1362
+ const response = await client.query({
1363
+ query: FIND_MANY_TRADE,
1364
+ variables: filteredVariables,
1365
+ fetchPolicy: 'network-only', // Force network request to avoid stale cache
1366
+ });
1367
+ if (response.errors && response.errors.length > 0)
1368
+ throw new Error(response.errors[0].message);
1369
+ if (response && response.data && response.data.trades) {
1370
+ return response.data.trades;
1371
+ }
1372
+ else {
1373
+ return [];
1374
+ }
937
1375
  }
938
- else {
939
- console.error('Error in getTrade:', error);
1376
+ catch (error) {
1377
+ lastError = error;
1378
+ // Check if this is a "No record found" error - this is an expected condition, not a failure
1379
+ if (error.message === 'No Trade found') {
1380
+ return null;
1381
+ }
1382
+ // Check if this is a database connection error that we should retry
1383
+ const isConnectionError = error.message?.includes('Server has closed the connection') ||
1384
+ error.message?.includes('Cannot reach database server') ||
1385
+ error.message?.includes('Connection timed out') ||
1386
+ error.message?.includes('Accelerate') || // Prisma Accelerate proxy errors
1387
+ (error.networkError && error.networkError.message?.includes('Failed to fetch'));
1388
+ if (isConnectionError && retryCount < MAX_RETRIES - 1) {
1389
+ retryCount++;
1390
+ const delay = Math.pow(2, retryCount) * 100; // Exponential backoff: 200ms, 400ms, 800ms
1391
+ console.warn("Database connection error, retrying...");
1392
+ await new Promise(resolve => setTimeout(resolve, delay));
1393
+ continue;
1394
+ }
1395
+ // Log the error and rethrow
1396
+ console.error("Database error occurred:", error);
940
1397
  throw error;
941
1398
  }
942
1399
  }
1400
+ // If we exhausted retries, throw the last error
1401
+ throw lastError;
943
1402
  }
944
1403
  };
945
1404
  //# sourceMappingURL=Trade.js.map