@aws-amplify/datastore 3.12.13-unstable.7 → 3.13.0

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 (79) hide show
  1. package/CHANGELOG.md +136 -19
  2. package/dist/aws-amplify-datastore.js +4025 -13130
  3. package/dist/aws-amplify-datastore.js.map +1 -1
  4. package/dist/aws-amplify-datastore.min.js +9 -9
  5. package/dist/aws-amplify-datastore.min.js.map +1 -1
  6. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -11
  7. package/lib/authModeStrategies/multiAuthStrategy.js +0 -11
  8. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  9. package/lib/datastore/datastore.d.ts +2 -79
  10. package/lib/datastore/datastore.js +324 -460
  11. package/lib/datastore/datastore.js.map +1 -1
  12. package/lib/storage/storage.js +2 -2
  13. package/lib/storage/storage.js.map +1 -1
  14. package/lib/sync/datastoreConnectivity.d.ts +0 -1
  15. package/lib/sync/datastoreConnectivity.js +0 -45
  16. package/lib/sync/datastoreConnectivity.js.map +1 -1
  17. package/lib/sync/index.d.ts +0 -6
  18. package/lib/sync/index.js +204 -346
  19. package/lib/sync/index.js.map +1 -1
  20. package/lib/sync/merger.d.ts +0 -6
  21. package/lib/sync/merger.js +0 -6
  22. package/lib/sync/merger.js.map +1 -1
  23. package/lib/sync/outbox.js +62 -66
  24. package/lib/sync/outbox.js.map +1 -1
  25. package/lib/sync/processors/mutation.d.ts +0 -2
  26. package/lib/sync/processors/mutation.js +158 -196
  27. package/lib/sync/processors/mutation.js.map +1 -1
  28. package/lib/sync/processors/subscription.d.ts +0 -2
  29. package/lib/sync/processors/subscription.js +171 -212
  30. package/lib/sync/processors/subscription.js.map +1 -1
  31. package/lib/sync/processors/sync.d.ts +0 -2
  32. package/lib/sync/processors/sync.js +20 -59
  33. package/lib/sync/processors/sync.js.map +1 -1
  34. package/lib/sync/utils.js +3 -1
  35. package/lib/sync/utils.js.map +1 -1
  36. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +0 -11
  37. package/lib-esm/authModeStrategies/multiAuthStrategy.js +0 -11
  38. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  39. package/lib-esm/datastore/datastore.d.ts +2 -79
  40. package/lib-esm/datastore/datastore.js +324 -460
  41. package/lib-esm/datastore/datastore.js.map +1 -1
  42. package/lib-esm/storage/storage.js +2 -2
  43. package/lib-esm/storage/storage.js.map +1 -1
  44. package/lib-esm/sync/datastoreConnectivity.d.ts +0 -1
  45. package/lib-esm/sync/datastoreConnectivity.js +0 -45
  46. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  47. package/lib-esm/sync/index.d.ts +0 -6
  48. package/lib-esm/sync/index.js +205 -347
  49. package/lib-esm/sync/index.js.map +1 -1
  50. package/lib-esm/sync/merger.d.ts +0 -6
  51. package/lib-esm/sync/merger.js +0 -6
  52. package/lib-esm/sync/merger.js.map +1 -1
  53. package/lib-esm/sync/outbox.js +62 -66
  54. package/lib-esm/sync/outbox.js.map +1 -1
  55. package/lib-esm/sync/processors/mutation.d.ts +0 -2
  56. package/lib-esm/sync/processors/mutation.js +159 -197
  57. package/lib-esm/sync/processors/mutation.js.map +1 -1
  58. package/lib-esm/sync/processors/subscription.d.ts +0 -2
  59. package/lib-esm/sync/processors/subscription.js +172 -213
  60. package/lib-esm/sync/processors/subscription.js.map +1 -1
  61. package/lib-esm/sync/processors/sync.d.ts +0 -2
  62. package/lib-esm/sync/processors/sync.js +21 -60
  63. package/lib-esm/sync/processors/sync.js.map +1 -1
  64. package/lib-esm/sync/utils.js +3 -1
  65. package/lib-esm/sync/utils.js.map +1 -1
  66. package/package.json +7 -7
  67. package/src/authModeStrategies/multiAuthStrategy.ts +0 -11
  68. package/src/datastore/datastore.ts +363 -504
  69. package/src/storage/storage.ts +2 -2
  70. package/src/sync/datastoreConnectivity.ts +0 -6
  71. package/src/sync/index.ts +340 -445
  72. package/src/sync/merger.ts +0 -6
  73. package/src/sync/outbox.ts +1 -1
  74. package/src/sync/processors/mutation.ts +104 -145
  75. package/src/sync/processors/subscription.ts +245 -279
  76. package/src/sync/processors/sync.ts +58 -97
  77. package/src/sync/utils.ts +3 -1
  78. package/src/util.ts +2 -2
  79. package/not-tsconfig.json +0 -32
@@ -1,12 +1,7 @@
1
1
  import API, { GraphQLResult, GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
2
2
  import { Auth } from '@aws-amplify/auth';
3
3
  import Cache from '@aws-amplify/cache';
4
- import {
5
- ConsoleLogger as Logger,
6
- Hub,
7
- HubCapsule,
8
- BackgroundProcessManager,
9
- } from '@aws-amplify/core';
4
+ import { ConsoleLogger as Logger, Hub, HubCapsule } from '@aws-amplify/core';
10
5
  import { CONTROL_MSG as PUBSUB_CONTROL_MSG } from '@aws-amplify/pubsub';
11
6
  import Observable, { ZenObservable } from 'zen-observable-ts';
12
7
  import {
@@ -61,8 +56,6 @@ class SubscriptionProcessor {
61
56
  [];
62
57
  private dataObserver: ZenObservable.Observer<any>;
63
58
 
64
- private runningProcesses: BackgroundProcessManager;
65
-
66
59
  constructor(
67
60
  private readonly schema: InternalSchema,
68
61
  private readonly syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>>,
@@ -244,19 +237,6 @@ class SubscriptionProcessor {
244
237
  Observable<CONTROL_MSG>,
245
238
  Observable<[TransformerMutationType, SchemaModel, PersistentModel]>
246
239
  ] {
247
- if (this.runningProcesses) {
248
- throw new Error(
249
- [
250
- 'Subscription processor is already started!',
251
- 'It must be stopped before it can be restarted.',
252
- 'Please report this error in a GitHub issue.',
253
- 'https://github.com/aws-amplify/amplify-js/issues',
254
- ].join('\n')
255
- );
256
- }
257
-
258
- this.runningProcesses = new BackgroundProcessManager();
259
-
260
240
  const ctlObservable = new Observable<CONTROL_MSG>(observer => {
261
241
  const promises: Promise<void>[] = [];
262
242
 
@@ -272,7 +252,7 @@ class SubscriptionProcessor {
272
252
  let cognitoTokenPayload: { [field: string]: any },
273
253
  oidcTokenPayload: { [field: string]: any };
274
254
  let userCredentials = USER_CREDENTIALS.none;
275
- this.runningProcesses.add(async () => {
255
+ (async () => {
276
256
  try {
277
257
  // retrieving current AWS Credentials
278
258
  const credentials =
@@ -330,270 +310,260 @@ class SubscriptionProcessor {
330
310
  Object.values(this.schema.namespaces).forEach(namespace => {
331
311
  Object.values(namespace.models)
332
312
  .filter(({ syncable }) => syncable)
333
- .forEach(modelDefinition =>
334
- this.runningProcesses.add(async () => {
335
- const modelAuthModes = await getModelAuthModes({
336
- authModeStrategy: this.authModeStrategy,
337
- defaultAuthMode:
338
- this.amplifyConfig.aws_appsync_authenticationType,
339
- modelName: modelDefinition.name,
340
- schema: this.schema,
341
- });
342
-
343
- // subscriptions are created only based on the READ auth mode(s)
344
- const readAuthModes = modelAuthModes.READ;
345
-
346
- subscriptions = {
347
- ...subscriptions,
348
- [modelDefinition.name]: {
349
- [TransformerMutationType.CREATE]: [],
350
- [TransformerMutationType.UPDATE]: [],
351
- [TransformerMutationType.DELETE]: [],
352
- },
353
- };
354
-
355
- const operations = [
356
- TransformerMutationType.CREATE,
357
- TransformerMutationType.UPDATE,
358
- TransformerMutationType.DELETE,
359
- ];
360
-
361
- const operationAuthModeAttempts = {
362
- [TransformerMutationType.CREATE]: 0,
363
- [TransformerMutationType.UPDATE]: 0,
364
- [TransformerMutationType.DELETE]: 0,
365
- };
366
-
367
- // Retry failed subscriptions with next auth mode (if available)
368
- const authModeRetry = async operation => {
369
- const {
370
- opType: transformerMutationType,
371
- opName,
372
- query,
373
- isOwner,
374
- ownerField,
375
- ownerValue,
376
- authMode,
377
- } = this.buildSubscription(
378
- namespace,
379
- modelDefinition,
380
- operation,
381
- userCredentials,
382
- cognitoTokenPayload,
383
- oidcTokenPayload,
384
- readAuthModes[operationAuthModeAttempts[operation]]
385
- );
386
-
387
- const authToken = await getTokenForCustomAuth(
388
- authMode,
389
- this.amplifyConfig
390
- );
391
-
392
- const variables = {};
393
-
394
- if (isOwner) {
395
- if (!ownerValue) {
396
- observer.error(
397
- 'Owner field required, sign in is needed in order to perform this operation'
398
- );
399
- return;
400
- }
401
-
402
- variables[ownerField] = ownerValue;
313
+ .forEach(async modelDefinition => {
314
+ const modelAuthModes = await getModelAuthModes({
315
+ authModeStrategy: this.authModeStrategy,
316
+ defaultAuthMode:
317
+ this.amplifyConfig.aws_appsync_authenticationType,
318
+ modelName: modelDefinition.name,
319
+ schema: this.schema,
320
+ });
321
+
322
+ // subscriptions are created only based on the READ auth mode(s)
323
+ const readAuthModes = modelAuthModes.READ;
324
+
325
+ subscriptions = {
326
+ ...subscriptions,
327
+ [modelDefinition.name]: {
328
+ [TransformerMutationType.CREATE]: [],
329
+ [TransformerMutationType.UPDATE]: [],
330
+ [TransformerMutationType.DELETE]: [],
331
+ },
332
+ };
333
+
334
+ const operations = [
335
+ TransformerMutationType.CREATE,
336
+ TransformerMutationType.UPDATE,
337
+ TransformerMutationType.DELETE,
338
+ ];
339
+
340
+ const operationAuthModeAttempts = {
341
+ [TransformerMutationType.CREATE]: 0,
342
+ [TransformerMutationType.UPDATE]: 0,
343
+ [TransformerMutationType.DELETE]: 0,
344
+ };
345
+
346
+ // Retry failed subscriptions with next auth mode (if available)
347
+ const authModeRetry = async operation => {
348
+ const {
349
+ opType: transformerMutationType,
350
+ opName,
351
+ query,
352
+ isOwner,
353
+ ownerField,
354
+ ownerValue,
355
+ authMode,
356
+ } = this.buildSubscription(
357
+ namespace,
358
+ modelDefinition,
359
+ operation,
360
+ userCredentials,
361
+ cognitoTokenPayload,
362
+ oidcTokenPayload,
363
+ readAuthModes[operationAuthModeAttempts[operation]]
364
+ );
365
+
366
+ const authToken = await getTokenForCustomAuth(
367
+ authMode,
368
+ this.amplifyConfig
369
+ );
370
+
371
+ const variables = {};
372
+
373
+ if (isOwner) {
374
+ if (!ownerValue) {
375
+ observer.error(
376
+ 'Owner field required, sign in is needed in order to perform this operation'
377
+ );
378
+ return;
403
379
  }
404
380
 
405
- logger.debug(
406
- `Attempting ${operation} subscription with authMode: ${
407
- readAuthModes[operationAuthModeAttempts[operation]]
408
- }`
409
- );
410
-
411
- const userAgentSuffix = USER_AGENT_SUFFIX_DATASTORE;
412
-
413
- const queryObservable = <
414
- Observable<{
415
- value: GraphQLResult<Record<string, PersistentModel>>;
416
- }>
417
- >(<unknown>this.amplifyContext.API.graphql({ query, variables, ...{ authMode }, authToken, userAgentSuffix }));
418
-
419
- let subscriptionReadyCallback: () => void;
420
-
421
- // TODO: consider onTerminate.then(() => API.cancel(...))
422
-
423
- subscriptions[modelDefinition.name][
424
- transformerMutationType
425
- ].push(
426
- queryObservable
427
- .map(({ value }) => {
428
- return value;
429
- })
430
- .subscribe({
431
- next: ({ data, errors }) => {
432
- if (Array.isArray(errors) && errors.length > 0) {
433
- const messages = (<
434
- {
435
- message: string;
436
- }[]
437
- >errors).map(({ message }) => message);
438
-
439
- logger.warn(
440
- `Skipping incoming subscription. Messages: ${messages.join(
441
- '\n'
442
- )}`
443
- );
444
-
445
- this.drainBuffer();
446
- return;
447
- }
448
-
449
- const predicatesGroup =
450
- ModelPredicateCreator.getPredicates(
451
- this.syncPredicates.get(modelDefinition),
452
- false
453
- );
381
+ variables[ownerField] = ownerValue;
382
+ }
454
383
 
455
- const { [opName]: record } = data;
384
+ logger.debug(
385
+ `Attempting ${operation} subscription with authMode: ${
386
+ readAuthModes[operationAuthModeAttempts[operation]]
387
+ }`
388
+ );
389
+
390
+ const userAgentSuffix = USER_AGENT_SUFFIX_DATASTORE;
391
+
392
+ const queryObservable = <
393
+ Observable<{
394
+ value: GraphQLResult<Record<string, PersistentModel>>;
395
+ }>
396
+ >(<unknown>this.amplifyContext.API.graphql({ query, variables, ...{ authMode }, authToken, userAgentSuffix }));
397
+
398
+ let subscriptionReadyCallback: () => void;
399
+
400
+ subscriptions[modelDefinition.name][
401
+ transformerMutationType
402
+ ].push(
403
+ queryObservable
404
+ .map(({ value }) => {
405
+ return value;
406
+ })
407
+ .subscribe({
408
+ next: ({ data, errors }) => {
409
+ if (Array.isArray(errors) && errors.length > 0) {
410
+ const messages = (<
411
+ {
412
+ message: string;
413
+ }[]
414
+ >errors).map(({ message }) => message);
415
+
416
+ logger.warn(
417
+ `Skipping incoming subscription. Messages: ${messages.join(
418
+ '\n'
419
+ )}`
420
+ );
456
421
 
457
- // checking incoming subscription against syncPredicate.
458
- // once AppSync implements filters on subscriptions, we'll be
459
- // able to set these when establishing the subscription instead.
460
- // Until then, we'll need to filter inbound
461
- if (
462
- this.passesPredicateValidation(
463
- record,
464
- predicatesGroup
465
- )
466
- ) {
467
- this.pushToBuffer(
468
- transformerMutationType,
469
- modelDefinition,
470
- record
471
- );
472
- }
473
422
  this.drainBuffer();
474
- },
475
- error: async subscriptionError => {
476
- const {
477
- error: { errors: [{ message = '' } = {}] } = {
478
- errors: [],
479
- },
480
- } = subscriptionError;
481
-
423
+ return;
424
+ }
425
+
426
+ const predicatesGroup =
427
+ ModelPredicateCreator.getPredicates(
428
+ this.syncPredicates.get(modelDefinition),
429
+ false
430
+ );
431
+
432
+ const { [opName]: record } = data;
433
+
434
+ // checking incoming subscription against syncPredicate.
435
+ // once AppSync implements filters on subscriptions, we'll be
436
+ // able to set these when establishing the subscription instead.
437
+ // Until then, we'll need to filter inbound
438
+ if (
439
+ this.passesPredicateValidation(
440
+ record,
441
+ predicatesGroup
442
+ )
443
+ ) {
444
+ this.pushToBuffer(
445
+ transformerMutationType,
446
+ modelDefinition,
447
+ record
448
+ );
449
+ }
450
+ this.drainBuffer();
451
+ },
452
+ error: async subscriptionError => {
453
+ const {
454
+ error: { errors: [{ message = '' } = {}] } = {
455
+ errors: [],
456
+ },
457
+ } = subscriptionError;
458
+
459
+ if (
460
+ message.includes(
461
+ PUBSUB_CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR
462
+ ) ||
463
+ message.includes(PUBSUB_CONTROL_MSG.CONNECTION_FAILED)
464
+ ) {
465
+ // Unsubscribe and clear subscription array for model/operation
466
+ subscriptions[modelDefinition.name][
467
+ transformerMutationType
468
+ ].forEach(subscription => subscription.unsubscribe());
469
+ subscriptions[modelDefinition.name][
470
+ transformerMutationType
471
+ ] = [];
472
+
473
+ operationAuthModeAttempts[operation]++;
482
474
  if (
483
- message.includes(
484
- PUBSUB_CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR
485
- ) ||
486
- message.includes(
487
- PUBSUB_CONTROL_MSG.CONNECTION_FAILED
488
- )
475
+ operationAuthModeAttempts[operation] >=
476
+ readAuthModes.length
489
477
  ) {
490
- // Unsubscribe and clear subscription array for model/operation
491
- subscriptions[modelDefinition.name][
492
- transformerMutationType
493
- ].forEach(subscription =>
494
- subscription.unsubscribe()
478
+ // last auth mode retry. Continue with error
479
+ logger.debug(
480
+ `${operation} subscription failed with authMode: ${
481
+ readAuthModes[
482
+ operationAuthModeAttempts[operation] - 1
483
+ ]
484
+ }`
495
485
  );
496
- subscriptions[modelDefinition.name][
497
- transformerMutationType
498
- ] = [];
499
-
500
- operationAuthModeAttempts[operation]++;
501
- if (
502
- operationAuthModeAttempts[operation] >=
503
- readAuthModes.length
504
- ) {
505
- // last auth mode retry. Continue with error
506
- logger.debug(
507
- `${operation} subscription failed with authMode: ${
508
- readAuthModes[
509
- operationAuthModeAttempts[operation] - 1
510
- ]
511
- }`
512
- );
513
- } else {
514
- // retry with different auth mode. Do not trigger
515
- // observer error or error handler
516
- logger.debug(
517
- `${operation} subscription failed with authMode: ${
518
- readAuthModes[
519
- operationAuthModeAttempts[operation] - 1
520
- ]
521
- }. Retrying with authMode: ${
522
- readAuthModes[
523
- operationAuthModeAttempts[operation]
524
- ]
525
- }`
526
- );
527
- authModeRetry(operation);
528
- return;
529
- }
530
- }
531
- logger.warn('subscriptionError', message);
532
-
533
- try {
534
- await this.errorHandler({
535
- recoverySuggestion:
536
- 'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
537
- localModel: null,
538
- message,
539
- model: modelDefinition.name,
540
- operation,
541
- errorType:
542
- getSubscriptionErrorType(subscriptionError),
543
- process: ProcessName.subscribe,
544
- remoteModel: null,
545
- cause: subscriptionError,
546
- });
547
- } catch (e) {
548
- logger.error(
549
- 'Subscription error handler failed with:',
550
- e
486
+ } else {
487
+ // retry with different auth mode. Do not trigger
488
+ // observer error or error handler
489
+ logger.debug(
490
+ `${operation} subscription failed with authMode: ${
491
+ readAuthModes[
492
+ operationAuthModeAttempts[operation] - 1
493
+ ]
494
+ }. Retrying with authMode: ${
495
+ readAuthModes[
496
+ operationAuthModeAttempts[operation]
497
+ ]
498
+ }`
551
499
  );
552
- }
553
-
554
- if (typeof subscriptionReadyCallback === 'function') {
555
- subscriptionReadyCallback();
556
- }
557
-
558
- if (
559
- message.includes('"errorType":"Unauthorized"') ||
560
- message.includes('"errorType":"OperationDisabled"')
561
- ) {
500
+ authModeRetry(operation);
562
501
  return;
563
502
  }
564
- observer.error(message);
565
- },
566
- })
567
- );
568
-
569
- promises.push(
570
- (async () => {
571
- let boundFunction: any;
572
-
573
- await new Promise(res => {
574
- subscriptionReadyCallback = res;
575
- boundFunction = this.hubQueryCompletionListener.bind(
576
- this,
577
- res
578
- );
579
- Hub.listen('api', boundFunction);
580
- });
581
- Hub.remove('api', boundFunction);
582
- })()
583
- );
584
- };
585
-
586
- operations.forEach(op => authModeRetry(op));
587
- })
588
- );
503
+ }
504
+ logger.warn('subscriptionError', message);
505
+
506
+ try {
507
+ await this.errorHandler({
508
+ recoverySuggestion:
509
+ 'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
510
+ localModel: null,
511
+ message,
512
+ model: modelDefinition.name,
513
+ operation,
514
+ errorType:
515
+ getSubscriptionErrorType(subscriptionError),
516
+ process: ProcessName.subscribe,
517
+ remoteModel: null,
518
+ cause: subscriptionError,
519
+ });
520
+ } catch (e) {
521
+ logger.error(
522
+ 'Subscription error handler failed with:',
523
+ e
524
+ );
525
+ }
526
+
527
+ if (typeof subscriptionReadyCallback === 'function') {
528
+ subscriptionReadyCallback();
529
+ }
530
+
531
+ if (
532
+ message.includes('"errorType":"Unauthorized"') ||
533
+ message.includes('"errorType":"OperationDisabled"')
534
+ ) {
535
+ return;
536
+ }
537
+ observer.error(message);
538
+ },
539
+ })
540
+ );
541
+
542
+ promises.push(
543
+ (async () => {
544
+ let boundFunction: any;
545
+
546
+ await new Promise(res => {
547
+ subscriptionReadyCallback = res;
548
+ boundFunction = this.hubQueryCompletionListener.bind(
549
+ this,
550
+ res
551
+ );
552
+ Hub.listen('api', boundFunction);
553
+ });
554
+ Hub.remove('api', boundFunction);
555
+ })()
556
+ );
557
+ };
558
+
559
+ operations.forEach(op => authModeRetry(op));
560
+ });
589
561
  });
590
562
 
591
- this.runningProcesses.add(() =>
592
- Promise.all(promises).then(() => observer.next(CONTROL_MSG.CONNECTED))
593
- );
594
- }, 'subscription processor new subscriber');
563
+ Promise.all(promises).then(() => observer.next(CONTROL_MSG.CONNECTED));
564
+ })();
595
565
 
596
- return this.runningProcesses.addCleaner(async () => {
566
+ return () => {
597
567
  Object.keys(subscriptions).forEach(modelName => {
598
568
  subscriptions[modelName][TransformerMutationType.CREATE].forEach(
599
569
  subscription => subscription.unsubscribe()
@@ -605,7 +575,7 @@ class SubscriptionProcessor {
605
575
  subscription => subscription.unsubscribe()
606
576
  );
607
577
  });
608
- });
578
+ };
609
579
  });
610
580
 
611
581
  const dataObservable = new Observable<
@@ -614,18 +584,14 @@ class SubscriptionProcessor {
614
584
  this.dataObserver = observer;
615
585
  this.drainBuffer();
616
586
 
617
- return this.runningProcesses.addCleaner(async () => {
587
+ return () => {
618
588
  this.dataObserver = null;
619
- });
589
+ };
620
590
  });
621
591
 
622
592
  return [ctlObservable, dataObservable];
623
593
  }
624
594
 
625
- public async stop() {
626
- this.runningProcesses && (await this.runningProcesses.close());
627
- }
628
-
629
595
  private passesPredicateValidation(
630
596
  record: PersistentModel,
631
597
  predicatesGroup: PredicatesGroup<any>