geek-cafe-saas-sdk 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl

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.

Potentially problematic release.


This version of geek-cafe-saas-sdk might be problematic. Click here for more details.

Files changed (79) hide show
  1. geek_cafe_saas_sdk/__init__.py +1 -1
  2. geek_cafe_saas_sdk/domains/files/models/directory.py +42 -6
  3. geek_cafe_saas_sdk/domains/files/models/file.py +40 -4
  4. geek_cafe_saas_sdk/domains/files/models/file_share.py +33 -0
  5. geek_cafe_saas_sdk/domains/files/models/file_version.py +24 -0
  6. geek_cafe_saas_sdk/domains/files/services/directory_service.py +54 -135
  7. geek_cafe_saas_sdk/domains/files/services/file_share_service.py +37 -120
  8. geek_cafe_saas_sdk/domains/files/services/file_system_service.py +40 -102
  9. geek_cafe_saas_sdk/domains/files/services/file_version_service.py +44 -124
  10. geek_cafe_saas_sdk/domains/messaging/services/contact_thread_service.py +55 -7
  11. geek_cafe_saas_sdk/domains/notifications/__init__.py +18 -0
  12. geek_cafe_saas_sdk/domains/notifications/handlers/__init__.py +1 -0
  13. geek_cafe_saas_sdk/domains/notifications/handlers/create_webhook/app.py +73 -0
  14. geek_cafe_saas_sdk/domains/notifications/handlers/get/app.py +40 -0
  15. geek_cafe_saas_sdk/domains/notifications/handlers/get_preferences/app.py +34 -0
  16. geek_cafe_saas_sdk/domains/notifications/handlers/list/app.py +43 -0
  17. geek_cafe_saas_sdk/domains/notifications/handlers/list_webhooks/app.py +40 -0
  18. geek_cafe_saas_sdk/domains/notifications/handlers/mark_read/app.py +40 -0
  19. geek_cafe_saas_sdk/domains/notifications/handlers/send/app.py +83 -0
  20. geek_cafe_saas_sdk/domains/notifications/handlers/update_preferences/app.py +45 -0
  21. geek_cafe_saas_sdk/domains/notifications/models/__init__.py +16 -0
  22. geek_cafe_saas_sdk/domains/notifications/models/notification.py +717 -0
  23. geek_cafe_saas_sdk/domains/notifications/models/notification_preference.py +365 -0
  24. geek_cafe_saas_sdk/domains/notifications/models/webhook_subscription.py +339 -0
  25. geek_cafe_saas_sdk/domains/notifications/services/__init__.py +10 -0
  26. geek_cafe_saas_sdk/domains/notifications/services/notification_service.py +576 -0
  27. geek_cafe_saas_sdk/domains/payments/__init__.py +16 -0
  28. geek_cafe_saas_sdk/domains/payments/handlers/README.md +334 -0
  29. geek_cafe_saas_sdk/domains/payments/handlers/__init__.py +6 -0
  30. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/create/app.py +105 -0
  31. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/get/app.py +60 -0
  32. geek_cafe_saas_sdk/domains/payments/handlers/billing_accounts/update/app.py +97 -0
  33. geek_cafe_saas_sdk/domains/payments/handlers/payment_intents/create/app.py +97 -0
  34. geek_cafe_saas_sdk/domains/payments/handlers/payment_intents/get/app.py +60 -0
  35. geek_cafe_saas_sdk/domains/payments/handlers/payments/get/app.py +60 -0
  36. geek_cafe_saas_sdk/domains/payments/handlers/payments/list/app.py +68 -0
  37. geek_cafe_saas_sdk/domains/payments/handlers/payments/record/app.py +118 -0
  38. geek_cafe_saas_sdk/domains/payments/handlers/refunds/create/app.py +89 -0
  39. geek_cafe_saas_sdk/domains/payments/handlers/refunds/get/app.py +60 -0
  40. geek_cafe_saas_sdk/domains/payments/models/__init__.py +17 -0
  41. geek_cafe_saas_sdk/domains/payments/models/billing_account.py +521 -0
  42. geek_cafe_saas_sdk/domains/payments/models/payment.py +639 -0
  43. geek_cafe_saas_sdk/domains/payments/models/payment_intent_ref.py +539 -0
  44. geek_cafe_saas_sdk/domains/payments/models/refund.py +404 -0
  45. geek_cafe_saas_sdk/domains/payments/services/__init__.py +11 -0
  46. geek_cafe_saas_sdk/domains/payments/services/payment_service.py +405 -0
  47. geek_cafe_saas_sdk/domains/subscriptions/__init__.py +19 -0
  48. geek_cafe_saas_sdk/domains/subscriptions/handlers/README.md +408 -0
  49. geek_cafe_saas_sdk/domains/subscriptions/handlers/__init__.py +1 -0
  50. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/create/app.py +81 -0
  51. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/get/app.py +48 -0
  52. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/list/app.py +54 -0
  53. geek_cafe_saas_sdk/domains/subscriptions/handlers/addons/update/app.py +54 -0
  54. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/create/app.py +83 -0
  55. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/get/app.py +47 -0
  56. geek_cafe_saas_sdk/domains/subscriptions/handlers/discounts/validate/app.py +62 -0
  57. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/create/app.py +82 -0
  58. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/get/app.py +48 -0
  59. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/list/app.py +66 -0
  60. geek_cafe_saas_sdk/domains/subscriptions/handlers/plans/update/app.py +54 -0
  61. geek_cafe_saas_sdk/domains/subscriptions/handlers/usage/aggregate/app.py +72 -0
  62. geek_cafe_saas_sdk/domains/subscriptions/handlers/usage/record/app.py +89 -0
  63. geek_cafe_saas_sdk/domains/subscriptions/models/__init__.py +13 -0
  64. geek_cafe_saas_sdk/domains/subscriptions/models/addon.py +604 -0
  65. geek_cafe_saas_sdk/domains/subscriptions/models/discount.py +492 -0
  66. geek_cafe_saas_sdk/domains/subscriptions/models/plan.py +569 -0
  67. geek_cafe_saas_sdk/domains/subscriptions/models/usage_record.py +300 -0
  68. geek_cafe_saas_sdk/domains/subscriptions/services/__init__.py +10 -0
  69. geek_cafe_saas_sdk/domains/subscriptions/services/subscription_manager_service.py +694 -0
  70. geek_cafe_saas_sdk/domains/tenancy/models/subscription.py +123 -1
  71. geek_cafe_saas_sdk/domains/tenancy/services/subscription_service.py +213 -0
  72. geek_cafe_saas_sdk/lambda_handlers/_base/base_handler.py +7 -0
  73. geek_cafe_saas_sdk/services/database_service.py +10 -6
  74. geek_cafe_saas_sdk/utilities/environment_variables.py +16 -0
  75. geek_cafe_saas_sdk/utilities/logging_utility.py +77 -0
  76. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/METADATA +1 -1
  77. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/RECORD +79 -20
  78. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/WHEEL +0 -0
  79. {geek_cafe_saas_sdk-0.7.0.dist-info → geek_cafe_saas_sdk-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -109,27 +109,8 @@ class FileShareService(DatabaseService[FileShare]):
109
109
  share.access_count = 0
110
110
 
111
111
  # Save to DynamoDB
112
- pk = f"FILE#{tenant_id}#{file_id}"
113
- sk = f"SHARE#{share.share_id}"
114
-
115
- item = share.to_dictionary()
116
- item["pk"] = pk
117
- item["sk"] = sk
118
-
119
- # GSI1: Shares by file
120
- item["gsi1_pk"] = f"FILE#{tenant_id}#{file_id}"
121
- item["gsi1_sk"] = f"USER#{shared_with_user_id}"
122
-
123
- # GSI2: Shares with user
124
- item["gsi2_pk"] = f"TENANT#{tenant_id}#USER#{shared_with_user_id}"
125
- item["gsi2_sk"] = f"FILE#{file_id}#{share.created_utc_ts}"
126
-
127
- self.dynamodb.save(
128
- item=item,
129
- table_name=self.table_name
130
- )
131
-
132
- return ServiceResult.success_result(share)
112
+ share.prep_for_save()
113
+ return self._save_model(share)
133
114
 
134
115
  except (ValidationError, AccessDeniedError) as e:
135
116
  return ServiceResult.error_result(
@@ -163,23 +144,12 @@ class FileShareService(DatabaseService[FileShare]):
163
144
  ServiceResult with FileShare model
164
145
  """
165
146
  try:
166
- if not file_id:
167
- raise ValidationError("file_id is required", "file_id")
168
-
169
- pk = f"FILE#{tenant_id}#{file_id}"
170
- sk = f"SHARE#{resource_id}"
147
+ # Use helper method with tenant check
148
+ share = self._get_model_by_id_with_tenant_check(resource_id, FileShare, tenant_id)
171
149
 
172
- result = self.dynamodb.get(
173
- table_name=self.table_name,
174
- key={"pk": pk, "sk": sk}
175
- )
176
-
177
- if not result or 'Item' not in result:
150
+ if not share:
178
151
  raise NotFoundError(f"Share not found: {resource_id}")
179
152
 
180
- share = FileShare()
181
- share.map(result['Item'])
182
-
183
153
  # Access control: user must be sharer or sharee
184
154
  if share.shared_by != user_id and share.shared_with_user_id != user_id:
185
155
  raise AccessDeniedError("You do not have access to this share")
@@ -256,25 +226,8 @@ class FileShareService(DatabaseService[FileShare]):
256
226
  share.updated_utc_ts = dt.datetime.now(dt.UTC).timestamp()
257
227
 
258
228
  # Save to DynamoDB
259
- pk = f"FILE#{tenant_id}#{file_id}"
260
- sk = f"SHARE#{resource_id}"
261
-
262
- item = share.to_dictionary()
263
- item["pk"] = pk
264
- item["sk"] = sk
265
-
266
- # Preserve GSI keys
267
- item["gsi1_pk"] = f"FILE#{tenant_id}#{file_id}"
268
- item["gsi1_sk"] = f"USER#{share.shared_with_user_id}"
269
- item["gsi2_pk"] = f"TENANT#{tenant_id}#USER#{share.shared_with_user_id}"
270
- item["gsi2_sk"] = f"FILE#{file_id}#{share.created_utc_ts}"
271
-
272
- self.dynamodb.save(
273
- item=item,
274
- table_name=self.table_name
275
- )
276
-
277
- return ServiceResult.success_result(share)
229
+ share.prep_for_save()
230
+ return self._save_model(share)
278
231
 
279
232
  except (ValidationError, AccessDeniedError) as e:
280
233
  return ServiceResult.error_result(
@@ -323,23 +276,11 @@ class FileShareService(DatabaseService[FileShare]):
323
276
  share.status = "revoked"
324
277
  share.revoked_at = dt.datetime.now(dt.UTC).timestamp()
325
278
 
326
- pk = f"FILE#{tenant_id}#{file_id}"
327
- sk = f"SHARE#{resource_id}"
328
-
329
- item = share.to_dictionary()
330
- item["pk"] = pk
331
- item["sk"] = sk
332
-
333
- # Preserve GSI keys
334
- item["gsi1_pk"] = f"FILE#{tenant_id}#{file_id}"
335
- item["gsi1_sk"] = f"USER#{share.shared_with_user_id}"
336
- item["gsi2_pk"] = f"TENANT#{tenant_id}#USER#{share.shared_with_user_id}"
337
- item["gsi2_sk"] = f"FILE#{file_id}#{share.created_utc_ts}"
279
+ share.prep_for_save()
280
+ save_result = self._save_model(share)
338
281
 
339
- self.dynamodb.save(
340
- item=item,
341
- table_name=self.table_name
342
- )
282
+ if not save_result.success:
283
+ return save_result
343
284
 
344
285
  return ServiceResult.success_result(True)
345
286
 
@@ -383,21 +324,19 @@ class FileShareService(DatabaseService[FileShare]):
383
324
  error_code=ErrorCode.ACCESS_DENIED
384
325
  )
385
326
 
386
- # Query GSI1
387
- gsi1_pk = f"FILE#{tenant_id}#{file_id}"
327
+ # Use GSI1 to query shares by file
328
+ temp_share = FileShare()
329
+ temp_share.file_id = file_id
388
330
 
389
- results = self.dynamodb.query(
390
- key=Key('gsi1_pk').eq(gsi1_pk) & Key('gsi1_sk').begins_with("USER#"),
391
- table_name=self.table_name,
392
- index_name="gsi1",
393
- limit=limit
394
- )
331
+ # Query using helper method
332
+ query_result = self._query_by_index(temp_share, "gsi1", limit=limit, ascending=False)
395
333
 
334
+ if not query_result.success:
335
+ return query_result
336
+
337
+ # Filter results
396
338
  shares = []
397
- for item in results.get('Items', []):
398
- share = FileShare()
399
- share.map(item)
400
-
339
+ for share in query_result.data:
401
340
  # Include active and expired shares, exclude revoked
402
341
  if share.status != "revoked":
403
342
  shares.append(share)
@@ -429,21 +368,19 @@ class FileShareService(DatabaseService[FileShare]):
429
368
  ServiceResult with list of FileShare models
430
369
  """
431
370
  try:
432
- # Query GSI2
433
- gsi2_pk = f"TENANT#{tenant_id}#USER#{user_id}"
371
+ # Use GSI2 to query shares by shared_with_user
372
+ temp_share = FileShare()
373
+ temp_share.shared_with_user_id = user_id
434
374
 
435
- results = self.dynamodb.query(
436
- key=Key('gsi2_pk').eq(gsi2_pk) & Key('gsi2_sk').begins_with("FILE#"),
437
- table_name=self.table_name,
438
- index_name="gsi2",
439
- limit=limit
440
- )
375
+ # Query using helper method
376
+ query_result = self._query_by_index(temp_share, "gsi2", limit=limit, ascending=False)
377
+
378
+ if not query_result.success:
379
+ return query_result
441
380
 
381
+ # Filter results
442
382
  shares = []
443
- for item in results.get('Items', []):
444
- share = FileShare()
445
- share.map(item)
446
-
383
+ for share in query_result.data:
447
384
  # Only include active, non-expired shares
448
385
  if share.is_active:
449
386
  shares.append(share)
@@ -543,20 +480,12 @@ class FileShareService(DatabaseService[FileShare]):
543
480
  def _get_file(self, tenant_id: str, file_id: str, user_id: str) -> ServiceResult[File]:
544
481
  """Get file with access control."""
545
482
  try:
546
- pk = f"FILE#{tenant_id}#{file_id}"
547
- sk = "METADATA"
548
-
549
- result = self.dynamodb.get(
550
- table_name=self.table_name,
551
- key={"pk": pk, "sk": sk}
552
- )
483
+ # Use helper method with tenant check
484
+ file = self._get_model_by_id_with_tenant_check(file_id, File, tenant_id)
553
485
 
554
- if not result or 'Item' not in result:
486
+ if not file:
555
487
  raise NotFoundError(f"File not found: {file_id}")
556
488
 
557
- file = File()
558
- file.map(result['Item'])
559
-
560
489
  if file.owner_id != user_id:
561
490
  raise AccessDeniedError("You do not have access to this file")
562
491
 
@@ -572,7 +501,7 @@ class FileShareService(DatabaseService[FileShare]):
572
501
  """Get file without access control (for internal use)."""
573
502
  try:
574
503
  pk = f"FILE#{tenant_id}#{file_id}"
575
- sk = "METADATA"
504
+ sk = "metadata"
576
505
 
577
506
  result = self.dynamodb.get(
578
507
  table_name=self.table_name,
@@ -645,19 +574,7 @@ class FileShareService(DatabaseService[FileShare]):
645
574
  share.access_count += 1
646
575
  share.last_accessed_at = dt.datetime.now(dt.UTC).timestamp()
647
576
 
648
- item = share.to_dictionary()
649
- item["pk"] = pk
650
- item["sk"] = sk
651
-
652
- # Preserve GSI keys
653
- item["gsi1_pk"] = result['Item'].get('gsi1_pk')
654
- item["gsi1_sk"] = result['Item'].get('gsi1_sk')
655
- item["gsi2_pk"] = result['Item'].get('gsi2_pk')
656
- item["gsi2_sk"] = result['Item'].get('gsi2_sk')
657
-
658
- self.dynamodb.save(
659
- item=item,
660
- table_name=self.table_name
661
- )
577
+ share.prep_for_save()
578
+ self._save_model(share)
662
579
  except Exception:
663
580
  pass # Best effort
@@ -174,28 +174,11 @@ class FileSystemService(DatabaseService[File]):
174
174
  )
175
175
 
176
176
  # Save metadata to DynamoDB
177
- pk = f"FILE#{tenant_id}#{file.file_id}"
178
- sk = "METADATA"
179
-
180
- item = file.to_dictionary()
181
- item["pk"] = pk
182
- item["sk"] = sk
183
-
184
- # GSI1: Files by directory
185
- item["gsi1_pk"] = f"TENANT#{tenant_id}"
186
- if directory_id:
187
- item["gsi1_sk"] = f"DIRECTORY#{directory_id}#{file_name}"
188
- else:
189
- item["gsi1_sk"] = f"DIRECTORY#ROOT#{file_name}"
190
-
191
- # GSI2: Files by owner
192
- item["gsi2_pk"] = f"TENANT#{tenant_id}#USER#{user_id}"
193
- item["gsi2_sk"] = f"FILE#{file.created_utc_ts}"
177
+ file.prep_for_save()
178
+ save_result = self._save_model(file)
194
179
 
195
- self.dynamodb.save(
196
- table_name=self.table_name,
197
- item=item
198
- )
180
+ if not save_result.success:
181
+ return save_result
199
182
 
200
183
  return ServiceResult.success_result(file)
201
184
 
@@ -229,23 +212,13 @@ class FileSystemService(DatabaseService[File]):
229
212
  ServiceResult with File model
230
213
  """
231
214
  try:
232
- pk = f"FILE#{tenant_id}#{resource_id}"
233
- sk = "METADATA"
215
+ # Use helper method with tenant check
216
+ file = self._get_model_by_id_with_tenant_check(resource_id, File, tenant_id)
234
217
 
235
- result = self.dynamodb.get(
236
- table_name=self.table_name,
237
- key={"pk": pk, "sk": sk}
238
- )
239
-
240
- # Check if file exists first (before checking ownership)
241
- # DynamoDB.get returns {'Item': {...}} or {'ResponseMetadata': {...}}
242
- if not result or 'Item' not in result:
218
+ # Check if file exists
219
+ if not file:
243
220
  raise NotFoundError(f"File not found: {resource_id}")
244
221
 
245
- # Convert to File model
246
- file = File()
247
- file.map(result['Item'])
248
-
249
222
  # Access control: Check if user is owner or has share access
250
223
  if file.owner_id != user_id:
251
224
  # TODO: Check FileShare for access
@@ -316,27 +289,8 @@ class FileSystemService(DatabaseService[File]):
316
289
  file.updated_utc_ts = dt.datetime.now(dt.UTC).timestamp()
317
290
 
318
291
  # Save to DynamoDB
319
- pk = f"FILE#{tenant_id}#{resource_id}"
320
- sk = "METADATA"
321
-
322
- item = file.to_dictionary()
323
- item["pk"] = pk
324
- item["sk"] = sk
325
-
326
- # Update GSI keys if directory changed
327
- if "directory_id" in updates:
328
- item["gsi1_pk"] = f"TENANT#{tenant_id}"
329
- if updates["directory_id"]:
330
- item["gsi1_sk"] = f"DIRECTORY#{updates['directory_id']}#{file.file_name}"
331
- else:
332
- item["gsi1_sk"] = f"DIRECTORY#ROOT#{file.file_name}"
333
-
334
- self.dynamodb.save(
335
- table_name=self.table_name,
336
- item=item
337
- )
338
-
339
- return ServiceResult.success_result(file)
292
+ file.prep_for_save()
293
+ return self._save_model(file)
340
294
 
341
295
  except AccessDeniedError as e:
342
296
  return ServiceResult.error_result(
@@ -397,7 +351,7 @@ class FileSystemService(DatabaseService[File]):
397
351
 
398
352
  # Delete from DynamoDB
399
353
  pk = f"FILE#{tenant_id}#{resource_id}"
400
- sk = "METADATA"
354
+ sk = "metadata"
401
355
 
402
356
  self.dynamodb.delete(
403
357
  primary_key={"pk": pk, "sk": sk},
@@ -409,17 +363,11 @@ class FileSystemService(DatabaseService[File]):
409
363
  file.status = "deleted"
410
364
  file.deleted_utc_ts = dt.datetime.now(dt.UTC).timestamp()
411
365
 
412
- pk = f"FILE#{tenant_id}#{resource_id}"
413
- sk = "METADATA"
414
-
415
- item = file.to_dictionary()
416
- item["pk"] = pk
417
- item["sk"] = sk
366
+ file.prep_for_save()
367
+ save_result = self._save_model(file)
418
368
 
419
- self.dynamodb.save(
420
- table_name=self.table_name,
421
- item=item
422
- )
369
+ if not save_result.success:
370
+ return save_result
423
371
 
424
372
  return ServiceResult.success_result(True)
425
373
 
@@ -507,32 +455,23 @@ class FileSystemService(DatabaseService[File]):
507
455
  ServiceResult with list of File models
508
456
  """
509
457
  try:
510
- gsi1_pk = f"TENANT#{tenant_id}"
458
+ # Use GSI1 to query files by directory
459
+ temp_file = File()
460
+ temp_file.tenant_id = tenant_id
461
+ temp_file.directory_id = directory_id # None for root files
511
462
 
512
- if directory_id:
513
- gsi1_sk_prefix = f"DIRECTORY#{directory_id}#"
514
- else:
515
- gsi1_sk_prefix = "DIRECTORY#ROOT#"
516
-
517
- # Query GSI1
518
- results = self.dynamodb.query(
519
- key=Key('gsi1_pk').eq(gsi1_pk) & Key('gsi1_sk').begins_with(gsi1_sk_prefix),
520
- table_name=self.table_name,
521
- index_name="gsi1",
522
- limit=limit
523
- )
463
+ # Query using helper method
464
+ query_result = self._query_by_index(temp_file, "gsi1", limit=limit, ascending=True)
465
+
466
+ if not query_result.success:
467
+ return query_result
524
468
 
469
+ # Filter results
525
470
  files = []
526
- for item in results.get('Items', []):
527
- file = File()
528
- file.map(item)
529
-
530
- # Filter out deleted files
531
- if file.status != "deleted":
532
- # Basic access control: show only owned files or shared files
533
- # TODO: Check FileShare for shared access
534
- if file.owner_id == user_id:
535
- files.append(file)
471
+ for file in query_result.data:
472
+ # Filter out deleted files and apply access control
473
+ if file.status != "deleted" and file.owner_id == user_id:
474
+ files.append(file)
536
475
 
537
476
  return ServiceResult.success_result(files)
538
477
 
@@ -567,21 +506,20 @@ class FileSystemService(DatabaseService[File]):
567
506
  if owner_id != user_id:
568
507
  raise AccessDeniedError("You can only list your own files")
569
508
 
570
- gsi2_pk = f"TENANT#{tenant_id}#USER#{owner_id}"
509
+ # Use GSI2 to query files by owner
510
+ temp_file = File()
511
+ temp_file.tenant_id = tenant_id
512
+ temp_file.owner_id = owner_id
571
513
 
572
- # Query GSI2
573
- results = self.dynamodb.query(
574
- key=Key('gsi2_pk').eq(gsi2_pk) & Key('gsi2_sk').begins_with("FILE#"),
575
- table_name=self.table_name,
576
- index_name="gsi2",
577
- limit=limit
578
- )
514
+ # Query using helper method
515
+ query_result = self._query_by_index(temp_file, "gsi2", limit=limit, ascending=False)
516
+
517
+ if not query_result.success:
518
+ return query_result
579
519
 
520
+ # Filter results
580
521
  files = []
581
- for item in results.get('Items', []):
582
- file = File()
583
- file.map(item)
584
-
522
+ for file in query_result.data:
585
523
  # Filter out deleted files
586
524
  if file.status != "deleted":
587
525
  files.append(file)