diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e866b86a7..f7e55afd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,250 +67,87 @@ jobs: # Dart jobs - deploy-cluster-dart-windows: - name: Deploy Cluster for Dart Windows - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: dw${{ github.run_id }}${{ github.run_attempt }} - dart-tests-windows: name: Dart Tests Windows uses: ./.github/workflows/dart-desktop-tests.yml needs: - build-windows - - deploy-cluster-dart-windows secrets: inherit with: runner: windows-latest - differentiator: dw${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-dart-windows: - name: Cleanup Cluster for Dart Windows - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - dart-tests-windows - secrets: inherit - with: - differentiator: dw${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-dart-macos: - name: Deploy Cluster for Dart MacOS - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: dm${{ github.run_id }}${{ github.run_attempt }} dart-tests-macos: name: Dart Tests MacOS uses: ./.github/workflows/dart-desktop-tests.yml needs: - build-macos - - deploy-cluster-dart-macos secrets: inherit with: runner: macos-13 - differentiator: dm${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-dart-macos: - name: Cleanup Cluster for Dart macOS - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - dart-tests-macos - secrets: inherit - with: - differentiator: dm${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-dart-macos-arm: - name: Deploy Cluster for Dart MacOS Arm - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: dma${{ github.run_id }}${{ github.run_attempt }} dart-tests-macos-arm: name: Dart Tests MacOS Arm uses: ./.github/workflows/dart-desktop-tests.yml needs: - build-macos - - deploy-cluster-dart-macos-arm secrets: inherit with: runner: macos-14 arch: arm64 - differentiator: dma${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-dart-macos-arm: - name: Cleanup Cluster for Dart macOS Arm - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - dart-tests-macos-arm - secrets: inherit - with: - differentiator: dma${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-dart-linux: - name: Deploy Cluster for Dart Linux - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: dl${{ github.run_id }}${{ github.run_attempt }} dart-tests-linux: name: Dart Tests Linux uses: ./.github/workflows/dart-desktop-tests.yml needs: - build-linux - - deploy-cluster-dart-linux secrets: inherit with: runner: ubuntu-latest - differentiator: dl${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-dart-linux: - name: Cleanup Cluster for Dart Linux - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - dart-tests-linux - secrets: inherit - with: - differentiator: dl${{ github.run_id }}${{ github.run_attempt }} # Flutter jobs - deploy-cluster-flutter-windows: - name: Deploy Cluster for Flutter Windows - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fw${{ github.run_id }}${{ github.run_attempt }} - flutter-tests-windows: name: Flutter Tests Windows uses: ./.github/workflows/flutter-desktop-tests.yml needs: - build-windows - - deploy-cluster-flutter-windows secrets: inherit with: runner: windows-latest - differentiator: fw${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-flutter-windows: - name: Cleanup Cluster for Flutter Windows - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-windows - secrets: inherit - with: - differentiator: fw${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-flutter-macos: - name: Deploy Cluster for Flutter MacOS - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fm${{ github.run_id }}${{ github.run_attempt }} flutter-tests-macos: name: Flutter Tests MacOS uses: ./.github/workflows/flutter-desktop-tests.yml needs: - build-macos - - deploy-cluster-flutter-macos secrets: inherit with: runner: macos-13 - differentiator: fm${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-flutter-macos: - name: Cleanup Cluster for Flutter macOS - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-macos - secrets: inherit - with: - differentiator: fm${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-flutter-macos-arm: - name: Deploy Cluster for Flutter MacOS Arm - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fma${{ github.run_id }}${{ github.run_attempt }} flutter-tests-macos-arm: name: Flutter Tests MacOS Arm uses: ./.github/workflows/flutter-desktop-tests.yml needs: - build-macos - - deploy-cluster-flutter-macos-arm secrets: inherit with: runner: macos-14 arch: arm64 - differentiator: fma${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-flutter-macos-arm: - name: Cleanup Cluster for Flutter macOS Arm - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-macos-arm - secrets: inherit - with: - differentiator: fma${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-flutter-linux: - name: Deploy Cluster for Flutter Linux - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fl${{ github.run_id }}${{ github.run_attempt }} flutter-tests-linux: name: Flutter Tests Linux uses: ./.github/workflows/flutter-desktop-tests.yml needs: - build-linux - - deploy-cluster-flutter-linux secrets: inherit with: runner: ubuntu-latest - differentiator: fl${{ github.run_id }}${{ github.run_attempt }} - - cleanup-cluster-flutter-linux: - name: Cleanup Cluster for Flutter Linux - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-linux - secrets: inherit - with: - differentiator: fl${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-flutter-ios: - name: Deploy Cluster for Flutter iOS - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fi${{ github.run_id }}${{ github.run_attempt }} flutter-tests-ios: runs-on: macos-14 name: Flutter Tests iOS timeout-minutes: 45 needs: - - deploy-cluster-flutter-ios - build-ios-xcframework - env: - BAAS_DIFFERENTIATOR: fi${{ github.run_id }}${{ github.run_attempt }} - BAAS_BAASAAS_API_KEY: ${{ secrets.BAASAAS_API_KEY}} defaults: run: working-directory: packages/realm/tests @@ -348,8 +185,6 @@ jobs: - name: Run tests on iOS Simulator run: | flutter test integration_test/all_tests.dart \ - --dart-define=BAAS_BAASAAS_API_KEY=$BAAS_BAASAAS_API_KEY \ - --dart-define=BAAS_DIFFERENTIATOR=$BAAS_DIFFERENTIATOR \ --file-reporter=json:test-results.json \ --suppress-analytics @@ -363,33 +198,12 @@ jobs: only-summary: true working-directory: packages/realm/tests - cleanup-cluster-flutter-ios: - name: Cleanup Cluster for Flutter iOS - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-ios - secrets: inherit - with: - differentiator: fi${{ github.run_id }}${{ github.run_attempt }} - - deploy-cluster-flutter-android: - name: Deploy Cluster for Flutter Android - uses: ./.github/workflows/deploy-baas.yml - secrets: inherit - with: - differentiator: fa${{ github.run_id }}${{ github.run_attempt }} - flutter-tests-android: runs-on: ubuntu-latest name: Flutter Tests Android timeout-minutes: 45 needs: - - deploy-cluster-flutter-android - build-android-combined - env: - BAAS_DIFFERENTIATOR: fa${{ github.run_id }}${{ github.run_attempt }} - BAAS_BAASAAS_API_KEY: ${{ secrets.BAASAAS_API_KEY}} defaults: run: working-directory: packages/realm/tests @@ -462,7 +276,7 @@ jobs: arch: x86_64 ndk: 25.2.9519653 cmake: 3.10.2.4988404 - script: cd packages/realm/tests && flutter test integration_test/all_tests.dart --dart-define=BAAS_BAASAAS_API_KEY=$BAAS_BAASAAS_API_KEY --dart-define=BAAS_DIFFERENTIATOR=$BAAS_DIFFERENTIATOR --file-reporter=json:test-results.json --suppress-analytics + script: cd packages/realm/tests && flutter test integration_test/all_tests.dart --file-reporter=json:test-results.json --suppress-analytics - name: Publish Test Report uses: dorny/test-reporter@v1.8.0 @@ -474,16 +288,6 @@ jobs: only-summary: true working-directory: packages/realm/tests - cleanup-cluster-flutter-android: - name: Cleanup Cluster for Flutter Android - uses: ./.github/workflows/terminate-baas.yml - if: always() - needs: - - flutter-tests-android - secrets: inherit - with: - differentiator: fa${{ github.run_id }}${{ github.run_attempt }} - # Generator jobs generator: @@ -592,7 +396,7 @@ jobs: ** <{{refUrl}}|`{{ref}}` - {{description}}> {{#if description}}<{{diffUrl}}|branch: `{{diffRef}}`>{{/if}} - + web-compile: name: Compile for web runs-on: ubuntu-latest diff --git a/.github/workflows/dart-desktop-tests.yml b/.github/workflows/dart-desktop-tests.yml index af3238cfb..eefefff28 100644 --- a/.github/workflows/dart-desktop-tests.yml +++ b/.github/workflows/dart-desktop-tests.yml @@ -7,10 +7,6 @@ on: description: GitHub runner image to execute on. required: true type: string - differentiator: - description: Differentiator for the BaaS container. - required: true - type: string arch: description: Architecture to execute on. default: x64 @@ -18,8 +14,6 @@ on: env: REALM_CI: true - BAAS_BAASAAS_API_KEY: ${{ secrets.BAASAAS_API_KEY}} - BAAS_DIFFERENTIATOR: ${{ inputs.differentiator }} jobs: dart-tests: diff --git a/.github/workflows/deploy-baas.yml b/.github/workflows/deploy-baas.yml deleted file mode 100644 index 15a5a897a..000000000 --- a/.github/workflows/deploy-baas.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Deploy BaaS and apps - -on: - workflow_call: - inputs: - differentiator: - description: Differentiator for the BaaS container. - required: true - type: string - -env: - REALM_CI: true - -jobs: - deploy-baas: - runs-on: ubuntu-latest - defaults: - run: - working-directory: packages/realm_dart - name: Deploy BaaS - timeout-minutes: 15 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: false - - - name: Setup Runner - uses: ./.github/actions/setup-runner - - - name: Deploy cluster and apps - run: dart run realm_dart deploy-apps --baasaas-api-key ${{ secrets.BAASAAS_API_KEY }} --differentiator ${{ inputs.differentiator }} diff --git a/.github/workflows/flutter-desktop-tests.yml b/.github/workflows/flutter-desktop-tests.yml index 13c55e297..52af86dbe 100644 --- a/.github/workflows/flutter-desktop-tests.yml +++ b/.github/workflows/flutter-desktop-tests.yml @@ -7,10 +7,6 @@ on: description: GitHub runner image to execute on. required: true type: string - differentiator: - description: Differentiator for the BaaS container. - required: true - type: string arch: description: Architecture to execute on. default: x64 @@ -24,12 +20,9 @@ jobs: runs-on: ${{ inputs.runner }} name: Flutter tests on ${{ inputs.runner }}-${{ inputs.arch }} timeout-minutes: 45 - env: - BAAS_BAASAAS_API_KEY: ${{ secrets.BAASAAS_API_KEY}} - BAAS_DIFFERENTIATOR: ${{ inputs.differentiator }} defaults: run: - working-directory: packages/realm/tests + working-directory: packages/realm/tests steps: @@ -44,7 +37,7 @@ jobs: shell: bash - id: runner_os_lowercase - # there is no such thing as ${{ tolower(runner.os) }}, hence this abomination ¯\_(ツ)_/¯ + # there is no such thing as ${{ tolower(runner.os) }}, hence this abomination ¯\_(ツ)_/¯ # use with steps.runner_os_lowercase.outputs.os run: echo ${{ runner.os }} | awk '{print "os=" tolower($0)}' >> $GITHUB_OUTPUT shell: bash @@ -74,8 +67,6 @@ jobs: run: | ${{ runner.os == 'linux' && 'xvfb-run' || '' }} \ flutter test integration_test/all_tests.dart \ - --dart-define=BAAS_BAASAAS_API_KEY=$BAAS_BAASAAS_API_KEY \ - --dart-define=BAAS_DIFFERENTIATOR=$BAAS_DIFFERENTIATOR \ --device-id=${{ steps.runner_os_lowercase.outputs.os }} \ --file-reporter=json:test-results.json \ --suppress-analytics diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index d1cb282e1..e45cc5817 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -78,30 +78,6 @@ jobs: exit 1 fi - - name: Read Core version - id: get-core-version - run: | - pkgVersion=$(yq '.VERSION' dependencies.yml) - echo "core-version=$pkgVersion" >> $GITHUB_OUTPUT - echo "Realm Core version: $pkgVersion" - shell: bash - working-directory: packages/realm_dart/src/realm-core - - - name: Update realmCoreVersion in metrics_command.dart - id: update-realmCoreVersion - uses: jacobtomlinson/gha-find-replace@b76729678e8d52dadb12e0e16454a93e301a919d #! 2.0.0 - with: - find: "const realmCoreVersion = '[^']*';" - replace: "const realmCoreVersion = '${{ steps.get-core-version.outputs.core-version }}';" - include: 'packages/realm_dart/lib/src/cli/metrics/metrics_command.dart' - - - name: Make sure we updated realmCoreVersion in metrics - run: | - if [ ${{ steps.update-realmCoreVersion.outputs.modifiedFiles }} -gt 1 ]; then - echo 'At most one modified file expected, got ${{ steps.update-realmCoreVersion.outputs.modifiedFiles }}' - exit 1 - fi - - name: Create Release PR uses: peter-evans/create-pull-request@7380612b49221684fefa025244f2ef4008ae50ad #! 3.10.1 with: diff --git a/.github/workflows/terminate-baas.yml b/.github/workflows/terminate-baas.yml deleted file mode 100644 index 7336dc931..000000000 --- a/.github/workflows/terminate-baas.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Terminate BaaS - -on: - workflow_call: - inputs: - differentiator: - description: Differentiator for the BaaS container. - required: true - type: string - -env: - REALM_CI: true - -jobs: - terminate-baas: - runs-on: ubuntu-latest - name: Terminate BaaS - timeout-minutes: 15 - defaults: - run: - working-directory: packages/realm_dart # TODO: Move out of realm_dart - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - submodules: false - - - name: Setup Runner - uses: ./.github/actions/setup-runner - - - name: Terminate baas - run: dart run realm_dart delete-apps --baasaas-api-key ${{ secrets.BAASAAS_API_KEY }} --differentiator ${{ inputs.differentiator }} diff --git a/dartdoc_options.yaml b/dartdoc_options.yaml index 1614f7b99..7a07b0cfb 100644 --- a/dartdoc_options.yaml +++ b/dartdoc_options.yaml @@ -3,9 +3,7 @@ dartdoc: "Configuration": "Annotations": "Realm": - "Application": - "Sync": - categoryOrder: ["Realm", "Configuration", "Annotations", "Application", "Sync"] + categoryOrder: ["Realm", "Configuration", "Annotations"] examplePathPrefix: 'example' # nodoc: ['generator/flutter/ffigen/scripts/src/test/*.g.dart'] showUndocumentedCategories: true diff --git a/packages/realm/android/build.gradle b/packages/realm/android/build.gradle index 3ffcaa6d1..afa01ec47 100644 --- a/packages/realm/android/build.gradle +++ b/packages/realm/android/build.gradle @@ -36,7 +36,7 @@ android { abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' } } - + sourceSets { main { java { @@ -45,7 +45,7 @@ android { jniLibs.srcDirs += ["src/main/cpp/lib/"] } } - + lintOptions { disable 'InvalidPackage' } @@ -81,27 +81,6 @@ def getPaths() { return [flutterRoot, dartExecutable] } -tasks.register("runMetrics", Exec) { - outputs.upToDateWhen { false } - - try { - def appProject = project.rootProject.subprojects.find { p -> p.name == 'app' } - def (flutterRoot, dartExecutable) = getPaths() - - workingDir "${project.rootProject.projectDir}${File.separator}.." - - String targetOsVersion - if (appProject != null) { - def conf = appProject.android.defaultConfig - targetOsVersion = "API Level ${conf.targetSdkVersion.apiLevel}" - } - commandLine dartExecutable, 'run', 'realm', 'metrics', '--flutter-root', flutterRoot, '--target-os-type', 'android', '--target-os-version', targetOsVersion - } - catch (e) { - logger.error "Error running metrics command $e" - } -} - tasks.register("downloadRealmBinaries", Exec) { outputs.upToDateWhen { false } @@ -134,11 +113,11 @@ def getBundleId() { tasks.register("generateRealmConfig", Copy) { outputs.upToDateWhen { false } - + def bundleId = getBundleId(); from 'src/gen' into "$buildDir/realm-generated" filter { line -> line.replaceAll('realm_bundle_id', "${bundleId}") } } -preBuild.dependsOn runMetrics, downloadRealmBinaries, generateRealmConfig \ No newline at end of file +preBuild.dependsOn downloadRealmBinaries, generateRealmConfig \ No newline at end of file diff --git a/packages/realm/ios/realm.podspec b/packages/realm/ios/realm.podspec index 183b62045..05f826df8 100644 --- a/packages/realm/ios/realm.podspec +++ b/packages/realm/ios/realm.podspec @@ -45,10 +45,6 @@ Pod::Spec.new do |s| #Use --debug to debug the install command :script => 'source "$PROJECT_DIR/../Flutter/flutter_export_environment.sh" && cd "$FLUTTER_APPLICATION_PATH" && "$FLUTTER_ROOT/bin/dart" run realm install --target-os-type ios', :execution_position => :before_headers - }, - { :name => 'Report Metrics', - :script => 'source "$PROJECT_DIR/../Flutter/flutter_export_environment.sh" && cd "$FLUTTER_APPLICATION_PATH" && "$FLUTTER_ROOT/bin/dart" run realm metrics --flutter-root "$FLUTTER_ROOT" --target-os-type ios --target-os-version "$IPHONEOS_DEPLOYMENT_TARGET"', - :execution_position => :before_compile } ] s.resource_bundles = { 'realm_privacy' => [ 'Resources/PrivacyInfo.xcprivacy' ] } diff --git a/packages/realm/linux/CMakeLists.txt b/packages/realm/linux/CMakeLists.txt index 688310714..d427b854c 100644 --- a/packages/realm/linux/CMakeLists.txt +++ b/packages/realm/linux/CMakeLists.txt @@ -34,6 +34,7 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) set(APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../..") file(REAL_PATH ${APP_DIR} ABSOLUTE_PATH_APP_DIR) + # message ("ABSOLUTE_PATH_APP_DIR is ${ABSOLUTE_PATH_APP_DIR}") # message ("APP_DIR is ${APP_DIR}") @@ -64,16 +65,3 @@ execute_process(COMMAND "${FLUTTER_ROOT}/bin/dart" "run" "realm" "install" "--ta ) message(STATUS "cmd output: ${output}") message(STATUS "cmd result: ${result}") - -# message("CMAKE_HOST_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION}") -execute_process( - COMMAND "${FLUTTER_ROOT}/bin/dart" "run" "realm" "metrics" "--verbose" "--flutter-root" "${FLUTTER_ROOT}/bin" "--target-os-type" "linux" "--target-os-version" "${CMAKE_HOST_SYSTEM_VERSION}" # "--pause-isolates-on-start" "--enable-vm-service" - WORKING_DIRECTORY ${ABSOLUTE_PATH_APP_DIR} - # COMMAND ${CMAKE_COMMAND} -E true - OUTPUT_VARIABLE output - RESULT_VARIABLE result - - # COMMAND_ERROR_IS_FATAL LAST -) -message(STATUS "cmd output: ${output}") -message(STATUS "cmd result: ${result}") diff --git a/packages/realm/macos/realm.podspec b/packages/realm/macos/realm.podspec index 488b7e49a..d834c9249 100644 --- a/packages/realm/macos/realm.podspec +++ b/packages/realm/macos/realm.podspec @@ -17,9 +17,9 @@ if realmLibraryPath.include?("packages/realm/") && !File.exist?(realmLibraryPath if !File.exist?(absoluteRealRealmLibPath) raise "Realm macos library does not exists in realm-dart repo at path #{absoluteRealRealmLibPath}" end - + # create an absolute symlink to realm flutter macos lib librealm_dart.dylib - File.symlink(absoluteRealRealmLibPath, realmLibraryPath); + File.symlink(absoluteRealRealmLibPath, realmLibraryPath); end # This works cause realm plugin is always accessed through the .symlinks directory. @@ -59,10 +59,6 @@ Pod::Spec.new do |s| #Use --debug to debug the install command :script => 'source "$PROJECT_DIR/../Flutter/ephemeral/flutter_export_environment.sh" && cd "$FLUTTER_APPLICATION_PATH" && "$FLUTTER_ROOT/bin/dart" run realm install --target-os-type macos', :execution_position => :before_headers - }, - { :name => 'Report Metrics', - :script => 'source "$PROJECT_DIR/../Flutter/ephemeral/flutter_export_environment.sh" && cd "$FLUTTER_APPLICATION_PATH" && "$FLUTTER_ROOT/bin/dart" run realm metrics --flutter-root "$FLUTTER_ROOT" --target-os-type macos --target-os-version "$MACOSX_DEPLOYMENT_TARGET"', - :execution_position => :before_compile } ] s.resource_bundles = { 'realm_privacy' => [ 'Resources/PrivacyInfo.xcprivacy' ] } diff --git a/packages/realm/tests/integration_test/all_tests.dart b/packages/realm/tests/integration_test/all_tests.dart index 8b2b98ab3..1459abbe7 100644 --- a/packages/realm/tests/integration_test/all_tests.dart +++ b/packages/realm/tests/integration_test/all_tests.dart @@ -9,19 +9,14 @@ import 'package:test/test.dart'; import '../../../realm_dart/test/test.dart' as test; -import '../../../realm_dart/test/app_test.dart' as app_test; -import '../../../realm_dart/test/asymmetric_test.dart' as asymmetric_test; import '../../../realm_dart/test/backlinks_test.dart' as backlinks_test; -import '../../../realm_dart/test/client_reset_test.dart' as client_reset_test; import '../../../realm_dart/test/configuration_test.dart' as configuration_test; -import '../../../realm_dart/test/credentials_test.dart' as credentials_test; import '../../../realm_dart/test/decimal128_test.dart' as decimal128_test; import '../../../realm_dart/test/dynamic_realm_test.dart' as dynamic_realm_test; import '../../../realm_dart/test/embedded_test.dart' as embedded_test; import '../../../realm_dart/test/geospatial_test.dart' as geospatial_test; import '../../../realm_dart/test/indexed_test.dart' as indexed_test; import '../../../realm_dart/test/list_test.dart' as list_test; -import '../../../realm_dart/test/manual_test.dart' as manual_test; import '../../../realm_dart/test/migration_test.dart' as migration_test; import '../../../realm_dart/test/realm_logger_test.dart' as realm_logger_test; import '../../../realm_dart/test/realm_map_test.dart' as realm_map_test; @@ -31,10 +26,6 @@ import '../../../realm_dart/test/realm_test.dart' as realm_test; import '../../../realm_dart/test/realm_value_test.dart' as realm_value_test; import '../../../realm_dart/test/results_test.dart' as results_test; import '../../../realm_dart/test/serialization_test.dart' as serialization_test; -import '../../../realm_dart/test/session_test.dart' as session_test; -import '../../../realm_dart/test/subscription_test.dart' as subscription_test; -import '../../../realm_dart/test/sync_migration_test.dart' as sync_migration_test; -import '../../../realm_dart/test/user_test.dart' as user_test; Future _copyBundledFile(String fromPath, String toPath) async { final data = await rootBundle.load(fromPath); @@ -49,19 +40,14 @@ void main() { // copyFile function. Remember to add any needed files as assets in pubspec.yaml. test.copyFile = _copyBundledFile; - group('app_test.dart', app_test.main); - group('asymmetric_test.dart', asymmetric_test.main); group('backlinks_test.dart', backlinks_test.main); - group('client_reset_test.dart', client_reset_test.main); group('configuration_test.dart', configuration_test.main); - group('credentials_test.dart', credentials_test.main); group('decimal128_test.dart', decimal128_test.main); group('dynamic_realm_test.dart', dynamic_realm_test.main); group('embedded_test.dart', embedded_test.main); group('geospatial_test.dart', geospatial_test.main); group('indexed_test.dart', indexed_test.main); group('list_test.dart', list_test.main); - group('manual_test.dart', manual_test.main); group('migration_test.dart', migration_test.main); group('realm_logger_test.dart', realm_logger_test.main); group('realm_map_test.dart', realm_map_test.main); @@ -71,8 +57,4 @@ void main() { group('realm_value_test.dart', realm_value_test.main); group('results_test.dart', results_test.main); group('serialization_test.dart', serialization_test.main); - group('session_test.dart', session_test.main); - group('subscription_test.dart', subscription_test.main); - group('sync_migration_test.dart', sync_migration_test.main); - group('user_test.dart', user_test.main); } diff --git a/packages/realm/windows/CMakeLists.txt b/packages/realm/windows/CMakeLists.txt index 8b8130ada..dd268bb06 100644 --- a/packages/realm/windows/CMakeLists.txt +++ b/packages/realm/windows/CMakeLists.txt @@ -30,11 +30,14 @@ set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../ephemeral") include(${EPHEMERAL_DIR}/generated_config.cmake) set(APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../..") + # message ("APP_DIR is ${APP_DIR}") set(APP_PUBSPEC_FILE "${APP_DIR}/pubspec.yaml") + # message ("APP_PUBSPEC_FILE is ${APP_PUBSPEC_FILE}") file(READ "${APP_PUBSPEC_FILE}" PUBSPEC_CONTENT) string(REGEX MATCH "name:[ \r\n\t]*([a-z0-9_]*)" _ ${PUBSPEC_CONTENT}) + # message ("Pubspec name 0 is ${CMAKE_MATCH_0}") # message ("Package name is ${CMAKE_MATCH_1}") set(APP_DIR_NAME ${CMAKE_MATCH_1}) @@ -43,25 +46,12 @@ set(BUNDLE_ID ${CMAKE_MATCH_1}) add_definitions(-DAPP_DIR_NAME="${APP_DIR_NAME}") add_definitions(-DBUNDLE_ID="${BUNDLE_ID}") - # message ("FLUTTER_TOOL_ENVIRONMENT is ${FLUTTER_TOOL_ENVIRONMENT}") # message ("FLUTTER_ROOT is ${FLUTTER_ROOT}") - -execute_process(COMMAND "${FLUTTER_ROOT}\\bin\\dart.bat" "run" "realm" "install" "--target-os-type" "windows" #"--debug" +execute_process(COMMAND "${FLUTTER_ROOT}\\bin\\dart.bat" "run" "realm" "install" "--target-os-type" "windows" # "--debug" OUTPUT_VARIABLE output RESULT_VARIABLE result COMMAND_ERROR_IS_FATAL ANY ) message(STATUS "cmd output: ${output}") message(STATUS "cmd result: ${result}") - -# message("CMAKE_HOST_SYSTEM_VERSION ${CMAKE_HOST_SYSTEM_VERSION}") -execute_process( - COMMAND "${FLUTTER_ROOT}\\bin\\dart.bat" "run" "realm" "metrics" "--verbose" "--flutter-root" "${FLUTTER_ROOT}\\bin" "--target-os-type" "windows" "--target-os-version" "${CMAKE_HOST_SYSTEM_VERSION}" #"--pause-isolates-on-start" "--enable-vm-service" - # COMMAND ${CMAKE_COMMAND} -E true - OUTPUT_VARIABLE output - RESULT_VARIABLE result - # COMMAND_ERROR_IS_FATAL LAST -) -message(STATUS "cmd output: ${output}") -message(STATUS "cmd result: ${result}") diff --git a/packages/realm_common/lib/src/realm_common_base.dart b/packages/realm_common/lib/src/realm_common_base.dart index 742085801..ab4de3d61 100644 --- a/packages/realm_common/lib/src/realm_common_base.dart +++ b/packages/realm_common/lib/src/realm_common_base.dart @@ -13,12 +13,7 @@ enum ObjectType { /// An object that can be embedded in other objects. It is considered owned /// by its parent and will be deleted if its parent is deleted. - embeddedObject('EmbeddedObject', 1), - - /// A special type of object used to facilitate unidirectional synchronization - /// with Atlas App Services. It is used to push data to Realm without the ability - /// to query or modify it. - asymmetricObject('AsymmetricObject', 2); + embeddedObject('EmbeddedObject', 1); const ObjectType(this._className, this._flags); diff --git a/packages/realm_common/lib/src/realm_types.dart b/packages/realm_common/lib/src/realm_types.dart index af031ae7e..54bb272c1 100644 --- a/packages/realm_common/lib/src/realm_types.dart +++ b/packages/realm_common/lib/src/realm_types.dart @@ -132,9 +132,6 @@ abstract class RealmObjectMarker implements RealmObjectBaseMarker {} /// @nodoc abstract class EmbeddedObjectMarker implements RealmObjectBaseMarker {} -/// @nodoc -abstract class AsymmetricObjectMarker implements RealmObjectBaseMarker {} - /// An enum describing the possible types that can be wrapped inside [RealmValue] enum RealmValueType { /// The [RealmValue] represents `null` diff --git a/packages/realm_dart/build.yaml b/packages/realm_dart/build.yaml index 626a99d8a..2627267aa 100644 --- a/packages/realm_dart/build.yaml +++ b/packages/realm_dart/build.yaml @@ -4,16 +4,12 @@ targets: build_cli: generate_for: - lib/src/cli/**/**.dart - json_serializable: - generate_for: - - lib/src/cli/metrics/flutter_info.dart - - lib/src/cli/metrics/metrics.dart realm_generator: generate_for: include: - test/**.dart - example/**.dart - + builders: realm_generator: import: "package:realm_generator/realm_generator.dart" diff --git a/packages/realm_dart/ffigen.yaml b/packages/realm_dart/ffigen.yaml index 905257949..19373169d 100644 --- a/packages/realm_dart/ffigen.yaml +++ b/packages/realm_dart/ffigen.yaml @@ -1,7 +1,7 @@ # Regenerate bindings with `dart run ffigen --config ffigen.yaml`. name: RealmLibrary description: Realm native lib bindings. -output: "lib/src/native/realm_bindings.dart" +output: "lib/src/handles/native/realm_bindings.dart" headers: entry-points: - 'src/realm-core/src/realm.h' diff --git a/packages/realm_dart/lib/src/app.dart b/packages/realm_dart/lib/src/app.dart deleted file mode 100644 index 8e25d0965..000000000 --- a/packages/realm_dart/lib/src/app.dart +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:isolate'; - -import 'package:http/http.dart'; -import 'package:meta/meta.dart'; -import 'package:path/path.dart' as path; - -import '../realm.dart'; -import 'credentials.dart'; -import 'handles/app_handle.dart'; -import 'handles/default_client.dart'; -import 'handles/realm_core.dart'; -import 'logging.dart'; -import 'user.dart'; - -/// Options for configuring timeouts and intervals used by the sync client. -@immutable -final class SyncTimeoutOptions { - /// Controls the maximum amount of time to allow for a connection to - /// become fully established. - /// - /// This includes the time to resolve the - /// network address, the TCP connect operation, the SSL handshake, and - /// the WebSocket handshake. - /// - /// Defaults to 2 minutes. - final Duration connectTimeout; // TimeSpan.FromMinutes(2); - - /// Controls the amount of time to keep a connection open after all - /// sessions have been abandoned. - /// - /// After all synchronized Realms have been closed for a given server, the - /// connection is kept open until the linger time has expired to avoid the - /// overhead of reestablishing the connection when Realms are being closed and - /// reopened. - /// - /// Defaults to 30 seconds. - final Duration connectionLingerTime; - - /// Controls how long to wait between each heartbeat ping message. - /// - /// The client periodically sends ping messages to the server to check if the - /// connection is still alive. Shorter periods make connection state change - /// notifications more responsive at the cost of battery life (as the antenna - /// will have to wake up more often). - /// - /// Defaults to 1 minute. - final Duration pingKeepAlivePeriod; - - /// Controls how long to wait for a reponse to a heartbeat ping before - /// concluding that the connection has dropped. - /// - /// Shorter values will make connection state change notifications more - /// responsive as it will only change to `disconnected` after this much time has - /// elapsed, but overly short values may result in spurious disconnection - /// notifications when the server is simply taking a long time to respond. - /// - /// Defaults to 2 minutes. - final Duration pongKeepAliveTimeout; - - /// Controls the maximum amount of time since the loss of a - /// prior connection, for a new connection to be considered a "fast - /// reconnect". - /// - /// When a client first connects to the server, it defers uploading any local - /// changes until it has downloaded all changesets from the server. This - /// typically reduces the total amount of merging that has to be done, and is - /// particularly beneficial the first time that a specific client ever connects - /// to the server. - /// - /// When an existing client disconnects and then reconnects within the "fact - /// reconnect" time this is skipped and any local changes are uploaded - /// immediately without waiting for downloads, just as if the client was online - /// the whole time. - /// - /// Defaults to 1 minute. - final Duration fastReconnectLimit; - - const SyncTimeoutOptions({ - this.connectTimeout = const Duration(minutes: 2), - this.connectionLingerTime = const Duration(seconds: 30), - this.pingKeepAlivePeriod = const Duration(minutes: 1), - this.pongKeepAliveTimeout = const Duration(minutes: 2), - this.fastReconnectLimit = const Duration(minutes: 1), - }); -} - -/// A class exposing configuration options for an [App] -/// {@category Application} -@immutable -class AppConfiguration { - /// The [appId] is the unique id that identifies the [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) application. - final String appId; - - /// The [baseFilePath] is the [Directory] relative to which all local data for this application will be stored. - /// - /// This data includes metadata for users and synchronized Realms. If set, you must ensure that the [baseFilePath] - /// directory exists. - final String baseFilePath; - - /// The [baseUrl] is the [Uri] used to reach the MongoDB Atlas. - /// - /// [baseUrl] only needs to be set if for some reason your application isn't hosted on services.cloud.mongodb.com. - /// This can be the case if you're synchronizing with an edge server. - final Uri baseUrl; - - /// The [defaultRequestTimeout] for HTTP requests. Defaults to 60 seconds. - final Duration defaultRequestTimeout; - - /// The maximum duration to allow for a connection to - /// become fully established. This includes the time to resolve the - /// network address, the TCP connect operation, the SSL handshake, and - /// the WebSocket handshake. Defaults to 2 minutes. - @Deprecated('Use SyncTimeoutOptions.connectTimeout') - final Duration maxConnectionTimeout; - - /// Enumeration that specifies how and if logged-in User objects are persisted across application launches. - final MetadataPersistenceMode metadataPersistenceMode; - - /// The encryption key to use for user metadata on this device, if [metadataPersistenceMode] is - /// [MetadataPersistenceMode.encrypted]. - /// - /// The [metadataEncryptionKey] must be exactly 64 bytes. - /// Setting this will not change the encryption key for individual Realms, which is set in the [Configuration]. - final List? metadataEncryptionKey; - - /// The [Client] that will be used for HTTP requests during authentication. - /// - /// You can use this to override the default http client handler and configure settings like proxies, - /// client certificates, and cookies. While these are not required to connect to MongoDB Atlas under - /// normal circumstances, they can be useful if client devices are behind corporate firewall or use - /// a more complex networking setup. - final Client httpClient; - - /// Options for the assorted types of connection timeouts for sync connections opened for this app. - final SyncTimeoutOptions syncTimeoutOptions; - - /// Instantiates a new [AppConfiguration] with the specified appId. - AppConfiguration( - this.appId, { - Uri? baseUrl, - String? baseFilePath, - this.defaultRequestTimeout = const Duration(seconds: 60), - this.metadataEncryptionKey, - this.metadataPersistenceMode = MetadataPersistenceMode.plaintext, - @Deprecated('Use SyncTimeoutOptions.connectTimeout') this.maxConnectionTimeout = const Duration(minutes: 2), - Client? httpClient, - this.syncTimeoutOptions = const SyncTimeoutOptions(), - }) : baseUrl = baseUrl ?? Uri.parse(realmCore.getDefaultBaseUrl()), - baseFilePath = baseFilePath ?? path.dirname(Configuration.defaultRealmPath), - httpClient = httpClient ?? defaultClient { - if (appId == '') { - throw RealmException('Supplied appId must be a non-empty value'); - } - } -} - -/// An [App] is the main client-side entry point for interacting with an [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) application. -/// -/// The [App] can be used to -/// * Register uses and perform various user-related operations through authentication providers -/// * Synchronize data between the local device and a remote Realm App with Synchronized Realms -/// {@category Application} -class App { - final AppHandle _handle; - - /// The id of this application. This is the same as the appId in the [AppConfiguration] used to - /// create this [App]. - String get id => handle.id; - - /// Create an app with a particular [AppConfiguration]. This constructor should only be used on the main isolate and, - /// ideally, only once as soon as the app starts. - App(AppConfiguration configuration) : _handle = _createApp(configuration) { - // This is not foolproof, but could point people to errors they may have in their app. Realm apps are cached natively, so calling App(config) - // on a background isolate will not recreate the app. Instead, users should construct the app on the main isolate and then call getById on the - // background isolates. This check will log a warning if the isolate name is != 'main' and doesn't start with 'test/' since dart test will - // construct a new isolate per file and we don't want to log excessively in unit test projects. - if (Isolate.current.debugName != 'main' && Isolate.current.debugName?.startsWith('test/') == false) { - Realm.logger.log(LogLevel.warn, - "App constructor called on Isolate ${Isolate.current.debugName} which doesn't appear to be the main isolate. If you need an app instance on a background isolate use App.getById after constructing the App on the main isolate."); - } - } - - /// Obtain an [App] instance by id. The app must have first been created by calling the constructor that takes an [AppConfiguration] - /// on the main isolate. If an App hasn't been already constructed with the same id, will return null. This method is safe to call - /// on a background isolate. - static App? getById(String id, {Uri? baseUrl}) { - final handle = AppHandle.get(id, baseUrl?.toString()); - return handle == null ? null : App._(handle); - } - - App._(this._handle); - - static AppHandle _createApp(AppConfiguration configuration) { - return AppHandle.from(configuration); - } - - /// Logs in a user with the given credentials. - Future logIn(Credentials credentials) async { - var userHandle = await handle.logIn(credentials.handle); - return UserInternal.create(userHandle, this); - } - - /// Gets the currently logged in [User]. If none exists, `null` is returned. - User? get currentUser { - final userHandle = _handle.currentUser; - if (userHandle == null) { - return null; - } - return UserInternal.create(userHandle, this); - } - - /// Gets all currently logged in users. - Iterable get users { - return handle.users.map((handle) => UserInternal.create(handle, this)); - } - - /// Removes a [user] and their local data from the device. If the user is logged in, they will be logged out in the process. - Future removeUser(User user) async { - return await handle.removeUser(user.handle); - } - - /// Deletes a user and all its data from the device as well as the server. - Future deleteUser(User user) async { - return await handle.deleteUser(user.handle); - } - - /// Switches the [currentUser] to the one specified in [user]. - void switchUser(User user) { - handle.switchUser(user.handle); - } - - /// Provide a hint to this app's sync client to reconnect. - /// Useful when the device has been offline and then receives a network reachability update. - /// - /// The sync client will always attempt to reconnect eventually, this is just a hint. - void reconnect() { - handle.reconnect(); - } - - /// Returns the current value of the base URL used to communicate with the server. - /// - /// If an [updateBaseUrl] operation is currently in progress, this value will not - /// be updated with the new value until that operation has completed. - @experimental - Uri get baseUrl { - return Uri.parse(handle.baseUrl); - } - - /// Temporarily overrides the [baseUrl] value from [AppConfiguration] with a new [baseUrl] value - /// used for communicating with the server. If set to `null`, the app will revert to the default - /// base url. - /// - /// If this operation fails, the app will continue to use the original base URL. If another [App] - /// operation is started while this function is in progress, that request will use the original - /// base URL location information. - /// - /// The App will revert to using the value in [AppConfiguration] when it is restarted. - @experimental - Future updateBaseUrl(Uri? baseUrl) async { - return await handle.updateBaseUrl(baseUrl); - } - - /// Returns an instance of [EmailPasswordAuthProvider] - EmailPasswordAuthProvider get emailPasswordAuthProvider => EmailPasswordAuthProviderInternal.create(this); -} - -/// Specify if and how to persists user objects. -/// {@category Application} -enum MetadataPersistenceMode { - /// Persist [User] objects, but do not encrypt them. - plaintext, - - /// Persist [User] objects in an encrypted store. - encrypted, - - /// Do not persist [User] objects. - disabled, -} - -/// @nodoc -extension AppInternal on App { - AppHandle get handle => _handle; - - static App create(AppHandle handle) => App._(handle); - - static AppException createException(String message, String? linkToLogs, int statusCode) => AppException._(message, linkToLogs, statusCode); -} - -/// An exception thrown from operations interacting with a [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) app. -class AppException extends RealmException { - /// A link to the server logs associated with this exception if available. - final String? linkToServerLogs; - - /// The HTTP status code returned by the server for this exception. - final int statusCode; - - AppException._(super.message, this.linkToServerLogs, this.statusCode); - - @override - String toString() { - var errorString = "AppException: $message, status code: $statusCode"; - if (linkToServerLogs != null) { - errorString += ", link to server logs: $linkToServerLogs"; - } - - return errorString; - } -} diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/baas_client.dart b/packages/realm_dart/lib/src/cli/atlas_apps/baas_client.dart deleted file mode 100644 index 7d340f97f..000000000 --- a/packages/realm_dart/lib/src/cli/atlas_apps/baas_client.dart +++ /dev/null @@ -1,887 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:collection/collection.dart'; -import 'package:http/http.dart' as http; -import 'dart:convert'; - -class BaasAuthHelper { - static const String _appId = 'baas-container-service-autzb'; - final String _apiKey; - final String _location; - - BaasAuthHelper(this._apiKey) : _location = 'https://us-east-1.aws.data.mongodb-api.com'; - - Future callEndpoint(String name, {Object? body, Map? query, bool isPost = true}) async { - var url = '$_location/app/$_appId/endpoint/$name'; - if (query != null) { - url = '$url?${query.entries.map((kvp) => '${kvp.key}=${kvp.value}').join('&')}'; - } - final headers = {'apiKey': _apiKey}; - final response = isPost ? await http.post(Uri.parse(url), headers: headers, body: jsonEncode(body)) : await http.get(Uri.parse(url), headers: headers); - - return BaasClient._decodeResponse(response); - } - - Future getUserId() async { - final response = await callEndpoint('userinfo', isPost: false) as Map; - return response['id'] as String; - } -} - -enum AppName { - flexible, - - // For application with name 'autoConfirm' and with confirmationType = 'auto' - // all the usernames are automatically confirmed. - autoConfirm, - - emailConfirm, - - staticSchema, -} - -class JsonSchemaDefinition { - final String collectionName; - final List properties; - - JsonSchemaDefinition(this.collectionName, this.properties); -} - -class JsonSchemaProperty { - final String name; - final String bsonType; - - final bool required; - - JsonSchemaProperty({required this.name, required this.bsonType, required this.required}); - - Map toJson() => {'bsonType': bsonType}; -} - -class BaasClient { - static const String _mongoServiceName = 'BackingDB'; - - static const String _confirmFuncSource = '''exports = async ({ token, tokenId, username }) => { - // process the confirm token, tokenId and username - if (username.includes("realm_tests_do_autoverify")) { - return { status: 'success' } - } - else if (username.includes("realm_tests_pending_confirm")) { - const mdb = context.services.get("$_mongoServiceName"); - const collection = mdb.db("custom-auth").collection("users"); - const existing = await collection.findOne({ username: username }); - if (existing) { - return { status: 'success' }; - } - - await collection.insertOne({ username: username }); - return { status: 'pending' } - } - else - { - // do not confirm the user - return { status: 'fail' }; - } - };'''; - - static const String _resetFuncSource = '''exports = ({ token, tokenId, username, password }, status) => { - // process the reset token, tokenId, username and password - if (status && status !== "") { - return { status: status }; - } - else - { - return { status: 'fail' }; - } - };'''; - - static const String _authFuncSource = '''exports = (loginPayload) => { - return loginPayload["userId"]; - };'''; - - static const String _userFuncNoArgs = '''exports = function(){ - return {}; - };'''; - - static const String _userFuncOneArg = '''exports = function(arg){ - return {'arg': arg }; - };'''; - - static const String _userFuncTwoArgs = '''exports = function(arg1, arg2){ - return { 'arg1': arg1, 'arg2': arg2}; - };'''; - - static const String _triggerClientResetFuncSource = '''exports = async function(userId, appId) { - const mongodb = context.services.get('$_mongoServiceName'); - console.log('user.id: ' + context.user.id); - try { - const dbName = `__realm_sync_\${appId}`; - const deletionResult = await mongodb.db(dbName).collection('clientfiles').deleteMany({ ownerId: userId }); - console.log('Deleted documents: ' + deletionResult.deletedCount); - - return { status: deletionResult.deletedCount > 0 ? 'success' : 'failure' }; - } catch(err) { - throw 'Deletion failed: ' + err; - } - };'''; - - static final _nullablesSchemaV0 = JsonSchemaDefinition('Nullables', [ - JsonSchemaProperty(name: '_id', bsonType: 'objectId', required: true), - JsonSchemaProperty(name: 'differentiator', bsonType: 'objectId', required: true), - JsonSchemaProperty(name: 'boolValue', bsonType: 'bool', required: false), - JsonSchemaProperty(name: 'intValue', bsonType: 'long', required: false), - JsonSchemaProperty(name: 'floatValue', bsonType: 'float', required: false), - JsonSchemaProperty(name: 'doubleValue', bsonType: 'double', required: false), - JsonSchemaProperty(name: 'decimalValue', bsonType: 'decimal', required: false), - JsonSchemaProperty(name: 'dateValue', bsonType: 'date', required: false), - JsonSchemaProperty(name: 'stringValue', bsonType: 'string', required: false), - JsonSchemaProperty(name: 'objectIdValue', bsonType: 'objectId', required: false), - JsonSchemaProperty(name: 'uuidValue', bsonType: 'uuid', required: false), - JsonSchemaProperty(name: 'binaryValue', bsonType: 'binData', required: false), - ]); - - static final _nullablesSchemaV1 = JsonSchemaDefinition('Nullables', [ - JsonSchemaProperty(name: '_id', bsonType: 'objectId', required: true), - JsonSchemaProperty(name: 'differentiator', bsonType: 'objectId', required: true), - JsonSchemaProperty(name: 'boolValue', bsonType: 'bool', required: true), - JsonSchemaProperty(name: 'intValue', bsonType: 'long', required: true), - JsonSchemaProperty(name: 'floatValue', bsonType: 'float', required: true), - JsonSchemaProperty(name: 'doubleValue', bsonType: 'double', required: true), - JsonSchemaProperty(name: 'decimalValue', bsonType: 'decimal', required: true), - JsonSchemaProperty(name: 'dateValue', bsonType: 'date', required: true), - JsonSchemaProperty(name: 'stringValue', bsonType: 'string', required: true), - JsonSchemaProperty(name: 'objectIdValue', bsonType: 'objectId', required: true), - JsonSchemaProperty(name: 'uuidValue', bsonType: 'uuid', required: true), - JsonSchemaProperty(name: 'binaryValue', bsonType: 'binData', required: true), - JsonSchemaProperty(name: 'willBeRemoved', bsonType: 'string', required: true), - ]); - - static final String defaultAppName = AppName.flexible.name; - - final String _adminApiUrl; - final String? _clusterName; - final Map _headers; - final String _appSuffix; - - final String baseUrl; - - late String _groupId; - late String publicRSAKey = ''; - - BaasClient._(this.baseUrl, String differentiator, [this._clusterName]) - : _adminApiUrl = '$baseUrl/api/admin/v3.0', - _headers = {'Accept': 'application/json'}, - _appSuffix = '-${shortenDifferentiator(differentiator)}${_clusterName == null ? '' : '-$_clusterName'}'; - - /// A client that imports apps in a MongoDB Atlas docker image. See https://github.com/realm/ci/tree/master/realm/docker/mongodb-realm - /// for instructions on how to set it up. - /// @nodoc - static Future docker(String baseUrl, String differentiator) async { - final result = BaasClient._(baseUrl, differentiator); - - await result._authenticate('local-userpass', '{ "username": "unique_user@domain.com", "password": "password" }'); - - dynamic groupDoc = await result._get('auth/profile'); - result._groupId = groupDoc['roles'][0]['group_id'] as String; - - print('Current GroupID ${result._groupId}'); - - return result; - } - - static Future deleteContainer(String apiKey, String differentiator) async { - try { - print('Stopping all containers with differentiator $differentiator'); - final authHelper = BaasAuthHelper(apiKey); - final containers = await _getContainers(authHelper, differentiator: differentiator); - for (final container in containers) { - print('Stopping container ${container.id}'); - await authHelper.callEndpoint('stopContainer', query: {'id': container.id}); - print('Stopped container ${container.id}'); - } - return; - } catch (e) { - print('Failed to destroy container: $e'); - rethrow; - } - } - - static Future<(String httpUrl, String containerId)> getOrDeployContainer(String apiKey, String differentiator) async { - final authHelper = BaasAuthHelper(apiKey); - final existing = (await _getContainers(authHelper, differentiator: differentiator)).firstOrNull; - if (existing != null) { - print('Using existing BaaS container at ${existing.httpUrl}'); - return (existing.httpUrl, existing.id); - } - - print('Deploying new BaaS container... '); - final response = await authHelper.callEndpoint('startContainer', body: [ - {'key': 'DIFFERENTIATOR', 'value': differentiator} - ]) as Map; - final id = response['id'] as String; - - String? httpUrl; - while (httpUrl == null) { - await Future.delayed(Duration(seconds: 1)); - httpUrl = await _waitForContainer(authHelper, id); - } - - print('Deployed BaaS instance at $httpUrl'); - - return (httpUrl, id); - } - - static Future retry(Future Function() func, {int attempts = 5}) async { - while (attempts >= 0) { - try { - return await func(); - } catch (e) { - print('An error occurred: $e'); - if (--attempts == 0) { - rethrow; - } - } - } - - throw 'UNREACHABLE'; - } - - static Future> _getContainers(BaasAuthHelper helper, {String? differentiator}) async { - var result = (await helper.callEndpoint('listContainers', isPost: false) as List) - .map((e) => _ContainerInfo.fromJson(e as Map)) - .whereNotNull(); - if (differentiator != null) { - final userId = await helper.getUserId(); - result = result.where((c) => c.creatorId == userId && c.tags['DIFFERENTIATOR'] == differentiator); - } - - return result.toList(); - } - - static Future _waitForContainer(BaasAuthHelper authHelper, String taskId) async { - try { - final containers = await _getContainers(authHelper); - final targetContainer = containers.firstWhereOrNull((c) => c.id == taskId); - if (targetContainer == null) { - print('$taskId is not found in container list. Retrying...'); - return null; - } - - if (!targetContainer.isRunning) { - print('$taskId status is ${targetContainer.lastStatus}. Retrying...'); - return null; - } - - final httpUrl = targetContainer.httpUrl; - - final response = await http.get(Uri.parse('$httpUrl/api/private/v1.0/version')); - if (response.statusCode > 300) { - print('$taskId version response is ${response.statusCode}. Retrying...'); - return null; - } - - return httpUrl; - } catch (e) { - print('Error waiting for container: $e'); - return null; - } - } - - /// A client that imports apps to a MongoDB Atlas environment (typically realm-dev or realm-qa). - /// @nodoc - static Future atlas(String baseUrl, String cluster, String apiKey, String privateApiKey, String groupId, String differentiator) async { - final BaasClient result = BaasClient._(baseUrl, differentiator, cluster); - - await result._authenticate('mongodb-cloud', '{ "username": "$apiKey", "apiKey": "$privateApiKey" }'); - - result._groupId = groupId; - - return result; - } - - /// Tries to look up the applications for the specified cluster. For [docker] client, returns all apps, - /// for [atlas] one, it will return only apps with suffix equal to the cluster name. If no apps exist, - /// then it will create the test applications and return them. - /// @nodoc - Future> getOrCreateApps() async { - var apps = await _getApps(); - await _createAppIfNotExists(apps, AppName.flexible); - await _createAppIfNotExists(apps, AppName.autoConfirm); - await _createAppIfNotExists(apps, AppName.emailConfirm); - await _createAppIfNotExists(apps, AppName.staticSchema); - return apps; - } - - Future waitForInitialSync(BaasApp app) async { - while (!await _isSyncComplete(app.appId)) { - print('Initial sync for ${app.name} is incomplete. Waiting 5 seconds.'); - await Future.delayed(Duration(seconds: 5)); - } - - print('Initial sync for ${app.name} is complete.'); - } - - Future _createAppIfNotExists(List existingApps, AppName appName) async { - final existingApp = existingApps.firstWhereOrNull((a) => a.name == appName.name); - if (existingApp == null) { - existingApps.add(await _createApp(appName)); - } - } - - Future _isSyncComplete(String appId) async { - try { - final response = await _get('groups/$_groupId/apps/$appId/sync/progress'); - - final progressInfo = response['progress'] as Map; - for (final key in progressInfo.keys) { - final error = progressInfo[key]['error'] as String?; - if (error != null) { - print(error); - return false; - } - - final namespaceComplete = progressInfo[key]['complete'] as bool; - - if (!namespaceComplete) { - return false; - } - } - - return true; - } catch (e) { - print(e); - return false; - } - } - - Future> _getApps() async { - final apps = await _get('groups/$_groupId/apps') as List; - return apps - .map((dynamic doc) { - final name = doc['name'] as String; - final String appName; - if (name.endsWith(_appSuffix)) { - appName = name.substring(0, name.length - _appSuffix.length); - } else { - return null; - } - return BaasApp(appId: doc['_id'] as String, clientAppId: doc['client_app_id'] as String, name: appName, uniqueName: name, isNewDeployment: false); - }) - .where((doc) => doc != null) - .map((doc) => doc!) - .toList(); - } - - Future updateAppConfirmFunction(String name, [String? source]) async { - final uniqueName = "$name$_appSuffix"; - final dynamic docs = await _get('groups/$_groupId/apps'); - dynamic doc = docs.firstWhere((dynamic d) { - return d["name"] == uniqueName; - }, orElse: () => throw Exception("BAAS app not found")); - final appId = doc['_id'] as String; - final appUniqueName = doc['name'] as String; - final clientAppId = doc['client_app_id'] as String; - final app = BaasApp(appId: appId, clientAppId: clientAppId, name: name, uniqueName: appUniqueName, isNewDeployment: false); - - final dynamic functions = await _get('groups/$_groupId/apps/$appId/functions'); - dynamic function = functions.firstWhere((dynamic f) => f["name"] == "confirmFunc", orElse: () => throw Exception("Func 'confirmFunc' not found")); - final confirmFuncId = function['_id'] as String; - - await _updateFunction(app, 'confirmFunc', confirmFuncId, source ?? _confirmFuncSource); - } - - Future _createApp(AppName appName) async { - final uniqueName = "${appName.name}$_appSuffix"; - print('Creating app $uniqueName'); - - final runConfirmationFunction = appName != AppName.autoConfirm && appName != AppName.emailConfirm; - - BaasApp? app; - try { - final dynamic doc = await _post('groups/$_groupId/apps', '{ "name": "$uniqueName" }'); - - app = - BaasApp(appId: doc['_id'] as String, clientAppId: doc['client_app_id'] as String, name: appName.name, uniqueName: uniqueName, isNewDeployment: true); - - final confirmFuncId = await _createFunction(app, 'confirmFunc', _confirmFuncSource); - final resetFuncId = await _createFunction(app, 'resetFunc', _resetFuncSource); - final authFuncId = await _createFunction(app, 'authFunc', _authFuncSource); - await _createFunction(app, 'userFuncNoArgs', _userFuncNoArgs); - await _createFunction(app, 'userFuncOneArg', _userFuncOneArg); - await _createFunction(app, 'userFuncTwoArgs', _userFuncTwoArgs); - await _createFunction(app, 'triggerClientResetOnSyncServer', _triggerClientResetFuncSource, runAsSystem: true); - - await enableProvider(app, 'anon-user'); - await enableProvider(app, 'local-userpass', config: '''{ - "autoConfirm": ${appName == AppName.autoConfirm}, - "confirmEmailSubject": "Confirmation required", - "confirmationFunctionName": "confirmFunc", - "confirmationFunctionId": "$confirmFuncId", - "emailConfirmationUrl": "http://localhost/confirmEmail", - "resetFunctionName": "resetFunc", - "resetFunctionId": "$resetFuncId", - "resetPasswordSubject": "", - "resetPasswordUrl": "http://localhost/resetPassword", - "runConfirmationFunction": $runConfirmationFunction, - "runResetFunction": true - }'''); - - await enableProvider(app, 'api-key'); - - if (publicRSAKey.isNotEmpty) { - String publicRSAKeyEncoded = jsonEncode(publicRSAKey); - final dynamic createSecretResult = await _post('groups/$_groupId/apps/$app/secrets', '{"name":"rsPublicKey","value":$publicRSAKeyEncoded}'); - String keyName = createSecretResult['name'] as String; - - await enableProvider(app, 'custom-token', config: '''{ - "audience": "mongodb.com", - "signingAlgorithm": "RS256", - "useJWKURI": false - }''', secretConfig: '''{ - "signingKeys": ["$keyName"] - }''', metadataFelds: '''{ - "required": false, - "name": "name.firstName", - "field_name": "firstName" - }, - { - "required": false, - "name": "name.lastName", - "field_name": "lastName" - }, - { - "required": true, - "name": "email", - "field_name": "name" - }, - { - "required": true, - "name": "email", - "field_name": "email" - }, - { - "required": false, - "name": "gender", - "field_name": "gender" - }, - { - "required": false, - "name": "birthDay", - "field_name": "birthDay" - }, - { - "required": false, - "name": "minAge", - "field_name": "minAge" - }, - { - "required": false, - "name": "maxAge", - "field_name": "maxAge" - }, - { - "required": false, - "name": "company", - "field_name": "company" - }'''); - } - - if (runConfirmationFunction) { - await enableProvider(app, 'custom-function', config: '''{ - "authFunctionName": "authFunc", - "authFunctionId": "$authFuncId" - }'''); - - const facebookSecret = "876750ac6d06618b323dee591602897f"; - final dynamic createFacebookSecretResult = await _post('groups/$_groupId/apps/$app/secrets', '{"name":"facebookSecret","value":"$facebookSecret"}'); - String facebookClientSecretKeyName = createFacebookSecretResult['name'] as String; - await enableProvider(app, 'oauth2-facebook', config: '''{ - "clientId": "1265617494254819" - }''', secretConfig: '''{ - "clientSecret": "$facebookClientSecretKeyName" - }''', metadataFelds: '''{ - "required": true, - "name": "name" - }, - { - "required": true, - "name": "first_name" - }, - { - "required": true, - "name": "last_name" - }, - { - "required": false, - "name": "email" - }, - { - "required": false, - "name": "gender" - }, - { - "required": false, - "name": "birthday" - }, - { - "required": false, - "name": "min_age" - }, - { - "required": false, - "name": "max_age" - }, - { - "required": false, - "name": "picture" - }'''); - } - - print('Creating database db_$uniqueName'); - - final mongoServiceId = await _createMongoDBService( - app, - syncConfig: '''{ - "flexible_sync": { - "state": "enabled", - "database_name": "db_$uniqueName", - "queryable_fields_names": ["differentiator", "stringQueryField", "boolQueryField", "intQueryField"] - } - }''', - rules: '''{ - "roles": [ - { - "name": "all", - "apply_when": {}, - "document_filters": { - "read": true, - "write": true - }, - "read": true, - "write": true, - "insert": true, - "delete": true, - "search": true - } - ] - }''', - ); - - if (appName == AppName.staticSchema) { - final schemaId = await _createSchema(app, mongoServiceId, _nullablesSchemaV0); - await _updateSchema(app, schemaId, _nullablesSchemaV1); - - // Revert to schema_v0 - await _updateSchema(app, schemaId, _nullablesSchemaV0); - - await _waitForSchemaVersion(app, 2); - } else { - await _put('groups/$_groupId/apps/$app/sync/config', '{ "development_mode_enabled": true }'); - } - - //create email/password user for tests - final dynamic createUserResult = await _post('groups/$_groupId/apps/$app/users', '{"email": "realm-test@realm.io", "password":"123456"}'); - print("Create user result: $createUserResult"); - } catch (error) { - print(error); - app ??= BaasApp._empty(appName.name); - app.error = error; - } - return app; - } - - Future enableProvider(BaasApp app, String type, {String config = '{}', String secretConfig = '{}', String metadataFelds = '{}'}) async { - print('Enabling provider $type for ${app.clientAppId}'); - - final url = 'groups/$_groupId/apps/$app/auth_providers'; - if (type == 'api-key') { - final providers = await _get(url) as List; - final apiKeyProviderId = providers.singleWhere((dynamic doc) => doc['type'] == 'api-key')['_id'] as String; - - await _put('$url/$apiKeyProviderId/enable', '{}'); - } else { - await _post(url, '''{ - "name": "$type", - "type": "$type", - "disabled": false, - "config": $config, - "secret_config": $secretConfig, - "metadata_fields": [$metadataFelds] - }'''); - } - } - - Future deleteApps() async { - var apps = await _getApps(); - for (final app in apps) { - print('Deleting app ${app.clientAppId}'); - - await _deleteApp(app.appId); - print("App with id='${app.appId}' is deleted."); - } - } - - Future createApiKey(String appId, String name, bool enabled) async { - final dynamic result = await _post('groups/$_groupId/apps/$appId/api_keys', '{ "name":"$name" }'); - if (!enabled) { - await _put('groups/$_groupId/apps/$appId/api_keys/${result['_id']}/disable', ''); - } - - return result['key'] as String; - } - - Future _authenticate(String provider, String credentials) async { - dynamic response = await _post('auth/providers/$provider/login', credentials); - - _headers['Authorization'] = "Bearer ${response['access_token']}"; - } - - Future _createFunction(BaasApp app, String name, String source, {bool runAsSystem = false}) async { - print('Creating function $name for ${app.clientAppId}...'); - - final dynamic response = await _post('groups/$_groupId/apps/$app/functions', '''{ - "name": "$name", - "source": ${jsonEncode(source)}, - "private": false, - "can_evaluate": {}, - "run_as_system": $runAsSystem - }'''); - - return response['_id'] as String; - } - - Future _updateFunction(BaasApp app, String name, String functionId, String source) async { - print('Updating function $name for ${app.clientAppId}...'); - - await _put('groups/$_groupId/apps/$app/functions/$functionId', '''{ - "name": "$name", - "source": ${jsonEncode(source)}, - "private": false, - "can_evaluate": {} - }'''); - } - - Future _createMongoDBService(BaasApp app, {required String syncConfig, required String rules}) async { - final serviceName = _clusterName == null ? 'mongodb' : 'mongodb-atlas'; - final mongoConfig = _clusterName == null ? '{ "uri": "mongodb://localhost:26000" }' : '{ "clusterName": "$_clusterName" }'; - final mongoServiceId = await _createService(app, _mongoServiceName, serviceName, mongoConfig); - - await _post('groups/$_groupId/apps/$app/services/$mongoServiceId/default_rule', rules); - - // The cluster linking must be separated from enabling sync because Atlas - // takes a few seconds to provision a user for BaaS, meaning enabling sync - // will fail if we attempt to do it with the same request. It's nondeterministic - // how long it'll take, so we must retry for a while. - var attempt = 0; - while (true) { - try { - await _patch('groups/$_groupId/apps/$app/services/$mongoServiceId/config', syncConfig); - break; - } catch (err) { - if (attempt++ < 24) { - print('Failed to update service after ${attempt * 5} seconds. Will keep retrying ...'); - - await Future.delayed(const Duration(seconds: 5)); - } else { - rethrow; - } - } - } - - return mongoServiceId; - } - - Future _createService(BaasApp app, String name, String type, String config) async { - print('Creating service $name for ${app.clientAppId}'); - - final dynamic response = await _post('groups/$_groupId/apps/$app/services', '''{ - "name": "$name", - "type": "$type", - "config": $config - }'''); - - return response['_id'] as String; - } - - Future _createSchema(BaasApp app, String mongoServiceId, JsonSchemaDefinition schemaDefinition) async { - print('Creating schema ${schemaDefinition.collectionName} for ${app.clientAppId}...'); - - final schema = _getSchemaJson(schemaDefinition); - - final response = await _post('groups/$_groupId/apps/$app/schemas', schema); - - return response["_id"] as String; - } - - Future _updateSchema(BaasApp app, String schemaId, JsonSchemaDefinition schemaDefinition) async { - print('Updating schema ${schemaDefinition.collectionName} for ${app.clientAppId}...'); - - final schema = _getSchemaJson(schemaDefinition); - - await _put('groups/$_groupId/apps/$app/schemas/$schemaId?bypass_service_change=SyncSchemaVersionIncrease', schema); - } - - Future _waitForSchemaVersion(BaasApp app, int expectedVersion) async { - while (true) { - final response = await _get('groups/$_groupId/apps/$app/sync/schemas/versions'); - final versions = response["versions"] as List; - - for (final version in versions) { - if (version['version_major'] as int >= expectedVersion) { - return; - } - } - } - } - - String _getSchemaJson(JsonSchemaDefinition schemaDefinition) { - final requiredProps = schemaDefinition.properties.where((p) => p.required).map((p) => '"${p.name}"').join(', '); - final props = {for (var p in schemaDefinition.properties) p.name: p}; - return '''{ - "metadata": { - "database": "Schema_$_appSuffix", - "collection": "${schemaDefinition.collectionName}", - "data_source": "$_mongoServiceName" - }, - "schema": { - "title": "${schemaDefinition.collectionName}", - "bsonType": "object", - "properties": ${jsonEncode(props)}, - "required": [ $requiredProps ] - } - }'''; - } - - Future _deleteApp(String appId) async { - await _delete('groups/$_groupId/apps/$appId'); - } - - Map _getHeaders([Map? additionalHeaders]) { - if (additionalHeaders == null) { - return _headers; - } - - additionalHeaders.addAll(_headers); - return additionalHeaders; - } - - Uri _getUri(String relativePath) { - return Uri.parse('$_adminApiUrl/$relativePath'); - } - - Future _post(String relativePath, String payload) async { - var response = await http.post(_getUri(relativePath), headers: _getHeaders({'Content-Type': 'application/json'}), body: payload); - return _decodeResponse(response, payload); - } - - Future _get(String relativePath) async { - var response = await http.get(_getUri(relativePath), headers: _getHeaders()); - return _decodeResponse(response); - } - - Future _put(String relativePath, String payload) async { - var response = await http.put(_getUri(relativePath), headers: _getHeaders({'Content-Type': 'application/json'}), body: payload); - return _decodeResponse(response, payload); - } - - Future _patch(String relativePath, String payload) async { - var response = await http.patch(_getUri(relativePath), headers: _getHeaders({'Content-Type': 'application/json'}), body: payload); - return _decodeResponse(response, payload); - } - - Future _delete(String relativePath, {String? payload}) async { - var response = await http.delete(_getUri(relativePath), headers: _getHeaders({'Content-Type': 'application/json'}), body: payload); - return _decodeResponse(response, payload); - } - - static dynamic _decodeResponse(http.Response response, [String? payload]) { - if (response.statusCode > 399 || response.statusCode < 200) { - throw Exception('Failed to ${response.request?.method} ${response.request?.url}: ${response.statusCode} ${response.body}. Body: $payload'); - } - - if (response.body.isEmpty) { - return {}; - } - return jsonDecode(response.body); - } - - static String shortenDifferentiator(String input) { - if (input.length < 8) { - return input; - } - //Take first 4 and last 4 symbols - final result = input.replaceRange(4, input.length - 4, ''); - return result; - } - - Future setAutomaticRecoveryEnabled(String name, bool enable) async { - final uniqueName = "$name$_appSuffix"; - final dynamic docs = await _get('groups/$_groupId/apps'); - dynamic doc = docs.firstWhere((dynamic d) { - return d["name"] == uniqueName; - }, orElse: () => throw Exception("BAAS app not found")); - final app = BaasApp( - appId: doc['_id'] as String, clientAppId: doc['client_app_id'] as String, name: name, uniqueName: doc['name'] as String, isNewDeployment: false); - - final dynamic services = await _get('groups/$_groupId/apps/$app/services'); - dynamic service = services.firstWhere((dynamic s) => s["name"] == _mongoServiceName, orElse: () => throw Exception("Func 'confirmFunc' not found")); - final mongoServiceId = service['_id'] as String; - final dynamic configDocs = await _get('groups/$_groupId/apps/$app/services/$mongoServiceId/config'); - final dynamic flexibleSync = configDocs['flexible_sync']; - final dynamic clusterName = configDocs['clusterName']; - flexibleSync["is_recovery_mode_disabled"] = !enable; - String data = jsonEncode({ - if (clusterName != null) 'clusterName': clusterName, - 'flexible_sync': flexibleSync, - }); - await _patch('groups/$_groupId/apps/$app/services/$mongoServiceId/config', data); - } -} - -class _ContainerInfo { - final String id; - bool get isRunning => lastStatus == 'RUNNING'; - final String httpUrl; - final String lastStatus; - final Map tags; - final String creatorId; - - _ContainerInfo._(this.id, this.httpUrl, this.lastStatus, this.tags, this.creatorId); - - static _ContainerInfo? fromJson(Map json) { - final httpUrl = json['httpUrl'] as String?; - if (httpUrl == null) { - return null; - } - - final id = json['id'] as String; - final lastStatus = json['lastStatus'] as String; - final tags = {for (var v in json['tags'] as List) v['key'] as String: v['value'] as String}; - final creatorId = json['creatorId'] as String; - - return _ContainerInfo._(id, httpUrl, lastStatus, tags, creatorId); - } -} - -class BaasApp { - final String appId; - final String clientAppId; - final String name; - final String uniqueName; - final bool isNewDeployment; - Object? error; - - BaasApp({required this.appId, required this.clientAppId, required this.name, required this.uniqueName, required this.isNewDeployment}); - - BaasApp._empty(this.name) - : appId = "", - clientAppId = "", - uniqueName = "", - isNewDeployment = false; - - @override - String toString() { - return appId; - } -} diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/deleteapps_command.dart b/packages/realm_dart/lib/src/cli/atlas_apps/deleteapps_command.dart deleted file mode 100644 index 9f7ad8974..000000000 --- a/packages/realm_dart/lib/src/cli/atlas_apps/deleteapps_command.dart +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'options.dart'; -import 'baas_client.dart'; - -class DeleteAppsCommand extends Command { - @override - final String description = 'Delete test applications from MongoDB Atlas.'; - - @override - final String name = 'delete-apps'; - - @override - bool get hidden => true; - - late Options options; - - DeleteAppsCommand() { - populateOptionsParser(argParser); - } - - @override - FutureOr? run() async { - options = parseOptionsResult(argResults!); - - if (options.atlasCluster != null) { - if (options.apiKey == null) { - abort('--api-key must be supplied when --atlas-cluster is not set'); - } - - if (options.privateApiKey == null) { - abort('--private-api-key must be supplied when --atlas-cluster is not set'); - } - - if (options.projectId == null) { - abort('--project-id must be supplied when --atlas-cluster is not set'); - } - } - - if (options.baasaasApiKey == null && options.baasUrl == null) { - abort('--baas-url must be supplied when --baasaas-api-key is null'); - } - - final differentiator = options.differentiator ?? 'local'; - - if (options.baasaasApiKey != null) { - await BaasClient.retry(() => BaasClient.deleteContainer(options.baasaasApiKey!, differentiator)); - } else { - final client = await (options.atlasCluster == null - ? BaasClient.docker(options.baasUrl!, differentiator) - : BaasClient.atlas(options.baasUrl!, options.atlasCluster!, options.apiKey!, options.privateApiKey!, options.projectId!, differentiator)); - - await client.deleteApps(); - } - } - - void abort(String error) { - print(error); - print(usage); - exit(64); //usage error - } -} diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/deployapps_command.dart b/packages/realm_dart/lib/src/cli/atlas_apps/deployapps_command.dart deleted file mode 100644 index 8948c3945..000000000 --- a/packages/realm_dart/lib/src/cli/atlas_apps/deployapps_command.dart +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:io'; - -import 'package:args/command_runner.dart'; - -import 'options.dart'; -import 'baas_client.dart'; - -class DeployAppsCommand extends Command { - final String publicRSAKeyForJWTValidation = '''-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvNHHs8T0AHD7SJ+CKvVR -leeJa4wqYTnaVYV+5bX9FmFXVoN+vHbMLEteMvSw4L3kSRZdcqxY7cTuhlpAvkXP -Yq6qSI+bW8T4jGW963uCc83UhVMx4MH/PzipAlfcPjVO2u4c+dmpgZQpgEmA467u -tauXUhmTsGpgNg2Gvc61B7Ny4LphshsyrfaJ9WjA/NM6LOmEBW3JPNcVG2qyU+gt -O8BM8KOSx9wGyoGs4+OusvRkJizhPaIwa3FInLs4r+xZW9Bp6RndsmVECtvXRv5d -87ztpg6o3DZJRmTp2lAnkNLmxXlFkOSNIwiT3qqyRZOh4DuxPOpfg9K+vtFmRdEJ -RwIDAQAB ------END PUBLIC KEY-----'''; - - @override - final String description = 'Deploys test applications to MongoDB Atlas.'; - - @override - final String name = 'deploy-apps'; - - @override - bool get hidden => true; - - late Options options; - - DeployAppsCommand() { - populateOptionsParser(argParser); - } - - @override - FutureOr? run() async { - options = parseOptionsResult(argResults!); - - if (options.atlasCluster != null) { - if (options.apiKey == null) { - abort('--api-key must be supplied when --atlas-cluster is set'); - } - - if (options.privateApiKey == null) { - abort('--private-api-key must be supplied when --atlas-cluster is set'); - } - - if (options.projectId == null) { - abort('--project-id must be supplied when --atlas-cluster is set'); - } - - if (options.baasaasApiKey != null) { - abort('--baasaas-api-key cannot be used when --atlas-cluster is set'); - } - } - - if (options.baasaasApiKey == null && options.baasUrl == null) { - abort('--baas-url must be supplied when --baasaas-api-key is null'); - } - - final differentiator = options.differentiator ?? 'local'; - - late String baasUrl; - if (options.baasaasApiKey != null) { - late String containerId; - (baasUrl, containerId) = await BaasClient.getOrDeployContainer(options.baasaasApiKey!, differentiator); - await File('baasurl').writeAsString(baasUrl); - await File('containerid').writeAsString(containerId); - print('BaasUrl: $baasUrl'); - } else { - baasUrl = options.baasUrl!; - } - - try { - final client = await (options.atlasCluster == null - ? BaasClient.docker(baasUrl, differentiator) - : BaasClient.atlas(baasUrl, options.atlasCluster!, options.apiKey!, options.privateApiKey!, options.projectId!, differentiator)); - client.publicRSAKey = publicRSAKeyForJWTValidation; - var apps = await client.getOrCreateApps(); - print('App import is complete. There are: ${apps.length} apps on the server:'); - List listApps = []; - for (var value in apps) { - print(" App '${value.name}': '${value.clientAppId}'"); - if (value.error != null) { - print(value.error!); - } - listApps.add(value.appId); - } - print("appIds: "); - print(listApps.join(",")); - exit(0); - } catch (error) { - print(error); - } - } - - void abort(String error) { - print(error); - print(usage); - exit(64); //usage error - } -} diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/options.dart b/packages/realm_dart/lib/src/cli/atlas_apps/options.dart deleted file mode 100644 index 74019898c..000000000 --- a/packages/realm_dart/lib/src/cli/atlas_apps/options.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:build_cli_annotations/build_cli_annotations.dart'; - -part 'options.g.dart'; - -@CliOptions() -class Options { - @CliOption(help: 'Url for MongoDB Atlas.') - final String? baasUrl; - - @CliOption(help: 'The database prefix that will be used for the sync service.') - final String? differentiator; - - @CliOption(help: 'Atlas Cluster to link in the application.') - final String? atlasCluster; - - @CliOption(help: 'Atlas API key to use for the import. Only used if atlas-cluster is specified.') - final String? apiKey; - - @CliOption(help: 'The private Atlas API key to use for the import. Only used if atlas-cluster is specified.') - final String? privateApiKey; - - @CliOption(help: 'The Atlas project id to use for the import. Only used if atlas-cluster is specified.') - final String? projectId; - - @CliOption(help: 'API key to use with BaaSaaS to spawn a new container and create apps in it.', name: 'baasaas-api-key') - final String? baasaasApiKey; - - Options({this.baasUrl, this.atlasCluster, this.apiKey, this.privateApiKey, this.projectId, this.differentiator, this.baasaasApiKey}); -} - -String get usage => _$parserForOptions.usage; - -ArgParser populateOptionsParser(ArgParser p) => _$populateOptionsParser(p); - -Options parseOptionsResult(ArgResults results) => _$parseOptionsResult(results); diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/options.g.dart b/packages/realm_dart/lib/src/cli/atlas_apps/options.g.dart deleted file mode 100644 index a6cd50993..000000000 --- a/packages/realm_dart/lib/src/cli/atlas_apps/options.g.dart +++ /dev/null @@ -1,58 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'options.dart'; - -// ************************************************************************** -// CliGenerator -// ************************************************************************** - -Options _$parseOptionsResult(ArgResults result) => Options( - baasUrl: result['baas-url'] as String?, - atlasCluster: result['atlas-cluster'] as String?, - apiKey: result['api-key'] as String?, - privateApiKey: result['private-api-key'] as String?, - projectId: result['project-id'] as String?, - differentiator: result['differentiator'] as String?, - baasaasApiKey: result['baasaas-api-key'] as String?, - ); - -ArgParser _$populateOptionsParser(ArgParser parser) => parser - ..addOption( - 'baas-url', - help: 'Url for MongoDB Atlas.', - ) - ..addOption( - 'differentiator', - help: 'The database prefix that will be used for the sync service.', - ) - ..addOption( - 'atlas-cluster', - help: 'Atlas Cluster to link in the application.', - ) - ..addOption( - 'api-key', - help: - 'Atlas API key to use for the import. Only used if atlas-cluster is specified.', - ) - ..addOption( - 'private-api-key', - help: - 'The private Atlas API key to use for the import. Only used if atlas-cluster is specified.', - ) - ..addOption( - 'project-id', - help: - 'The Atlas project id to use for the import. Only used if atlas-cluster is specified.', - ) - ..addOption( - 'baasaas-api-key', - help: - 'API key to use with BaaSaaS to spawn a new container and create apps in it.', - ); - -final _$parserForOptions = _$populateOptionsParser(ArgParser()); - -Options parseOptions(List args) { - final result = _$parserForOptions.parse(args); - return _$parseOptionsResult(result); -} diff --git a/packages/realm_dart/lib/src/cli/main.dart b/packages/realm_dart/lib/src/cli/main.dart index 002ff3a19..ed7933ddb 100644 --- a/packages/realm_dart/lib/src/cli/main.dart +++ b/packages/realm_dart/lib/src/cli/main.dart @@ -7,21 +7,15 @@ import 'package:args/command_runner.dart'; import 'generate/generate_command.dart'; import 'install/install_command.dart'; -import 'metrics/metrics_command.dart'; import 'archive/archive_command.dart'; import 'extract/extract_command.dart'; -import 'atlas_apps/deployapps_command.dart'; -import 'atlas_apps/deleteapps_command.dart'; void main(List arguments) { CommandRunner("dart run realm|realm_dart", 'Realm commands for working with Realm Flutter & Dart SDKs.') - ..addCommand(MetricsCommand()) ..addCommand(GenerateCommand()) ..addCommand(InstallCommand()) ..addCommand(ArchiveCommand()) ..addCommand(ExtractCommand()) - ..addCommand(DeployAppsCommand()) - ..addCommand(DeleteAppsCommand()) ..run(arguments).catchError((Object error) { if (error is UsageException) { print(error); diff --git a/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart b/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart deleted file mode 100644 index 47c6b58b3..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2021 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:json_annotation/json_annotation.dart'; -import 'package:pub_semver/pub_semver.dart'; - -import '../common/utils.dart'; - -part 'flutter_info.g.dart'; - -class VersionConverter extends JsonConverter { - const VersionConverter(); - - @override - Version fromJson(String json) => Version.parse(json.takeUntil(' ')); - - @override - String toJson(Version object) => object.toString(); -} - -@JsonSerializable() -class FlutterInfo { - @VersionConverter() - final Version frameworkVersion; - final String? channel; - final String? repositoryUrl; - final String? frameworkRevision; - final String? frameworkCommitDate; - final String? engineRevision; - @VersionConverter() - final Version dartSdkVersion; - final String? flutterRoot; - - FlutterInfo( - {required this.frameworkVersion, - this.channel, - this.repositoryUrl, - this.frameworkRevision, - this.frameworkCommitDate, - this.engineRevision, - required this.dartSdkVersion, - this.flutterRoot}); - - factory FlutterInfo.fromJson(Map json) => _$FlutterInfoFromJson(json); -} diff --git a/packages/realm_dart/lib/src/cli/metrics/flutter_info.g.dart b/packages/realm_dart/lib/src/cli/metrics/flutter_info.g.dart deleted file mode 100644 index c737361bc..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/flutter_info.g.dart +++ /dev/null @@ -1,34 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'flutter_info.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -FlutterInfo _$FlutterInfoFromJson(Map json) => FlutterInfo( - frameworkVersion: - const VersionConverter().fromJson(json['frameworkVersion'] as String), - channel: json['channel'] as String?, - repositoryUrl: json['repositoryUrl'] as String?, - frameworkRevision: json['frameworkRevision'] as String?, - frameworkCommitDate: json['frameworkCommitDate'] as String?, - engineRevision: json['engineRevision'] as String?, - dartSdkVersion: - const VersionConverter().fromJson(json['dartSdkVersion'] as String), - flutterRoot: json['flutterRoot'] as String?, - ); - -Map _$FlutterInfoToJson(FlutterInfo instance) => - { - 'frameworkVersion': - const VersionConverter().toJson(instance.frameworkVersion), - 'channel': instance.channel, - 'repositoryUrl': instance.repositoryUrl, - 'frameworkRevision': instance.frameworkRevision, - 'frameworkCommitDate': instance.frameworkCommitDate, - 'engineRevision': instance.engineRevision, - 'dartSdkVersion': - const VersionConverter().toJson(instance.dartSdkVersion), - 'flutterRoot': instance.flutterRoot, - }; diff --git a/packages/realm_dart/lib/src/cli/metrics/metrics.dart b/packages/realm_dart/lib/src/cli/metrics/metrics.dart deleted file mode 100644 index a5a0465d2..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/metrics.dart +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2021 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:convert'; -import 'dart:io'; - -import 'package:crypto/crypto.dart'; -import 'package:json_annotation/json_annotation.dart'; - -import '../common/target_os_type.dart'; - -part 'metrics.g.dart'; - -Future generateMetrics({ - required Digest distinctId, - required Digest builderId, - required String framework, - required String frameworkVersion, - required String realmVersion, - TargetOsType? targetOsType, - String? targetOsVersion, - Digest? anonymizedMacAddress, - Digest? anonymizedBundleId, - String? realmCoreVersion, -}) async { - return Metrics( - event: 'run', - properties: Properties( - distinctId: distinctId, - builderId: builderId, - token: 'ce0fac19508f6c8f20066d345d360fd0', - binding: 'dart', - language: 'dart', - framework: framework, - frameworkVersion: frameworkVersion, - hostOsType: Platform.operatingSystem, - hostOsVersion: Platform.operatingSystemVersion, - realmVersion: realmVersion, - targetOsType: targetOsType, - targetOsVersion: targetOsVersion, - anonymizedMacAddress: anonymizedMacAddress ?? distinctId, // fallback - anonymizedBundleId: anonymizedBundleId, - ), - ); -} - -Digest _digestFromJson(String json) => Digest(base64Decode(json)); -String _digestToJson(Digest object) => base64Encode(object.bytes); - -class DigestConverter extends JsonConverter { - const DigestConverter(); - - @override - Digest? fromJson(String? json) => json != null ? _digestFromJson(json) : null; - - @override - String? toJson(Digest? object) => object != null ? _digestToJson(object) : null; -} - -@JsonSerializable() -class Metrics { - final String event; - final Properties properties; - - Metrics({required this.event, required this.properties}); - - factory Metrics.fromJson(Map json) => _$MetricsFromJson(json); - Map toJson() => _$MetricsToJson(this); -} - -@JsonSerializable( - fieldRename: FieldRename.pascal, // ex: hostOSType becomes HostOSType - includeIfNull: false, -) -class Properties { - @JsonKey(name: 'token') // not PascalCase - final String token; - - @JsonKey( - name: 'distinct_id', // snake-case - fromJson: _digestFromJson, // While we wait for: https://github.com/google/json_serializable.dart/issues/822 - toJson: _digestToJson, - ) - final Digest distinctId; - - @JsonKey( - name: 'builder_id', // snake-case - fromJson: _digestFromJson, // While we wait for: https://github.com/google/json_serializable.dart/issues/822 - toJson: _digestToJson, - ) - final Digest builderId; - - @JsonKey(name: 'Anonymized MAC Address') - @DigestConverter() - final Digest? anonymizedMacAddress; - - @JsonKey(name: 'Anonymized Bundle ID') - @DigestConverter() - final Digest? anonymizedBundleId; - - final String binding; - final String language; - final String framework; - - @JsonKey(name: 'Framework Version') - final String frameworkVersion; - - @JsonKey(name: 'Sync Enabled') - final String? syncEnabled; - - @JsonKey(name: 'Realm Version') - final String realmVersion; - - @JsonKey(name: 'Host OS Type') - final String hostOsType; - - @JsonKey(name: 'Host OS Version') - final String hostOsVersion; - - @JsonKey(name: 'Target OS Type') - final TargetOsType? targetOsType; - - @JsonKey(name: 'Target OS Version') - final String? targetOsVersion; - - @JsonKey(name: 'Core Version') - final String? realmCoreVersion; - - Properties({ - required this.distinctId, - required this.builderId, - required this.token, - required this.binding, - required this.framework, - required this.frameworkVersion, - required this.hostOsType, - required this.hostOsVersion, - required this.language, - required this.realmVersion, - this.anonymizedBundleId, - this.anonymizedMacAddress, - this.syncEnabled, - this.targetOsType, - this.targetOsVersion, - this.realmCoreVersion, - }); - - factory Properties.fromJson(Map json) => _$PropertiesFromJson(json); - Map toJson() => _$PropertiesToJson(this); -} diff --git a/packages/realm_dart/lib/src/cli/metrics/metrics.g.dart b/packages/realm_dart/lib/src/cli/metrics/metrics.g.dart deleted file mode 100644 index f479ed0ce..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/metrics.g.dart +++ /dev/null @@ -1,79 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'metrics.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -Metrics _$MetricsFromJson(Map json) => Metrics( - event: json['event'] as String, - properties: - Properties.fromJson(json['properties'] as Map), - ); - -Map _$MetricsToJson(Metrics instance) => { - 'event': instance.event, - 'properties': instance.properties, - }; - -Properties _$PropertiesFromJson(Map json) => Properties( - distinctId: _digestFromJson(json['distinct_id'] as String), - builderId: _digestFromJson(json['builder_id'] as String), - token: json['token'] as String, - binding: json['Binding'] as String, - framework: json['Framework'] as String, - frameworkVersion: json['Framework Version'] as String, - hostOsType: json['Host OS Type'] as String, - hostOsVersion: json['Host OS Version'] as String, - language: json['Language'] as String, - realmVersion: json['Realm Version'] as String, - anonymizedBundleId: const DigestConverter() - .fromJson(json['Anonymized Bundle ID'] as String?), - anonymizedMacAddress: const DigestConverter() - .fromJson(json['Anonymized MAC Address'] as String?), - syncEnabled: json['Sync Enabled'] as String?, - targetOsType: - $enumDecodeNullable(_$TargetOsTypeEnumMap, json['Target OS Type']), - targetOsVersion: json['Target OS Version'] as String?, - realmCoreVersion: json['Core Version'] as String?, - ); - -Map _$PropertiesToJson(Properties instance) { - final val = { - 'token': instance.token, - 'distinct_id': _digestToJson(instance.distinctId), - 'builder_id': _digestToJson(instance.builderId), - }; - - void writeNotNull(String key, dynamic value) { - if (value != null) { - val[key] = value; - } - } - - writeNotNull('Anonymized MAC Address', - const DigestConverter().toJson(instance.anonymizedMacAddress)); - writeNotNull('Anonymized Bundle ID', - const DigestConverter().toJson(instance.anonymizedBundleId)); - val['Binding'] = instance.binding; - val['Language'] = instance.language; - val['Framework'] = instance.framework; - val['Framework Version'] = instance.frameworkVersion; - writeNotNull('Sync Enabled', instance.syncEnabled); - val['Realm Version'] = instance.realmVersion; - val['Host OS Type'] = instance.hostOsType; - val['Host OS Version'] = instance.hostOsVersion; - writeNotNull('Target OS Type', _$TargetOsTypeEnumMap[instance.targetOsType]); - writeNotNull('Target OS Version', instance.targetOsVersion); - writeNotNull('Core Version', instance.realmCoreVersion); - return val; -} - -const _$TargetOsTypeEnumMap = { - TargetOsType.android: 'android', - TargetOsType.ios: 'ios', - TargetOsType.linux: 'linux', - TargetOsType.macos: 'macos', - TargetOsType.windows: 'windows', -}; diff --git a/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart b/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart deleted file mode 100644 index ca133f01f..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2021 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:args/command_runner.dart'; -import 'package:crypto/crypto.dart'; -import 'package:logging/logging.dart'; -import 'package:path/path.dart' as path; -import 'package:pub_semver/pub_semver.dart'; -import 'package:pubspec_parse/pubspec_parse.dart'; - -import 'flutter_info.dart'; -import 'metrics.dart'; -import 'options.dart'; -import '../common/utils.dart'; - -// stamped into the library by the build system (see prepare-release.yml) -const realmCoreVersion = '14.11.0'; - -class MetricsCommand extends Command { - @override - final String description = 'Report anonymized builder metrics to Realm'; - - @override - final String name = 'metrics'; - - MetricsCommand() { - populateOptionsParser(argParser); - } - - @override - FutureOr? run() async { - await safe(() async { - final options = parseOptionsResult(argResults!); - await uploadMetrics(options); - }); - } -} - -Future uploadMetrics(Options options) async { - final pubspecPath = options.pubspecPath; - final pubspecFile = File(pubspecPath); - - if (!pubspecFile.existsSync()) { - // Curently the pubspec file is a hard requirement for metrics to work. Skip metrics run if the file does not exists at the expected location. - // TODO: remove the pubspec file hard requirement and allow metrics to run with the neededdata gathered by other means. - // https://jira.mongodb.org/browse/RDART-815 - return; - } - - final pubspec = Pubspec.parse(await pubspecFile.readAsString()); - - hierarchicalLoggingEnabled = true; - log.level = options.verbose ? Level.INFO : Level.WARNING; - - var skipUpload = (isRealmCI || - Platform.environment['CI'] != null || - Platform.environment['REALM_DISABLE_ANALYTICS'] != null || - Directory.current.absolute.path.contains("realm-dart")) && - Platform.environment['REALM_DEBUG_ANALYTICS'] == null; - if (skipUpload) { - // skip early and don't do any work - log.info('Skipping metrics upload.'); - return; - } - - FlutterInfo? flutterInfo; - try { - flutterInfo = await getInfo(options); - } catch (e) { - flutterInfo = null; - } - - final distinctId = await generateDistinctId(); - - final builderId = await generateBuilderId(); - - var frameworkName = flutterInfo != null ? 'Flutter' : null; - - Dependency? realmDep; - if (pubspec.dependencies.containsKey('realm')) { - realmDep = pubspec.dependencies["realm"]; - frameworkName = frameworkName ?? "Flutter"; - } else if (pubspec.dependencies.containsKey('realm_dart')) { - realmDep = pubspec.dependencies["realm_dart"]; - frameworkName = frameworkName ?? "Dart"; - } - - final realmVersion = realmDep is HostedDependency ? '${realmDep.version}' : '?'; - - final metrics = await generateMetrics( - distinctId: distinctId, - builderId: builderId, - targetOsType: options.targetOsType, - targetOsVersion: options.targetOsVersion, - anonymizedMacAddress: distinctId, - anonymizedBundleId: pubspec.name.strongHash(), - framework: frameworkName ?? "Unknown", - frameworkVersion: flutterInfo != null - ? [ - '${flutterInfo.frameworkVersion}', - if (flutterInfo.channel != null) '(${flutterInfo.channel})', // to mimic Platform.version - if (flutterInfo.frameworkCommitDate != null) '(${flutterInfo.frameworkCommitDate})', // -"- - ].join(' ') - : Platform.version, - realmVersion: realmVersion, - realmCoreVersion: realmCoreVersion); - - const encoder = JsonEncoder.withIndent(' '); - final payload = encoder.convert(metrics.toJson()); - log.info('Uploading metrics for ${pubspec.name}...\n$payload'); - final base64Payload = base64Encode(utf8.encode(payload)); - - if (Platform.environment['REALM_DEBUG_ANALYTICS'] != null) { - skipUpload = true; - } - - if (skipUpload) { - // skip late - log.info('Skipping metrics upload.'); - return; - } - - final client = HttpClient(); - try { - final request = await client.getUrl( - Uri.parse( - 'https://data.mongodb-api.com' - '/app/realmsdkmetrics-zmhtm/endpoint/metric_webhook/metric' - '?data=$base64Payload', - ), - ); - await request.close(); - } finally { - client.close(force: true); - } -} - -Future getMachineId() async { - var id = await safe(() async { - if (Platform.isLinux) { - // For linux use /etc/machine-id - // Can be changed by administrator but with unpredictable consequences! - // (see https://man7.org/linux/man-pages/man5/machine-id.5.html) - final process = await Process.start('cat', ['/etc/machine-id']); - return await process.stdout.transform(utf8.decoder).join(); - } else if (Platform.isMacOS) { - // For MacOS, use the IOPlatformUUID value from I/O Kit registry in - // IOPlatformExpertDevice class - final process = await Process.start('ioreg', [ - '-rd1', - '-c', - 'IOPlatformExpertDevice', - ]); - final id = await process.stdout.transform(utf8.decoder).join(); - return id; - } else if (Platform.isWindows) { - // For Windows, use the key MachineGuid in registry: - // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography - // Can be changed by administrator but with unpredictable consequences! - // - // It is generated during OS installation and won't change unless you make - // another OS update or re-install. Depending on the OS version it may - // contain the network adapter MAC address embedded (plus some other numbers, - // including random), or a pseudorandom number. - // - // Consider using System.Identity.UniqueID instead. - // (see https://docs.microsoft.com/en-gb/windows/win32/properties/props-system-identity-uniqueid) - final process = await Process.start( - '${Platform.environment['WINDIR']}\\System32\\Reg.exe', - [ - 'QUERY', - r'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography', - '/v', - 'MachineGuid', - ], - ); - return await process.stdout.transform(systemEncoding.decoder).join(); - } - }, message: 'failed to get machine id'); - id ??= Platform.localHostname; // fallback - return id; -} - -const macOSMachineIdRegEx = r'.*\"IOPlatformUUID\"\s=\s\"(.+)\"'; - -Future generateDistinctId() async { - var id = await safe(() async { - final machineId = await getMachineId(); - if (Platform.isLinux) { - return machineId; - } else if (Platform.isMacOS) { - final regex = RegExp(macOSMachineIdRegEx, dotAll: true); - return regex.firstMatch(machineId)?.group(1); // extract IOPlatformUUID - } else if (Platform.isWindows) { - return machineId; - } - }, message: 'failed to get machine id'); - - id ??= Platform.localHostname; // fallback - return id.strongHash(); // strong hash for privacy -} - -Future generateBuilderId() async { - var id = await safe(() async { - final machineId = await getMachineId(); - if (Platform.isLinux) { - return machineId; - } else if (Platform.isMacOS) { - final regex = RegExp(macOSMachineIdRegEx, dotAll: true); - return regex.firstMatch(machineId)?.group(1); // extract IOPlatformUUID - } else if (Platform.isWindows) { - final regex = RegExp(r'\s*MachineGuid\s*\w*\s*([A-Za-z0-9-]+)', dotAll: true); - return regex.firstMatch(machineId)?.group(1); // extract MachineGuid - } - }, message: 'failed to get machine id'); - - id ??= Platform.localHostname; // fallback - - const builderIdSalt = [82, 101, 97, 108, 109, 32, 105, 115, 32, 103, 114, 101, 97, 116]; - return id.strongHash(builderIdSalt); // strong hash for privacy -} - -extension _StringEx on String { - static const _defaultSalt = [75, 97, 115, 112, 101, 114, 32, 119, 97, 115, 32, 104, 101, 114]; - Digest strongHash([List salt = _defaultSalt]) => sha256.convert([...salt, ...utf8.encode(this)]); -} - -Future getInfo(Options options) async { - final pubspecPath = options.pubspecPath; - final pubspec = Pubspec.parse(await File(pubspecPath).readAsString()); - - const flutter = 'flutter'; - final flutterDep = pubspec.dependencies.values.whereType().where((dep) => dep.sdk == flutter).firstOrNull; - if (flutterDep == null) { - return null; // no flutter dependency, so not a flutter project - } - - // Read constraints, if any - var flutterVersionConstraints = flutterDep.version.intersect(pubspec.environment?[flutter] ?? VersionConstraint.any); - - // Try to read actual version from version file in .dart_tools. - // This is updated when calling a flutter command on the project, - // but not when calling a dart command.. - final version = await safe(() async { - return Version.parse(await File(path.join(path.dirname(pubspecPath), '.dart_tool/version')).readAsString()); - }); - - // Try to get full info by calling flutter executable - final info = await safe(() async { - final flutterRoot = options.flutterRoot; - final flutterExecutableName = Platform.isWindows ? "flutter.bat" : "flutter"; - final flutterPath = - flutterRoot == null ? flutterExecutableName : path.join(flutterRoot, path.basename(flutterRoot) != "bin" ? 'bin' : "", flutterExecutableName); - final process = await Process.start(flutterPath, ['--version', '--machine']); - final infoJson = await process.stdout.transform(utf8.decoder).join(); - return FlutterInfo.fromJson(json.decode(infoJson) as Map); - }); - - // Sanity check full info, if we have it - if (info != null && (version == null || version == info.frameworkVersion) && flutterVersionConstraints.allows(info.frameworkVersion)) { - // The returned info match both the projects constraints and the - // flutter version of the latest flutter command run on the project - return info; - } - - // Fallback to simplified info build from the version read from .dart_tool/version, - // secondly the min constraint of the flutter SDK used - return FlutterInfo( - frameworkVersion: version ?? (await safe(() => (flutterVersionConstraints as VersionRange).min!)) ?? Version.none, - dartSdkVersion: Version.parse(Platform.version.takeUntil(' ')), - ); -} diff --git a/packages/realm_dart/lib/src/cli/metrics/options.dart b/packages/realm_dart/lib/src/cli/metrics/options.dart deleted file mode 100644 index 99a9a0577..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/options.dart +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright 2021 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:build_cli_annotations/build_cli_annotations.dart'; -import 'package:path/path.dart' as path; -import '../common/target_os_type.dart'; - -part 'options.g.dart'; - -@CliOptions() -class Options { - @CliOption(help: "The OS type this project is targeting.") - final TargetOsType? targetOsType; - @CliOption(help: "The OS version this project is targeting.") - final String? targetOsVersion; - @CliOption(help: "The path to the Flutter SDK (excluding the bin directory).") - final String? flutterRoot; - @CliOption(help: "The path to the application pubspec") - final String pubspecPath; - - @CliOption(abbr: 'v', help: 'Show additional command output.') - bool verbose = false; - - Options({this.targetOsType, this.targetOsVersion, this.flutterRoot, String? pubspecPath}) - : pubspecPath = path.join(path.current, pubspecPath ?? 'pubspec.yaml'); -} - -String get usage => _$parserForOptions.usage; - -ArgParser populateOptionsParser(ArgParser p) => _$populateOptionsParser(p); - -Options parseOptionsResult(ArgResults results) => _$parseOptionsResult(results); diff --git a/packages/realm_dart/lib/src/cli/metrics/options.g.dart b/packages/realm_dart/lib/src/cli/metrics/options.g.dart deleted file mode 100644 index 9559e0438..000000000 --- a/packages/realm_dart/lib/src/cli/metrics/options.g.dart +++ /dev/null @@ -1,73 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'options.dart'; - -// ************************************************************************** -// CliGenerator -// ************************************************************************** - -T _$enumValueHelper(Map enumValues, String source) => - enumValues.entries - .singleWhere( - (e) => e.value == source, - orElse: () => throw ArgumentError( - '`$source` is not one of the supported values: ' - '${enumValues.values.join(', ')}', - ), - ) - .key; - -T? _$nullableEnumValueHelperNullable( - Map enumValues, - String? source, -) => - source == null ? null : _$enumValueHelper(enumValues, source); - -Options _$parseOptionsResult(ArgResults result) => Options( - targetOsType: _$nullableEnumValueHelperNullable( - _$TargetOsTypeEnumMapBuildCli, - result['target-os-type'] as String?, - ), - targetOsVersion: result['target-os-version'] as String?, - flutterRoot: result['flutter-root'] as String?, - pubspecPath: result['pubspec-path'] as String?, - )..verbose = result['verbose'] as bool; - -const _$TargetOsTypeEnumMapBuildCli = { - TargetOsType.android: 'android', - TargetOsType.ios: 'ios', - TargetOsType.linux: 'linux', - TargetOsType.macos: 'macos', - TargetOsType.windows: 'windows' -}; - -ArgParser _$populateOptionsParser(ArgParser parser) => parser - ..addOption( - 'target-os-type', - help: 'The OS type this project is targeting.', - allowed: ['android', 'ios', 'linux', 'macos', 'windows'], - ) - ..addOption( - 'target-os-version', - help: 'The OS version this project is targeting.', - ) - ..addOption( - 'flutter-root', - help: 'The path to the Flutter SDK (excluding the bin directory).', - ) - ..addOption( - 'pubspec-path', - help: 'The path to the application pubspec', - ) - ..addFlag( - 'verbose', - abbr: 'v', - help: 'Show additional command output.', - ); - -final _$parserForOptions = _$populateOptionsParser(ArgParser()); - -Options parseOptions(List args) { - final result = _$parserForOptions.parse(args); - return _$parseOptionsResult(result); -} diff --git a/packages/realm_dart/lib/src/configuration.dart b/packages/realm_dart/lib/src/configuration.dart index 95cd4fa5d..381536674 100644 --- a/packages/realm_dart/lib/src/configuration.dart +++ b/packages/realm_dart/lib/src/configuration.dart @@ -1,17 +1,12 @@ // Copyright 2021 MongoDB, Inc. // SPDX-License-Identifier: Apache-2.0 -import 'dart:async'; - // ignore: no_leading_underscores_for_library_prefixes import 'package:collection/collection.dart'; import 'package:path/path.dart' as _path; -import 'app.dart'; import 'handles/realm_core.dart'; -import 'logging.dart'; import 'realm_dart.dart'; -import 'user.dart'; const encryptionKeySize = 64; @@ -42,28 +37,6 @@ typedef InitialDataCallback = void Function(Realm realm); /// The `oldSchemaVersion` argument indicates the version from which the `Realm` migrates while typedef MigrationCallback = void Function(Migration migration, int oldSchemaVersion); -/// The signature of a callback that will be triggered when a Client Reset error happens in a synchronized `Realm`. -/// -/// The [clientResetError] holds useful data to be used when trying to manually recover from a client reset. -typedef ClientResetCallback = FutureOr Function(ClientResetError clientResetError); - -/// Callback that indicates a Client Reset is about to happen. -/// -/// The [beforeResetRealm] holds the frozen `Realm` just before the client reset happens. -/// -/// The lifetime of [beforeResetRealm] is tied to the callback lifetime, so don't store references to the `Realm` or objects -/// obtained from it for use outside of the callback. -typedef BeforeResetCallback = FutureOr Function(Realm beforeResetRealm); - -/// Callback that indicates a Client Reset has just happened. -/// -/// The [beforeResetRealm] holds the frozen `Realm` just before the client reset happened. -/// The [afterResetRealm] holds the live `Realm` just after the client reset happened. -/// -/// The lifetime of the `Realm` instances supplied is tied to the callback, so don't store references to -/// the `Realm` or objects obtained from it for use outside of the callback. -typedef AfterResetCallback = FutureOr Function(Realm beforeResetRealm, Realm afterResetRealm); - /// Configuration used to create a `Realm` instance /// {@category Configuration} abstract class Configuration { @@ -176,50 +149,6 @@ abstract class Configuration { maxNumberOfActiveVersions: maxNumberOfActiveVersions, ); - /// Constructs a [FlexibleSyncConfiguration] - static FlexibleSyncConfiguration flexibleSync( - User user, - List schemaObjects, { - String? fifoFilesFallbackPath, - String? path, - List? encryptionKey, - SyncErrorHandler syncErrorHandler = defaultSyncErrorHandler, - ClientResetHandler clientResetHandler = const RecoverOrDiscardUnsyncedChangesHandler(onManualResetFallback: _defaultClientResetHandler), - int? maxNumberOfActiveVersions, - ShouldCompactCallback? shouldCompactCallback, - int schemaVersion = 0, - bool cancelAsyncOperationsOnNonFatalErrors = false, - }) => - FlexibleSyncConfiguration._( - user, - schemaObjects, - fifoFilesFallbackPath: fifoFilesFallbackPath, - path: path, - encryptionKey: encryptionKey, - syncErrorHandler: syncErrorHandler, - clientResetHandler: clientResetHandler, - maxNumberOfActiveVersions: maxNumberOfActiveVersions, - shouldCompactCallback: shouldCompactCallback, - schemaVersion: schemaVersion, - cancelAsyncOperationsOnNonFatalErrors: cancelAsyncOperationsOnNonFatalErrors, - ); - - /// Constructs a [DisconnectedSyncConfiguration] - static DisconnectedSyncConfiguration disconnectedSync( - List schemaObjects, { - required String path, - String? fifoFilesFallbackPath, - List? encryptionKey, - int? maxNumberOfActiveVersions, - }) => - DisconnectedSyncConfiguration._( - schemaObjects, - path: path, - fifoFilesFallbackPath: fifoFilesFallbackPath, - encryptionKey: encryptionKey, - maxNumberOfActiveVersions: maxNumberOfActiveVersions, - ); - void _validateEncryptionKey(List? key) { if (key == null) { return; @@ -294,115 +223,6 @@ class LocalConfiguration extends Configuration { final bool shouldDeleteIfMigrationNeeded; } -/// @nodoc -enum SessionStopPolicy { - immediately, // Immediately stop the session as soon as all Realms/Sessions go out of scope. - liveIndefinitely, // Never stop the session. - afterChangesUploaded, // Once all Realms/Sessions go out of scope, wait for uploads to complete and stop. -} - -/// The signature of a callback that will be invoked whenever a [SyncError] occurs for the synchronized realm. -/// -/// Client reset errors will not be reported through this callback as they are handled by [ClientResetHandler]. -typedef SyncErrorHandler = void Function(SyncError); - -void defaultSyncErrorHandler(SyncError e) { - Realm.logger.log(LogLevel.error, e); -} - -void _defaultClientResetHandler(ClientResetError e) { - Realm.logger.log( - LogLevel.error, - "A client reset error occurred but no handler was supplied. " - "Synchronization is now paused and will resume automatically once the app is restarted and " - "the server data is re-downloaded. Any un-synchronized changes the client has made or will " - "make will be lost. To handle that scenario, pass in a non-null value to " - "clientResetHandler when constructing Configuration.flexibleSync."); -} - -/// [FlexibleSyncConfiguration] is used to open [Realm] instances that are synchronized -/// with MongoDB Atlas. -/// {@category Configuration} -class FlexibleSyncConfiguration extends Configuration { - /// The [User] used to created this [FlexibleSyncConfiguration] - final User user; - - SessionStopPolicy _sessionStopPolicy = SessionStopPolicy.afterChangesUploaded; - - /// Called when a [SyncError] occurs for this synchronized `Realm`. - /// - /// The default [SyncErrorHandler] prints to the console. - final SyncErrorHandler syncErrorHandler; - - /// Called when a [ClientResetError] occurs for this synchronized `Realm`. - /// - /// The default [ClientResetHandler] logs a message using the current [Realm.logger]. - final ClientResetHandler clientResetHandler; - - /// Called when opening a `Realm` for the first time, after process start. - final ShouldCompactCallback? shouldCompactCallback; - - /// The schema version for this Realm. This has to be a valid schema version on the server - /// and the schema supplied in [schemaObjects] should match the one on the server. - /// - /// Note that unlike with [LocalConfiguration], changing the schema version will not execute - /// any migrations locally as the data is migrated on the server. - /// - /// When changing the schema version, the Realm **must** be opened asynchronously - i.e. - /// using [Realm.open] as migrating the data will require that first all the local changes - /// are uploaded, and then, that a client reset is performed. When changing the schema version - /// all subscriptions will be reset since they may not conform to the new schema. - final int schemaVersion; - - /// Controls whether async operations such as [Realm.open], [Session.waitForUpload], and [Session.waitForDownload] - /// should throw an error whenever a non-fatal error, such as timeout occurs. - /// - /// If set to `false`, non-fatal session errors will be ignored and sync will continue retrying the - /// connection under in the background. This means that in cases where the devie is offline, these operations - /// may take an indeterminate time to complete. - final bool cancelAsyncOperationsOnNonFatalErrors; - - FlexibleSyncConfiguration._( - this.user, - super.schemaObjects, { - super.fifoFilesFallbackPath, - super.path, - super.encryptionKey, - this.syncErrorHandler = defaultSyncErrorHandler, - this.clientResetHandler = const RecoverOrDiscardUnsyncedChangesHandler(onManualResetFallback: _defaultClientResetHandler), - super.maxNumberOfActiveVersions, - this.shouldCompactCallback, - this.schemaVersion = 0, - this.cancelAsyncOperationsOnNonFatalErrors = false, - }) : super._(); - - @override - String get _defaultPath => user.handle.path; -} - -extension FlexibleSyncConfigurationInternal on FlexibleSyncConfiguration { - SessionStopPolicy get sessionStopPolicy => _sessionStopPolicy; - set sessionStopPolicy(SessionStopPolicy value) => _sessionStopPolicy = value; -} - -/// [DisconnectedSyncConfiguration] is used to open [Realm] instances that are synchronized -/// with MongoDB Atlas, without establishing a connection to [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/). This allows -/// for the synchronized realm to be opened in multiple processes concurrently, as long as -/// only one of them uses a [FlexibleSyncConfiguration] to sync changes. -/// {@category Configuration} -class DisconnectedSyncConfiguration extends Configuration { - DisconnectedSyncConfiguration._( - super.schemaObjects, { - required super.path, - super.fifoFilesFallbackPath, - super.encryptionKey, - super.maxNumberOfActiveVersions, - }) : super._(); - - @override - String get _defaultPath => _path.dirname(path); -} - /// [InMemoryConfiguration] is used to open [Realm] instances that /// are temporary to running process. /// {@category Configuration} @@ -482,291 +302,3 @@ extension RealmSchemaInternal on RealmSchema { _schema.add(obj); } } - -/// [ClientResetHandler] is triggered if the device and server cannot agree -/// on a common shared history for the realm file -/// or when it is impossible for the device to upload or receive any changes. -/// This can happen if the server is rolled back or restored from backup. -/// {@category Sync} -abstract class ClientResetHandler { - // Defines what should happen in case of a client reset - final ClientResyncModeInternal _mode; - - final BeforeResetCallback? _onBeforeReset; - final AfterResetCallback? _onAfterDiscard; - final AfterResetCallback? _onAfterRecovery; - - /// The callback that handles the [ClientResetError]. - final ClientResetCallback? onManualReset; - - const ClientResetHandler._(this._mode, this.onManualReset, - {BeforeResetCallback? onBeforeReset, AfterResetCallback? onAfterDiscard, AfterResetCallback? onAfterRecovery}) - : _onBeforeReset = onBeforeReset, - _onAfterDiscard = onAfterDiscard, - _onAfterRecovery = onAfterRecovery; -} - -/// A client reset strategy where the user needs to fully take care of a client reset. -/// -/// If you set [ManualRecoveryHandler] callback as `clientResetHandler` argument of [Configuration.flexibleSync], -/// that will enable full control of moving any unsynced changes to the synchronized realm. -/// {@category Sync} -class ManualRecoveryHandler extends ClientResetHandler { - /// Creates an instance of `ManualRecoveryHandler` with the supplied client reset handler. - /// - /// [onReset] callback is triggered when a manual client reset happens. - const ManualRecoveryHandler(ClientResetCallback onReset) : super._(ClientResyncModeInternal.manual, onReset); -} - -/// A client reset strategy where any not yet synchronized data is automatically -/// discarded and a fresh copy of the synchronized realm is obtained. -/// -/// If you set [DiscardUnsyncedChangesHandler] callback as `clientResetHandler` argument of [Configuration.flexibleSync], -/// the local `Realm` will be discarded and replaced with the server side `Realm`. -/// All local changes will be lost. -/// {@category Sync} -class DiscardUnsyncedChangesHandler extends ClientResetHandler { - /// The callback that will be executed just before the client reset happens. - BeforeResetCallback? get onBeforeReset => _onBeforeReset; - - /// The callback that will be executed just after the client reset happens. - AfterResetCallback? get onAfterReset => _onAfterDiscard; - - /// Creates an instance of `DiscardUnsyncedChangesHandler`. - /// - /// This strategy supplies three callbacks: [onBeforeReset], [onAfterReset] and [onManualResetFallback]. - /// The first two are invoked just before and after the client reset has happened, - /// while the last one will be invoked in case an error occurs during the automated process and the system needs to fallback to a manual mode. - /// The freshly downloaded copy of the synchronized Realm triggers all change notifications as a write transaction is internally simulated. - const DiscardUnsyncedChangesHandler({BeforeResetCallback? onBeforeReset, AfterResetCallback? onAfterReset, ClientResetCallback? onManualResetFallback}) - : super._(ClientResyncModeInternal.discardLocal, onManualResetFallback, onAfterDiscard: onAfterReset, onBeforeReset: onBeforeReset); -} - -/// A client reset strategy that attempts to automatically recover any unsynchronized changes. -/// -/// If you set [RecoverUnsyncedChangesHandler] callback as `clientResetHandler` argument of [Configuration.flexibleSync], -/// `Realm` will compare the local `Realm` with the `Realm` on the server and automatically transfer -/// any changes from the local `Realm` that makes sense to the `Realm` provided by the server. -/// {@category Sync} -class RecoverUnsyncedChangesHandler extends ClientResetHandler { - /// The callback that will be executed just before the client reset happens. - BeforeResetCallback? get onBeforeReset => _onBeforeReset; - - /// The callback that will be executed just after the client reset happens. - AfterResetCallback? get onAfterReset => _onAfterRecovery; - - /// Creates an instance of `RecoverUnsyncedChangesHandler`. - /// - /// This strategy supplies three callbacks: [onBeforeReset], [onAfterReset] and [onManualResetFallback]. - /// The first two are invoked just before and after the client reset has happened, while the last one is invoked - /// in case an error occurs during the automated process and the system needs to fallback to a manual mode. - const RecoverUnsyncedChangesHandler({BeforeResetCallback? onBeforeReset, AfterResetCallback? onAfterReset, ClientResetCallback? onManualResetFallback}) - : super._(ClientResyncModeInternal.recover, onManualResetFallback, onBeforeReset: onBeforeReset, onAfterRecovery: onAfterReset); -} - -/// A client reset strategy that attempts to automatically recover any unsynchronized changes. -/// If that fails, this handler fallsback to the discard unsynced changes strategy. -/// -/// If you set [RecoverOrDiscardUnsyncedChangesHandler] callback as `clientResetHandler` argument of [Configuration.flexibleSync], -/// `Realm` will compare the local `Realm` with the `Realm` on the server and automatically transfer -/// any changes from the local `Realm` that makes sense to the `Realm` provided by the server. -/// If that fails, the local changes will be discarded. -/// This is the default mode for fully synchronized Realms. -/// {@category Sync} -class RecoverOrDiscardUnsyncedChangesHandler extends ClientResetHandler { - /// The callback that will be executed just before the client reset happens. - BeforeResetCallback? get onBeforeReset => _onBeforeReset; - - /// The callback that will be executed just after the client reset happens if the local changes - /// needed to be discarded. - AfterResetCallback? get onAfterDiscard => _onAfterDiscard; - - /// The callback that will be executed just after the client reset happens if the local changes - /// were successfully recovered. - AfterResetCallback? get onAfterRecovery => _onAfterRecovery; - - /// Creates an instance of `RecoverOrDiscardUnsyncedChangesHandler`. - /// - /// This strategy will recover automatically any unsynchronized changes. If the recovery fails this strategy fallsback to the discard unsynced one. - /// The automatic recovery mechanism creates write transactions meaning that all the changes that take place - /// are properly propagated through the standard Realm's change notifications. - /// This strategy supplies four callbacks: [onBeforeReset], [onAfterRecovery], [onAfterDiscard] and [onManualResetFallback]. - /// [onBeforeReset] is invoked just before the client reset happens. - /// [onAfterRecovery] is invoke if and only if an automatic client reset succeeded. The callback is never called - /// if the automatic client reset fails. - /// [onAfterDiscard] is invoked if and only if an automatic client reset failed and instead the discard unsynced one succeded. - /// The callback is never called if the discard unsynced client reset fails. - /// [onManualResetFallback] is invoked whenever an error occurs in either of the recovery stragegies and the system needs to fallback to a manual mode. - const RecoverOrDiscardUnsyncedChangesHandler( - {BeforeResetCallback? onBeforeReset, AfterResetCallback? onAfterRecovery, AfterResetCallback? onAfterDiscard, ClientResetCallback? onManualResetFallback}) - : super._(ClientResyncModeInternal.recoverOrDiscard, onManualResetFallback, - onBeforeReset: onBeforeReset, onAfterDiscard: onAfterDiscard, onAfterRecovery: onAfterRecovery); -} - -/// @nodoc -extension ClientResetHandlerInternal on ClientResetHandler { - ClientResyncModeInternal get clientResyncMode => _mode; - - BeforeResetCallback? get onBeforeReset => _onBeforeReset; - AfterResetCallback? get onAfterDiscard => _onAfterDiscard; - AfterResetCallback? get onAfterRecovery => _onAfterRecovery; -} - -/// Enum describing what should happen in case of a Client Resync. -/// @nodoc -enum ClientResyncModeInternal { - manual, - discardLocal, - recover, - recoverOrDiscard, -} - -/// An error type that describes a client reset error condition. -/// {@category Sync} -class ClientResetError extends SyncError { - final App? _app; - - /// The path to the original copy of the realm when the client reset was triggered. - /// This realm may contain unsynced changes. - final String? originalFilePath; - - /// The path where the backup copy of the realm will be placed once the client reset process is complete. - final String? backupFilePath; - - ClientResetError._( - String message, - SyncErrorCode code, - this._app, - Object? innerError, { - this.backupFilePath, - this.originalFilePath, - }) : super._(message, code, innerError); - - @override - String toString() { - return "ClientResetError message: $message${innerError == null ? '' : ", inner error: '$innerError'"}"; - } - - /// Initiates the client reset process. - /// - /// Returns `true` if actions were run successfully, `false` otherwise. - bool resetRealm() { - if (_app == null) { - throw RealmException("This `ClientResetError` does not have an `Application` instance."); - } - - if (originalFilePath == null) { - throw RealmException("Missing `originalFilePath`"); - } - - return _app.handle.resetRealm(originalFilePath!); - } -} - -/// Thrown when an error occurs during synchronization -/// This error or its subclasses will be returned to users through [FlexibleSyncConfiguration.syncErrorHandler] -/// and the exact reason must be found in the `message`. -/// {@category Sync} -class SyncError extends RealmError { - /// The code that describes this error. - final SyncErrorCode code; - - SyncError._(super.message, this.code, this.innerError); - - final Object? innerError; - - @override - String toString() { - return "Sync Error: $message"; - } -} - -/// Contains the details for a compensating write performed by the server. -/// {@category Sync} -class CompensatingWriteInfo { - /// The type of the object which was affected by the compensating write. - final String objectType; - - /// The reason for the server to perform a compensating write. - final String reason; - - /// The primary key of the object which was affected by the compensating write. - final RealmValue primaryKey; - - const CompensatingWriteInfo(this.objectType, this.reason, this.primaryKey); - - @override - String toString() { - return "CompensatingWriteInfo: objectType: '$objectType' reason: '$reason' primaryKey: '$primaryKey'"; - } -} - -/// An error type that describes a compensating write error, -/// which indicates that one more object changes have been reverted -/// by the server. -/// {@category Sync} -final class CompensatingWriteError extends SyncError { - /// The list of the compensating writes performed by the server. - late final List? compensatingWrites; - - CompensatingWriteError._( - String message, - Object? innerError, { - this.compensatingWrites, - }) : super._(message, SyncErrorCode.compensatingWrite, innerError); - - @override - String toString() { - return "CompensatingWriteError: $message. ${compensatingWrites ?? ''}"; - } -} - -/// @nodoc -class SyncErrorDetails { - final String message; - final SyncErrorCode code; - final String? path; - final bool isFatal; - final bool isClientResetRequested; - final String? originalFilePath; - final String? backupFilePath; - final List? compensatingWrites; - final Object? userError; - - SyncErrorDetails( - this.message, - this.code, - this.userError, { - this.path, - this.isFatal = false, - this.isClientResetRequested = false, - this.originalFilePath, - this.backupFilePath, - this.compensatingWrites, - }); -} - -/// @nodoc -extension SyncErrorInternal on SyncError { - static SyncError createSyncError(SyncErrorDetails error, {App? app}) { - //Client reset can be requested with isClientResetRequested disregarding the ErrorCode - return switch (error.code) { - SyncErrorCode.autoClientResetFailed => ClientResetError._( - error.message, - error.code, - app, - error.userError, - originalFilePath: error.originalFilePath, - backupFilePath: error.backupFilePath, - ), - SyncErrorCode.clientReset => - ClientResetError._(error.message, error.code, app, error.userError, originalFilePath: error.originalFilePath, backupFilePath: error.backupFilePath), - SyncErrorCode.compensatingWrite => CompensatingWriteError._( - error.message, - error.userError, - compensatingWrites: error.compensatingWrites, - ), - _ => SyncError._(error.message, error.code, error.userError), - }; - } -} diff --git a/packages/realm_dart/lib/src/credentials.dart b/packages/realm_dart/lib/src/credentials.dart deleted file mode 100644 index 85ba0e52d..000000000 --- a/packages/realm_dart/lib/src/credentials.dart +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:convert'; - -import 'app.dart'; -import 'convert.dart'; -import 'handles/credentials_handle.dart'; -import 'user.dart'; - -/// An enum containing all authentication providers. These have to be enabled manually for the application before they can be used. -/// [Authentication Providers Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/#authentication-providers) -/// {@category Application} -enum AuthProviderType { - /// For authenticating without credentials. - anonymous(0), - - /// For authenticating without credentials using a new anonymous user. - /// @nodoc - _anonymousNoReuse(1), - - /// Authenticate with Facebook account. - facebook(2), - - /// Authenticate with Google account - google(3), - - /// Authenticate with Apple Id - apple(4), - - /// For authenticating with JSON web token. - jwt(5), - - /// For authenticating with an email and a password. - emailPassword(6), - - /// For authenticating with custom function with payload argument. - function(7), - - /// For authenticating with an API key. - apiKey(8); - - const AuthProviderType(this._value); - - final int _value; -} - -extension AuthProviderTypeInternal on AuthProviderType { - static AuthProviderType getByValue(int value) { - if (value == AuthProviderType._anonymousNoReuse._value) { - return AuthProviderType.anonymous; - } - return AuthProviderType.values.firstWhere((v) => v._value == value); - } -} - -/// A class, representing the credentials used for authenticating a [User] -/// {@category Application} -class Credentials { - final CredentialsHandle _handle; - - /// Returns a [Credentials] object that can be used to authenticate an anonymous user. - /// Setting [reuseCredentials] to `false` will create a new anonymous user, upon [App.logIn]. - /// [Anonymous Authentication Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/anonymous/#anonymous-authentication) - Credentials.anonymous({bool reuseCredentials = true}) : _handle = CredentialsHandle.anonymous(reuseCredentials); - - /// Returns a [Credentials] object that can be used to authenticate a user with a Google account using an id token. - Credentials.apple(String idToken) : _handle = CredentialsHandle.apple(idToken); - - /// Returns a [Credentials] object that can be used to authenticate a user with their email and password. - /// A user can login with email and password only after they have registered their account and verified their - /// email. - /// [Email/Password Authentication Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/email-password/#email-password-authentication) - Credentials.emailPassword(String email, String password) : _handle = CredentialsHandle.emailPassword(email, password); - - /// Returns a [Credentials] object that can be used to authenticate a user with a custom JWT. - /// [Custom-JWT Authentication Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/custom-jwt/#custom-jwt-authentication) - Credentials.jwt(String token) : _handle = CredentialsHandle.jwt(token); - - /// Returns a [Credentials] object that can be used to authenticate a user with a Facebook account. - Credentials.facebook(String accessToken) : _handle = CredentialsHandle.facebook(accessToken); - - /// Returns a [Credentials] object that can be used to authenticate a user with a Google account using an authentication code. - Credentials.googleAuthCode(String authCode) : _handle = CredentialsHandle.googleAuthCode(authCode); - - /// Returns a [Credentials] object that can be used to authenticate a user with a Google account using an id token. - Credentials.googleIdToken(String idToken) : _handle = CredentialsHandle.googleIdToken(idToken); - - /// Returns a [Credentials] object that can be used to authenticate a user with a custom Function. - /// [Custom Function Authentication Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/custom-function/) - Credentials.function(String payload) : _handle = CredentialsHandle.function(payload); - - /// Returns a [Credentials] object that can be used to authenticate a user with an API key. - /// To generate an API key, use [ApiKeyClient.create] or the App Services web UI. - Credentials.apiKey(String key) : _handle = CredentialsHandle.apiKey(key); - - AuthProviderType get provider => handle.providerType; -} - -/// @nodoc -extension CredentialsInternal on Credentials { - CredentialsHandle get handle => _handle; -} - -/// A class, encapsulating functionality for users, logged in with [Credentials.emailPassword()]. -/// It is always scoped to a particular app. -/// {@category Application} -class EmailPasswordAuthProvider { - final App app; - - /// Create a new EmailPasswordAuthProvider for the [app] - EmailPasswordAuthProvider(this.app); - - /// Registers a new user with the given email and password. - /// The [email] to register with. This will be the user's username and, if user confirmation is enabled, this will be the address for - /// the confirmation email. - /// The [password] to associate with the email. The password must be between 6 and 128 characters long. - /// - /// Successful completion indicates that the user has been created on the server and can now be logged in with [Credentials.emailPassword()]. - Future registerUser(String email, String password) async { - return app.handle.registerUser(email, password); - } - - /// Confirms a user with the given token and token id. These are typically included in the registration email. - Future confirmUser(String token, String tokenId) { - return app.handle.confirmUser(token, tokenId); - } - - /// Resend the confirmation email for a user to the given email. - Future resendUserConfirmation(String email) { - return app.handle.resendConfirmation(email); - } - - /// Completes the reset password procedure by providing the desired new [password] using the - /// password reset [token] and [tokenId] that were emailed to a user. - Future completeResetPassword(String password, String token, String tokenId) { - return app.handle.completeResetPassword(password, token, tokenId); - } - - /// Sends a password reset email. - Future resetPassword(String email) { - return app.handle.requestResetPassword(email); - } - - /// Calls the reset password function, configured on the server. - Future callResetPasswordFunction(String email, String password, {List? functionArgs}) { - return app.handle.callResetPasswordFunction(email, password, functionArgs.convert(jsonEncode)); - } - - /// Retries the custom confirmation function on a user for a given email. - Future retryCustomConfirmationFunction(String email) { - return app.handle.retryCustomConfirmationFunction(email); - } -} - -extension EmailPasswordAuthProviderInternal on EmailPasswordAuthProvider { - static EmailPasswordAuthProvider create(App app) => EmailPasswordAuthProvider(app); -} diff --git a/packages/realm_dart/lib/src/handles/app_handle.dart b/packages/realm_dart/lib/src/handles/app_handle.dart deleted file mode 100644 index 58f171adf..000000000 --- a/packages/realm_dart/lib/src/handles/app_handle.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../../realm.dart'; - -import 'credentials_handle.dart'; -import 'user_handle.dart'; - -import 'native/app_handle.dart' if (dart.library.js_interop) 'web/app_handle.dart' as impl; - -abstract interface class AppHandle { - factory AppHandle.from(AppConfiguration configuration) = impl.AppHandle.from; - static AppHandle? get(String id, String? baseUrl) => impl.AppHandle.get(id, baseUrl); - - String get id; - - UserHandle? get currentUser; - List get users; - Future logIn(CredentialsHandle credentials); - Future removeUser(UserHandle user); - void switchUser(UserHandle user); - Future refreshCustomData(UserHandle user); - - void reconnect(); - String get baseUrl; - Future updateBaseUrl(Uri? baseUrl); - - Future registerUser(String email, String password); - Future confirmUser(String token, String tokenId); - Future resendConfirmation(String email); - - Future completeResetPassword(String password, String token, String tokenId); - Future requestResetPassword(String email); - Future callResetPasswordFunction(String email, String password, String? argsAsJSON); - Future retryCustomConfirmationFunction(String email); - Future deleteUser(UserHandle user); - bool resetRealm(String realmPath); - Future callAppFunction(UserHandle user, String functionName, String? argsAsJSON); -} diff --git a/packages/realm_dart/lib/src/handles/async_open_task_handle.dart b/packages/realm_dart/lib/src/handles/async_open_task_handle.dart deleted file mode 100644 index 47d988585..000000000 --- a/packages/realm_dart/lib/src/handles/async_open_task_handle.dart +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../realm_class.dart'; -import 'handle_base.dart'; -import 'native/async_open_task_handle.dart' if (dart.library.js_interop) 'web/async_open_task_handle.dart' as impl; -import 'realm_handle.dart'; - -abstract interface class AsyncOpenTaskHandle extends HandleBase { - factory AsyncOpenTaskHandle.from(FlexibleSyncConfiguration config) = impl.AsyncOpenTaskHandle.from; - - Future openAsync(CancellationToken? cancellationToken); - void cancel(); - - AsyncOpenTaskProgressNotificationTokenHandle registerProgressNotifier( - RealmAsyncOpenProgressNotificationsController controller, - ); -} - -abstract class AsyncOpenTaskProgressNotificationTokenHandle extends HandleBase {} \ No newline at end of file diff --git a/packages/realm_dart/lib/src/handles/credentials_handle.dart b/packages/realm_dart/lib/src/handles/credentials_handle.dart deleted file mode 100644 index d4259374b..000000000 --- a/packages/realm_dart/lib/src/handles/credentials_handle.dart +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../credentials.dart'; -import 'handle_base.dart'; - -import 'native/credentials_handle.dart' if (dart.library.js_interop) 'web/credentials_handle.dart' as impl; - -abstract interface class CredentialsHandle extends HandleBase { - factory CredentialsHandle.anonymous(bool reuseCredentials) = impl.CredentialsHandle.anonymous; - - factory CredentialsHandle.emailPassword(String email, String password) = impl.CredentialsHandle.emailPassword; - - factory CredentialsHandle.jwt(String token) = impl.CredentialsHandle.jwt; - - factory CredentialsHandle.apple(String idToken) = impl.CredentialsHandle.apple; - - factory CredentialsHandle.facebook(String accessToken) = impl.CredentialsHandle.facebook; - - factory CredentialsHandle.googleIdToken(String idToken) = impl.CredentialsHandle.googleIdToken; - - factory CredentialsHandle.googleAuthCode(String authCode) = impl.CredentialsHandle.googleAuthCode; - - factory CredentialsHandle.function(String payload) = impl.CredentialsHandle.function; - - factory CredentialsHandle.apiKey(String key) = impl.CredentialsHandle.apiKey; - - AuthProviderType get providerType; -} diff --git a/packages/realm_dart/lib/src/handles/mutable_subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/mutable_subscription_set_handle.dart deleted file mode 100644 index 06cb2a811..000000000 --- a/packages/realm_dart/lib/src/handles/mutable_subscription_set_handle.dart +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'results_handle.dart'; -import 'subscription_handle.dart'; -import 'subscription_set_handle.dart'; - -abstract interface class MutableSubscriptionSetHandle extends SubscriptionSetHandle { - SubscriptionSetHandle commit(); - - SubscriptionHandle insertOrAssignSubscription(ResultsHandle results, String? name, bool update); - - bool erase(SubscriptionHandle subscription); - bool eraseByName(String name); - bool eraseByResults(ResultsHandle results); - - void clear(); -} diff --git a/packages/realm_dart/lib/src/handles/native/app_handle.dart b/packages/realm_dart/lib/src/handles/native/app_handle.dart deleted file mode 100644 index 28c5c9e4e..000000000 --- a/packages/realm_dart/lib/src/handles/native/app_handle.dart +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:ffi'; -import 'dart:io'; -import 'dart:isolate'; - -import 'package:realm_dart/realm.dart'; - -import 'convert.dart'; -import 'convert_native.dart'; -import 'credentials_handle.dart'; -import 'error_handling.dart'; -import 'ffi.dart'; -import 'handle_base.dart'; -import 'http_transport_handle.dart'; -import 'realm_bindings.dart'; -import 'realm_core.dart'; -import 'realm_library.dart'; -import 'scheduler_handle.dart'; -import 'user_handle.dart'; - -import '../app_handle.dart' as intf; - -class AppHandle extends HandleBase implements intf.AppHandle { - AppHandle(Pointer pointer) : super(pointer, 16); - - static bool _firstTime = true; - factory AppHandle.from(AppConfiguration configuration) { - // to avoid caching apps across hot restarts we clear the cache on the first - // time the ctor is called in the root isolate. - if (_firstTime && _isRootIsolate) { - _firstTime = false; - realmLib.realm_clear_cached_apps(); - } - Directory(configuration.baseFilePath).createSync(recursive: true); - - final httpTransportHandle = HttpTransportHandle.from(configuration.httpClient); - final appConfigHandle = _createAppConfig(configuration, httpTransportHandle); - return AppHandle(realmLib.realm_app_create_cached(appConfigHandle.pointer)); - } - - static AppHandle? get(String id, String? baseUrl) { - return using((arena) { - final outApp = arena>(); - realmLib - .realm_app_get_cached( - id.toCharPtr(arena), - baseUrl == null ? nullptr : baseUrl.toCharPtr(arena), - outApp, - ) - .raiseLastErrorIfFalse(); - return outApp.value.convert(AppHandle.new); - }); - } - - @override - UserHandle? get currentUser { - return realmLib.realm_app_get_current_user(pointer).convert(UserHandle.new); - } - - @override - List get users => using((arena) => _getUsers(arena)); - - List _getUsers(Arena arena, {int expectedSize = 2}) { - final actualCount = arena(); - final usersPtr = arena>(expectedSize); - realmLib.realm_app_get_all_users(pointer, usersPtr, expectedSize, actualCount).raiseLastErrorIfFalse(); - - if (expectedSize < actualCount.value) { - // The supplied array was too small - resize it - arena.free(usersPtr); - return _getUsers(arena, expectedSize: actualCount.value); - } - - final result = []; - for (var i = 0; i < actualCount.value; i++) { - result.add(UserHandle((usersPtr + i).value)); - } - - return result; - } - - @override - Future removeUser(covariant UserHandle user) { - final completer = Completer(); - realmLib - .realm_app_remove_user( - pointer, - user.pointer, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - } - - @override - void switchUser(covariant UserHandle user) { - using((arena) { - realmLib - .realm_app_switch_user( - pointer, - user.pointer, - ) - .raiseLastErrorIfFalse(); - }); - } - - @override - void reconnect() => realmLib.realm_app_sync_client_reconnect(pointer); - - @override - String get baseUrl { - final customDataPtr = realmLib.realm_app_get_base_url(pointer); - return customDataPtr.cast().toRealmDartString(freeRealmMemory: true)!; - } - - @override - Future updateBaseUrl(Uri? baseUrl) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_update_base_url( - pointer, - baseUrl?.toString().toCharPtr(arena) ?? nullptr, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future refreshCustomData(covariant UserHandle user) { - final completer = Completer(); - realmLib - .realm_app_refresh_custom_data( - pointer, - user.pointer, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - } - - @override - String get id { - return realmLib.realm_app_get_app_id(pointer).cast().toRealmDartString()!; - } - - @override - Future logIn(covariant CredentialsHandle credentials) { - final completer = Completer(); - realmLib - .realm_app_log_in_with_credentials( - pointer, - credentials.pointer, - realmLib.addresses.realm_dart_user_completion_callback, - createAsyncUserCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - } - - @override - Future registerUser(String email, String password) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_register_email( - pointer, - email.toCharPtr(arena), - password.toRealmString(arena).ref, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future confirmUser(String token, String tokenId) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_confirm_user( - pointer, - token.toCharPtr(arena), - tokenId.toCharPtr(arena), - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future resendConfirmation(String email) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_resend_confirmation_email( - pointer, - email.toCharPtr(arena), - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future completeResetPassword(String password, String token, String tokenId) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_reset_password( - pointer, - password.toRealmString(arena).ref, - token.toCharPtr(arena), - tokenId.toCharPtr(arena), - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future requestResetPassword(String email) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_send_reset_password_email( - pointer, - email.toCharPtr(arena), - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future callResetPasswordFunction(String email, String password, String? argsAsJSON) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_call_reset_password_function( - pointer, - email.toCharPtr(arena), - password.toRealmString(arena).ref, - argsAsJSON != null ? argsAsJSON.toCharPtr(arena) : nullptr, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future retryCustomConfirmationFunction(String email) { - final completer = Completer(); - using((arena) { - realmLib - .realm_app_email_password_provider_client_retry_custom_confirmation( - pointer, - email.toCharPtr(arena), - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - }); - return completer.future; - } - - @override - Future deleteUser(covariant UserHandle user) { - final completer = Completer(); - realmLib - .realm_app_delete_user( - pointer, - user.pointer, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - } - - @override - bool resetRealm(String realmPath) { - return using((arena) { - final didRun = arena(); - realmLib - .realm_sync_immediately_run_file_actions( - pointer, - realmPath.toCharPtr(arena), - didRun, - ) - .raiseLastErrorIfFalse(); - return didRun.value; - }); - } - - @override - Future callAppFunction(covariant UserHandle user, String functionName, String? argsAsJSON) { - return using((arena) { - final completer = Completer(); - realmLib - .realm_app_call_function( - pointer, - user.pointer, - functionName.toCharPtr(arena), - argsAsJSON?.toCharPtr(arena) ?? nullptr, - nullptr, - realmLib.addresses.realm_dart_return_string_callback, - createAsyncFunctionCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - }); - } -} - -Pointer createAsyncFunctionCallbackUserdata(Completer completer) { - final callback = Pointer.fromFunction< - Void Function( - Pointer, - Pointer, - Pointer, - )>(_callAppFunctionCallback); - - final userdata = realmLib.realm_dart_userdata_async_new( - completer, - callback.cast(), - schedulerHandle.pointer, - ); - - return userdata.cast(); -} - -void _callAppFunctionCallback(Pointer userdata, Pointer response, Pointer error) { - final Completer completer = userdata.toObject(); - - if (error != nullptr) { - completer.completeWithAppError(error); - return; - } - - final stringResponse = response.cast().toRealmDartString()!; - completer.complete(stringResponse); -} - -Pointer createAsyncCallbackUserdata(Completer completer) { - final callback = Pointer.fromFunction< - Void Function( - Pointer, - Pointer, - )>(_voidCompletionCallback); - - final userdata = realmLib.realm_dart_userdata_async_new( - completer, - callback.cast(), - schedulerHandle.pointer, - ); - - return userdata.cast(); -} - -void _voidCompletionCallback(Pointer userdata, Pointer error) { - final Completer completer = userdata.toObject(); - - if (error != nullptr) { - completer.completeWithAppError(error); - return; - } - - completer.complete(); -} - -class _AppConfigHandle extends HandleBase { - _AppConfigHandle(Pointer pointer) : super(pointer, 8); -} - -_AppConfigHandle _createAppConfig(AppConfiguration configuration, HttpTransportHandle httpTransport) { - return using((arena) { - final appId = configuration.appId.toCharPtr(arena); - final handle = _AppConfigHandle(realmLib.realm_app_config_new(appId, httpTransport.pointer)); - - realmLib.realm_app_config_set_platform_version(handle.pointer, Platform.operatingSystemVersion.toCharPtr(arena)); - - realmLib.realm_app_config_set_sdk(handle.pointer, 'Dart'.toCharPtr(arena)); - realmLib.realm_app_config_set_sdk_version(handle.pointer, libraryVersion.toCharPtr(arena)); - - final deviceName = realmCore.getDeviceName(); - realmLib.realm_app_config_set_device_name(handle.pointer, deviceName.toCharPtr(arena)); - - final deviceVersion = realmCore.getDeviceVersion(); - realmLib.realm_app_config_set_device_version(handle.pointer, deviceVersion.toCharPtr(arena)); - - realmLib.realm_app_config_set_framework_name(handle.pointer, (isFlutterPlatform ? 'Flutter' : 'Dart VM').toCharPtr(arena)); - realmLib.realm_app_config_set_framework_version(handle.pointer, Platform.version.toCharPtr(arena)); - - realmLib.realm_app_config_set_base_url(handle.pointer, configuration.baseUrl.toString().toCharPtr(arena)); - - realmLib.realm_app_config_set_default_request_timeout(handle.pointer, configuration.defaultRequestTimeout.inMilliseconds); - - realmLib.realm_app_config_set_bundle_id(handle.pointer, realmCore.getBundleId().toCharPtr(arena)); - - realmLib.realm_app_config_set_base_file_path(handle.pointer, configuration.baseFilePath.toCharPtr(arena)); - realmLib.realm_app_config_set_metadata_mode(handle.pointer, configuration.metadataPersistenceMode.index); - - if (configuration.metadataEncryptionKey != null && configuration.metadataPersistenceMode == MetadataPersistenceMode.encrypted) { - realmLib.realm_app_config_set_metadata_encryption_key(handle.pointer, configuration.metadataEncryptionKey!.toUint8Ptr(arena)); - } - - final syncClientConfig = realmLib.realm_app_config_get_sync_client_config(handle.pointer); - realmLib.realm_sync_client_config_set_connect_timeout(syncClientConfig, configuration.syncTimeoutOptions.connectTimeout.inMilliseconds); - realmLib.realm_sync_client_config_set_connection_linger_time(syncClientConfig, configuration.syncTimeoutOptions.connectionLingerTime.inMilliseconds); - realmLib.realm_sync_client_config_set_ping_keepalive_period(syncClientConfig, configuration.syncTimeoutOptions.pingKeepAlivePeriod.inMilliseconds); - realmLib.realm_sync_client_config_set_pong_keepalive_timeout(syncClientConfig, configuration.syncTimeoutOptions.pongKeepAliveTimeout.inMilliseconds); - realmLib.realm_sync_client_config_set_fast_reconnect_limit(syncClientConfig, configuration.syncTimeoutOptions.fastReconnectLimit.inMilliseconds); - - return handle; - }); -} - -// TODO: -// We need a pure Dart equivalent of: -// ```dart -// ServiceBinding.rootIsolateToken != null -// ``` -// to get rid of this hack. -final bool _isRootIsolate = Isolate.current.debugName == 'main'; diff --git a/packages/realm_dart/lib/src/handles/native/async_open_task_handle.dart b/packages/realm_dart/lib/src/handles/native/async_open_task_handle.dart deleted file mode 100644 index 2ab5450d4..000000000 --- a/packages/realm_dart/lib/src/handles/native/async_open_task_handle.dart +++ /dev/null @@ -1,86 +0,0 @@ -import 'dart:ffi'; - -import 'package:cancellation_token/cancellation_token.dart'; -import 'ffi.dart'; -import 'error_handling.dart'; -import 'realm_bindings.dart'; - -import '../../realm_dart.dart'; -import 'config_handle.dart'; -import 'handle_base.dart'; -import 'realm_handle.dart'; -import 'realm_library.dart'; -import 'scheduler_handle.dart'; -import 'session_handle.dart'; - -import '../async_open_task_handle.dart' as intf; - -class AsyncOpenTaskHandle extends HandleBase implements intf.AsyncOpenTaskHandle { - AsyncOpenTaskHandle(Pointer pointer) : super(pointer, 32); - - factory AsyncOpenTaskHandle.from(FlexibleSyncConfiguration config) { - final configHandle = ConfigHandle.from(config); - final asyncOpenTaskPtr = realmLib.realm_open_synchronized(configHandle.pointer).raiseLastErrorIfNull(); - return AsyncOpenTaskHandle(asyncOpenTaskPtr); - } - - @override - Future openAsync(CancellationToken? cancellationToken) { - final completer = CancellableCompleter(cancellationToken); - if (!completer.isCancelled) { - final callback = - Pointer.fromFunction realm, Pointer error)>(_openRealmAsyncCallback); - final userData = realmLib.realm_dart_userdata_async_new(completer, callback.cast(), schedulerHandle.pointer); - realmLib.realm_async_open_task_start( - pointer, - realmLib.addresses.realm_dart_async_open_task_callback, - userData.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ); - } - return completer.future; - } - - @override - void cancel() { - realmLib.realm_async_open_task_cancel(pointer); - } - - @override - AsyncOpenTaskProgressNotificationTokenHandle registerProgressNotifier( - RealmAsyncOpenProgressNotificationsController controller, - ) { - final callback = Pointer.fromFunction(syncProgressCallback); - final userdata = realmLib.realm_dart_userdata_async_new(controller, callback.cast(), schedulerHandle.pointer); - return AsyncOpenTaskProgressNotificationTokenHandle( - realmLib.realm_async_open_task_register_download_progress_notifier( - pointer, - realmLib.addresses.realm_dart_sync_progress_callback, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ), - ); - } -} - -class AsyncOpenTaskProgressNotificationTokenHandle extends HandleBase - implements intf.AsyncOpenTaskProgressNotificationTokenHandle { - AsyncOpenTaskProgressNotificationTokenHandle(Pointer pointer) : super(pointer, 40); -} - -void _openRealmAsyncCallback(Object userData, Pointer realmSafePtr, Pointer error) { - return using((arena) { - final completer = userData as CancellableCompleter; - if (completer.isCancelled) { - return; - } - if (error != nullptr) { - final err = arena(); - final lastError = realmLib.realm_get_async_error(error, err) ? err.ref.toDart() : null; - completer.completeError(RealmException("Failed to open realm: ${lastError?.message ?? 'Error details missing.'}")); - return; - } - - completer.complete(RealmHandle(realmLib.realm_from_thread_safe_reference(realmSafePtr, schedulerHandle.pointer))); - }); -} diff --git a/packages/realm_dart/lib/src/handles/native/config_handle.dart b/packages/realm_dart/lib/src/handles/native/config_handle.dart index b166d70b6..d6268b004 100644 --- a/packages/realm_dart/lib/src/handles/native/config_handle.dart +++ b/packages/realm_dart/lib/src/handles/native/config_handle.dart @@ -1,15 +1,11 @@ // Copyright 2024 MongoDB, Inc. // SPDX-License-Identifier: Apache-2.0 -import 'dart:async'; import 'dart:ffi'; -import '../../configuration.dart'; import '../../migration.dart'; import '../../realm_class.dart'; -import '../../user.dart'; import 'convert_native.dart'; -import 'error_handling.dart'; import 'ffi.dart'; import 'handle_base.dart'; import 'realm_bindings.dart'; @@ -17,7 +13,6 @@ import 'realm_handle.dart'; import 'realm_library.dart'; import 'scheduler_handle.dart'; import 'schema_handle.dart'; -import 'user_handle.dart'; class ConfigHandle extends HandleBase { ConfigHandle(Pointer pointer) : super(pointer, 512); @@ -43,7 +38,6 @@ class ConfigHandle extends HandleBase { final schemaVersion = switch (config) { (LocalConfiguration lc) => lc.schemaVersion, - (FlexibleSyncConfiguration fsc) => fsc.schemaVersion, _ => 0, }; realmLib.realm_config_set_schema_version(configHandle.pointer, schemaVersion); @@ -85,54 +79,6 @@ class ConfigHandle extends HandleBase { } } else if (config is InMemoryConfiguration) { realmLib.realm_config_set_in_memory(configHandle.pointer, true); - } else if (config is FlexibleSyncConfiguration) { - realmLib.realm_config_set_schema_mode(configHandle.pointer, realm_schema_mode.RLM_SCHEMA_MODE_ADDITIVE_EXPLICIT); - final syncConfigPtr = realmLib.realm_flx_sync_config_new((config.user.handle as UserHandle).pointer).raiseLastErrorIfNull(); - try { - realmLib.realm_sync_config_set_session_stop_policy(syncConfigPtr, config.sessionStopPolicy.index); - realmLib.realm_sync_config_set_resync_mode(syncConfigPtr, config.clientResetHandler.clientResyncMode.index); - realmLib.realm_sync_config_set_cancel_waits_on_nonfatal_error(syncConfigPtr, config.cancelAsyncOperationsOnNonFatalErrors); - - final errorHandlerCallback = - Pointer.fromFunction, realm_sync_error_t)>(_syncErrorHandlerCallback); - final errorHandlerUserdata = realmLib.realm_dart_userdata_async_new(config, errorHandlerCallback.cast(), schedulerHandle.pointer); - realmLib.realm_sync_config_set_error_handler(syncConfigPtr, realmLib.addresses.realm_dart_sync_error_handler_callback, errorHandlerUserdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free); - - if (config.clientResetHandler.onBeforeReset != null) { - final syncBeforeResetCallback = Pointer.fromFunction, Pointer)>(_syncBeforeResetCallback); - final beforeResetUserdata = realmLib.realm_dart_userdata_async_new(config, syncBeforeResetCallback.cast(), schedulerHandle.pointer); - - realmLib.realm_sync_config_set_before_client_reset_handler(syncConfigPtr, realmLib.addresses.realm_dart_sync_before_reset_handler_callback, - beforeResetUserdata.cast(), realmLib.addresses.realm_dart_userdata_async_free); - } - - if (config.clientResetHandler.onAfterRecovery != null || config.clientResetHandler.onAfterDiscard != null) { - final syncAfterResetCallback = - Pointer.fromFunction, Pointer, Bool, Pointer)>( - _syncAfterResetCallback); - final afterResetUserdata = realmLib.realm_dart_userdata_async_new(config, syncAfterResetCallback.cast(), schedulerHandle.pointer); - - realmLib.realm_sync_config_set_after_client_reset_handler(syncConfigPtr, realmLib.addresses.realm_dart_sync_after_reset_handler_callback, - afterResetUserdata.cast(), realmLib.addresses.realm_dart_userdata_async_free); - } - - if (config.shouldCompactCallback != null) { - realmLib.realm_config_set_should_compact_on_launch_function( - configHandle.pointer, - Pointer.fromFunction(_shouldCompactCallback, false), - config.toPersistentHandle(), - realmLib.addresses.realm_dart_delete_persistent_handle, - ); - } - - realmLib.realm_config_set_sync_config(configHandle.pointer, syncConfigPtr); - } finally { - realmLib.realm_release(syncConfigPtr.cast()); - } - } else if (config is DisconnectedSyncConfiguration) { - realmLib.realm_config_set_schema_mode(configHandle.pointer, realm_schema_mode.RLM_SCHEMA_MODE_ADDITIVE_EXPLICIT); - realmLib.realm_config_set_force_sync_history(configHandle.pointer, true); } final key = config.encryptionKey; @@ -140,8 +86,8 @@ class ConfigHandle extends HandleBase { realmLib.realm_config_set_encryption_key(configHandle.pointer, key.toUint8Ptr(arena), key.length); } - // For sync and for dynamic Realms, we need to have a complete view of the schema in Core. - if (config.schemaObjects.isEmpty || config is FlexibleSyncConfiguration) { + // For dynamic Realms, we need to have a complete view of the schema in Core. + if (config.schemaObjects.isEmpty) { realmLib.realm_config_set_schema_subset_mode(configHandle.pointer, realm_schema_subset_mode.RLM_SCHEMA_SUBSET_MODE_COMPLETE); } @@ -150,41 +96,11 @@ class ConfigHandle extends HandleBase { } } -void _syncAfterResetCallback(Object userdata, Pointer beforeHandle, Pointer afterReference, bool didRecover, - Pointer unlockCallbackFunc) { - _guardSynchronousCallback(() async { - final syncConfig = userdata as FlexibleSyncConfiguration; - final afterResetCallback = didRecover ? syncConfig.clientResetHandler.onAfterRecovery : syncConfig.clientResetHandler.onAfterDiscard; - - if (afterResetCallback == null) { - return; - } - - final beforeRealm = RealmInternal.getUnowned(syncConfig, RealmHandle.unowned(beforeHandle)); - final afterRealm = RealmInternal.getUnowned( - syncConfig, - RealmHandle.unowned(realmLib.realm_from_thread_safe_reference( - afterReference, - schedulerHandle.pointer, - ))); - - try { - await afterResetCallback(beforeRealm, afterRealm); - return; - } finally { - beforeRealm.handle.release(); - afterRealm.handle.release(); - } - }, unlockCallbackFunc); -} - bool _shouldCompactCallback(Pointer userdata, int totalSize, int usedSize) { final config = userdata.toObject(); if (config is LocalConfiguration) { return config.shouldCompactCallback!(totalSize, usedSize); - } else if (config is FlexibleSyncConfiguration) { - return config.shouldCompactCallback!(totalSize, usedSize); } return false; @@ -215,33 +131,6 @@ bool _migrationCallback(Pointer userdata, Pointer oldRealmHa return false; } -void _syncErrorHandlerCallback(Object userdata, Pointer session, realm_sync_error error) { - final syncConfig = userdata as FlexibleSyncConfiguration; - // TODO: Take the app from the session instead of from syncConfig after fixing issue https://github.com/realm/realm-dart/issues/633 - final syncError = SyncErrorInternal.createSyncError(error.toDart(), app: syncConfig.user.app); - - if (syncError is ClientResetError) { - syncConfig.clientResetHandler.onManualReset?.call(syncError); - return; - } - - syncConfig.syncErrorHandler(syncError); -} - -void _syncBeforeResetCallback(Object userdata, Pointer realmPtr, Pointer unlockCallbackFunc) { - _guardSynchronousCallback(() async { - final syncConfig = userdata as FlexibleSyncConfiguration; - var beforeResetCallback = syncConfig.clientResetHandler.onBeforeReset!; - - final realm = RealmInternal.getUnowned(syncConfig, RealmHandle.unowned(realmPtr)); - try { - await beforeResetCallback(realm); - } finally { - realm.handle.release(); - } - }, unlockCallbackFunc); -} - bool _initialDataCallback(Pointer userdata, Pointer realmPtr) { final realmHandle = RealmHandle.unowned(realmPtr); try { @@ -257,14 +146,3 @@ bool _initialDataCallback(Pointer userdata, Pointer realmPtr return false; } - -void _guardSynchronousCallback(FutureOr Function() callback, Pointer unlockCallbackFunc) async { - Pointer userError = nullptr; - try { - await callback(); - } catch (error) { - userError = error.toPersistentHandle(); - } finally { - realmLib.realm_dart_invoke_unlock_callback(userError, unlockCallbackFunc); - } -} diff --git a/packages/realm_dart/lib/src/handles/native/credentials_handle.dart b/packages/realm_dart/lib/src/handles/native/credentials_handle.dart deleted file mode 100644 index c7ecffe0f..000000000 --- a/packages/realm_dart/lib/src/handles/native/credentials_handle.dart +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:ffi'; - -import 'ffi.dart'; - -import '../../credentials.dart'; -import 'handle_base.dart'; -import 'realm_bindings.dart'; -import 'realm_library.dart'; -import 'to_native.dart'; - -import '../credentials_handle.dart' as intf; - -class CredentialsHandle extends HandleBase implements intf.CredentialsHandle { - CredentialsHandle(Pointer pointer) : super(pointer, 16); - - factory CredentialsHandle.anonymous(bool reuseCredentials) { - return CredentialsHandle(realmLib.realm_app_credentials_new_anonymous(reuseCredentials)); - } - - factory CredentialsHandle.emailPassword(String email, String password) { - return using((arena) { - final emailPtr = email.toCharPtr(arena); - final passwordPtr = password.toRealmString(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_email_password(emailPtr, passwordPtr.ref)); - }); - } - - factory CredentialsHandle.jwt(String token) { - return using((arena) { - final tokenPtr = token.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_jwt(tokenPtr)); - }); - } - - factory CredentialsHandle.apple(String idToken) { - return using((arena) { - final idTokenPtr = idToken.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_apple(idTokenPtr)); - }); - } - - factory CredentialsHandle.facebook(String accessToken) { - return using((arena) { - final accessTokenPtr = accessToken.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_facebook(accessTokenPtr)); - }); - } - - factory CredentialsHandle.googleIdToken(String idToken) { - return using((arena) { - final idTokenPtr = idToken.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_google_id_token(idTokenPtr)); - }); - } - - factory CredentialsHandle.googleAuthCode(String authCode) { - return using((arena) { - final authCodePtr = authCode.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_google_auth_code(authCodePtr)); - }); - } - - factory CredentialsHandle.function(String payload) { - return using((arena) { - final payloadPtr = payload.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_function(payloadPtr)); - }); - } - - factory CredentialsHandle.apiKey(String key) { - return using((arena) { - final keyPtr = key.toCharPtr(arena); - return CredentialsHandle(realmLib.realm_app_credentials_new_api_key(keyPtr)); - }); - } - - AuthProviderType get providerType { - final provider = realmLib.realm_auth_credentials_get_provider(pointer); - return AuthProviderTypeInternal.getByValue(provider); - } -} diff --git a/packages/realm_dart/lib/src/handles/native/from_native.dart b/packages/realm_dart/lib/src/handles/native/from_native.dart index f61812228..b534a92c6 100644 --- a/packages/realm_dart/lib/src/handles/native/from_native.dart +++ b/packages/realm_dart/lib/src/handles/native/from_native.dart @@ -5,10 +5,7 @@ import 'dart:typed_data'; import 'ffi.dart'; -import '../../app.dart'; -import '../../configuration.dart'; import '../../realm_class.dart'; -import '../../user.dart'; import 'decimal128.dart'; import 'list_handle.dart'; import 'map_handle.dart'; @@ -142,122 +139,12 @@ extension PointerUtf8Ex on Pointer { } } -extension RealmSyncErrorEx on realm_sync_error { - SyncErrorDetails toDart() { - final message = status.message.cast().toRealmDartString()!; - final userInfoMap = user_info_map.toDart(user_info_length); - final originalFilePathKey = c_original_file_path_key.cast().toRealmDartString(); - final recoveryFilePathKey = c_recovery_file_path_key.cast().toRealmDartString(); - - return SyncErrorDetails( - message, - status.error.toSyncErrorCode(), - user_code_error.toUserCodeError(), - isFatal: is_fatal, - isClientResetRequested: is_client_reset_requested, - originalFilePath: userInfoMap?[originalFilePathKey], - backupFilePath: userInfoMap?[recoveryFilePathKey], - compensatingWrites: compensating_writes.toList(compensating_writes_length), - ); - } -} - -extension PointerRealmSyncErrorUserInfoEx on Pointer { - Map? toDart(int length) { - if (this == nullptr) { - return null; - } - Map userInfoMap = {}; - for (int i = 0; i < length; i++) { - final userInfoItem = this[i]; - final key = userInfoItem.key.cast().toDartString(); - final value = userInfoItem.value.cast().toDartString(); - userInfoMap[key] = value; - } - return userInfoMap; - } -} - -extension PointerRealmSyncErrorCompensatingWriteInfoEx on Pointer { - List? toList(int length) { - if (this == nullptr || length == 0) { - return null; - } - List compensatingWrites = []; - for (int i = 0; i < length; i++) { - final compensatingWrite = this[i]; - final reason = compensatingWrite.reason.cast().toDartString(); - final objectName = compensatingWrite.object_name.cast().toDartString(); - final primaryKey = compensatingWrite.primary_key.toPrimitiveValue(); - compensatingWrites.add(CompensatingWriteInfo(objectName, reason, RealmValue.from(primaryKey))); - } - return compensatingWrites; - } -} - -extension PointerRealmErrorEx on Pointer { - SyncError toDart() { - final message = ref.message.cast().toDartString(); - final details = SyncErrorDetails(message, ref.error.toSyncErrorCode(), ref.user_code_error.toUserCodeError()); - return SyncErrorInternal.createSyncError(details); - } -} - -extension IntEx on int { - SyncErrorCode toSyncErrorCode() => switch (this) { - realm_errno.RLM_ERR_RUNTIME => SyncErrorCode.runtimeError, - realm_errno.RLM_ERR_BAD_CHANGESET => SyncErrorCode.badChangeset, - realm_errno.RLM_ERR_BAD_SYNC_PARTITION_VALUE => SyncErrorCode.badPartitionValue, - realm_errno.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED => SyncErrorCode.protocolInvariantFailed, - realm_errno.RLM_ERR_INVALID_SUBSCRIPTION_QUERY => SyncErrorCode.invalidSubscriptionQuery, - realm_errno.RLM_ERR_SYNC_CLIENT_RESET_REQUIRED => SyncErrorCode.clientReset, - realm_errno.RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE => SyncErrorCode.invalidSchemaChange, - realm_errno.RLM_ERR_SYNC_PERMISSION_DENIED => SyncErrorCode.permissionDenied, - realm_errno.RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED => SyncErrorCode.serverPermissionsChanged, - realm_errno.RLM_ERR_SYNC_USER_MISMATCH => SyncErrorCode.userMismatch, - realm_errno.RLM_ERR_SYNC_WRITE_NOT_ALLOWED => SyncErrorCode.writeNotAllowed, - realm_errno.RLM_ERR_AUTO_CLIENT_RESET_FAILED => SyncErrorCode.autoClientResetFailed, - realm_errno.RLM_ERR_WRONG_SYNC_TYPE => SyncErrorCode.wrongSyncType, - realm_errno.RLM_ERR_SYNC_COMPENSATING_WRITE => SyncErrorCode.compensatingWrite, - _ => throw RealmError("Unknown sync error code $this"), - }; -} - -extension SyncErrorCodeEx on SyncErrorCode { - int get code => switch (this) { - SyncErrorCode.runtimeError => realm_errno.RLM_ERR_RUNTIME, - SyncErrorCode.badChangeset => realm_errno.RLM_ERR_BAD_CHANGESET, - SyncErrorCode.badPartitionValue => realm_errno.RLM_ERR_BAD_SYNC_PARTITION_VALUE, - SyncErrorCode.protocolInvariantFailed => realm_errno.RLM_ERR_SYNC_PROTOCOL_INVARIANT_FAILED, - SyncErrorCode.invalidSubscriptionQuery => realm_errno.RLM_ERR_INVALID_SUBSCRIPTION_QUERY, - SyncErrorCode.clientReset => realm_errno.RLM_ERR_SYNC_CLIENT_RESET_REQUIRED, - SyncErrorCode.invalidSchemaChange => realm_errno.RLM_ERR_SYNC_INVALID_SCHEMA_CHANGE, - SyncErrorCode.permissionDenied => realm_errno.RLM_ERR_SYNC_PERMISSION_DENIED, - SyncErrorCode.serverPermissionsChanged => realm_errno.RLM_ERR_SYNC_SERVER_PERMISSIONS_CHANGED, - SyncErrorCode.userMismatch => realm_errno.RLM_ERR_SYNC_USER_MISMATCH, - SyncErrorCode.writeNotAllowed => realm_errno.RLM_ERR_SYNC_WRITE_NOT_ALLOWED, - SyncErrorCode.autoClientResetFailed => realm_errno.RLM_ERR_AUTO_CLIENT_RESET_FAILED, - SyncErrorCode.wrongSyncType => realm_errno.RLM_ERR_WRONG_SYNC_TYPE, - SyncErrorCode.compensatingWrite => realm_errno.RLM_ERR_SYNC_COMPENSATING_WRITE, - }; -} - extension ObjectEx on Object { Pointer toPersistentHandle() { return realmLib.realm_dart_object_to_persistent_handle(this); } } -extension ListUserStateEx on List { - UserState fromIndex(int index) { - if (!UserState.values.any((value) => value.index == index)) { - throw RealmError("Unknown user state $index"); - } - - return UserState.values[index]; - } -} - extension RealmPropertyInfoEx on realm_property_info { SchemaProperty toSchemaProperty() { final linkTarget = link_target == nullptr ? null : link_target.cast().toDartString(); @@ -269,41 +156,6 @@ extension RealmPropertyInfoEx on realm_property_info { } } -extension CompleterEx on Completer { - void completeFrom(FutureOr Function() action) { - try { - complete(action()); - } catch (error, stackTrace) { - completeError(error, stackTrace); - } - } - - void completeWithAppError(Pointer error) { - final message = error.ref.message.cast().toRealmDartString()!; - final linkToLogs = error.ref.link_to_server_logs.cast().toRealmDartString(); - completeError(AppInternal.createException(message, linkToLogs, error.ref.http_status_code)); - } -} - -enum CustomErrorCode { - noError(0), - socketException(997), - unknownHttp(998), - unknown(999), - timeout(1000); - - final int code; - const CustomErrorCode(this.code); -} - -enum HttpMethod { - get, - post, - patch, - put, - delete, -} - extension RealmTimestampEx on realm_timestamp_t { DateTime toDart() { return DateTime.fromMicrosecondsSinceEpoch(seconds * _microsecondsPerSecond + nanoseconds ~/ 1000, isUtc: true); @@ -334,15 +186,6 @@ extension RealmObjectIdEx on realm_object_id { } } -extension RealmAppUserApikeyEx on realm_app_user_apikey { - ApiKey toDart() => UserInternal.createApiKey( - id.toDart(), - name.cast().toDartString(), - key.cast().toRealmDartString(treatEmptyAsNull: true), - !disabled, - ); -} - extension PlatformEx on Platform { static String fromEnvironment(String name, {String defaultValue = ""}) { final result = Platform.environment[name]; diff --git a/packages/realm_dart/lib/src/handles/native/http_transport_handle.dart b/packages/realm_dart/lib/src/handles/native/http_transport_handle.dart deleted file mode 100644 index 8a316e5b6..000000000 --- a/packages/realm_dart/lib/src/handles/native/http_transport_handle.dart +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi'; -import 'dart:io'; - -import 'package:http/http.dart'; - -import '../../logging.dart'; -import '../../realm_dart.dart'; -import 'convert_native.dart'; -import 'ffi.dart'; -import 'handle_base.dart'; -import 'realm_bindings.dart'; -import 'realm_library.dart'; -import 'scheduler_handle.dart'; - -class HttpTransportHandle extends HandleBase { - HttpTransportHandle(Pointer pointer) : super(pointer, 24); - - factory HttpTransportHandle.from(Client httpClient) { - final requestCallback = Pointer.fromFunction)>(_requestCallback); - final requestCallbackUserdata = realmLib.realm_dart_userdata_async_new(httpClient, requestCallback.cast(), schedulerHandle.pointer); - return HttpTransportHandle(realmLib.realm_http_transport_new( - realmLib.addresses.realm_dart_http_request_callback, - requestCallbackUserdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - )); - } -} - -void _requestCallback(Object userData, realm_http_request request, Pointer requestContext) { - // - // The request struct only survives until end-of-call, even though - // we explicitly call realm_http_transport_complete_request to - // mark request as completed later. - // - // Therefore we need to copy everything out of request before returning. - // We cannot clone request on the native side with realm_clone, - // since realm_http_request does not inherit from WrapC. - - final client = userData as Client; - - final timeLimit = Duration(milliseconds: request.timeout_ms); - - final url = Uri.parse(request.url.cast().toRealmDartString()!); - - final body = request.body.cast().toRealmDartString(length: request.body_size); - - final headers = {}; - for (int i = 0; i < request.num_headers; ++i) { - final header = request.headers[i]; - final name = header.name.cast().toRealmDartString()!; - final value = header.value.cast().toRealmDartString()!; - headers[name] = value; - } - - _requestCallbackAsync(client, request.method, url, body, headers, timeLimit, requestContext); - // The request struct dies here! -} - -Future _requestCallbackAsync( - Client client, - int requestMethod, - Uri url, - String? body, - Map headers, - Duration timeLimit, - Pointer requestContext, -) async { - await using((arena) async { - final responsePointer = arena(); - final responseRef = responsePointer.ref; - final method = HttpMethod.values[requestMethod]; - - try { - // Build request - final request = Request(method.name, url); - for (final header in headers.entries) { - request.headers[header.key] = header.value; - } - - if (body != null) { - request.bodyBytes = utf8.encode(body); - } - - Realm.logger.log(LogLevel.debug, "HTTP Transport: Executing ${method.name} $url"); - - final stopwatch = Stopwatch()..start(); - - // Do the call.. - final response = await client.send(request).timeout(timeLimit); - - stopwatch.stop(); - Realm.logger.log(LogLevel.debug, "HTTP Transport: Executed ${method.name} $url: ${response.statusCode} in ${stopwatch.elapsedMilliseconds} ms"); - - final responseBody = await response.stream.fold>([], (acc, l) => acc..addAll(l)); // gather response - - // Report back to core - responseRef.status_code = response.statusCode; - responseRef.body = responseBody.toCharPtr(arena); - responseRef.body_size = responseBody.length; - - int headerCnt = response.headers.length; - responseRef.headers = arena(headerCnt); - responseRef.num_headers = headerCnt; - - int index = 0; - response.headers.forEach((name, value) { - final headerRef = (responseRef.headers + index).ref; - headerRef.name = name.toCharPtr(arena); - headerRef.value = value.toCharPtr(arena); - index++; - }); - - responseRef.custom_status_code = CustomErrorCode.noError.code; - } on TimeoutException catch (timeoutEx) { - Realm.logger.log(LogLevel.warn, "HTTP Transport: TimeoutException executing ${method.name} $url: $timeoutEx"); - responseRef.custom_status_code = CustomErrorCode.timeout.code; - } on SocketException catch (socketEx) { - Realm.logger.log(LogLevel.warn, "HTTP Transport: SocketException executing ${method.name} $url: $socketEx"); - responseRef.custom_status_code = CustomErrorCode.socketException.code; - } on HttpException catch (httpEx) { - Realm.logger.log(LogLevel.warn, "HTTP Transport: HttpException executing ${method.name} $url: $httpEx"); - responseRef.custom_status_code = CustomErrorCode.unknownHttp.code; - } catch (ex) { - Realm.logger.log(LogLevel.error, "HTTP Transport: Exception executing ${method.name} $url: $ex"); - responseRef.custom_status_code = CustomErrorCode.unknown.code; - } finally { - realmLib.realm_http_transport_complete_request(requestContext, responsePointer); - } - }); -} diff --git a/packages/realm_dart/lib/src/handles/native/init.dart b/packages/realm_dart/lib/src/handles/native/init.dart index dbebc737e..e01292847 100644 --- a/packages/realm_dart/lib/src/handles/native/init.dart +++ b/packages/realm_dart/lib/src/handles/native/init.dart @@ -10,8 +10,6 @@ import 'package:path/path.dart' as p; import 'package:type_plus/type_plus.dart'; import '../../cli/common/target_os_type.dart'; -import '../../cli/metrics/metrics_command.dart'; -import '../../cli/metrics/options.dart'; import '../../realm_class.dart'; import '../../../realm.dart' show isFlutterPlatform; @@ -179,18 +177,6 @@ DynamicLibrary initRealm() { register(encodeDecimal128, decodeDecimal128); register(encodeRealmValue, decodeRealmValue); - if (!isFlutterPlatform) { - assert(() { - try { - uploadMetrics(Options( - targetOsType: Platform.operatingSystem.asTargetOsType, - targetOsVersion: Platform.operatingSystemVersion, - )); - } catch (_) {} // ignore: avoid_catching_errors - return true; - }()); - } - final realmLibrary = _openRealmLib(); final initializeApi = realmLibrary.lookupFunction), int Function(Pointer)>('realm_dart_initializeDartApiDL'); diff --git a/packages/realm_dart/lib/src/handles/native/mutable_subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/native/mutable_subscription_set_handle.dart deleted file mode 100644 index 70de535df..000000000 --- a/packages/realm_dart/lib/src/handles/native/mutable_subscription_set_handle.dart +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:ffi'; - -import 'ffi.dart'; - -import '../../realm_dart.dart'; -import 'convert_native.dart'; -import 'error_handling.dart'; -import 'realm_bindings.dart'; -import 'realm_handle.dart'; -import 'realm_library.dart'; -import 'results_handle.dart'; -import 'subscription_handle.dart'; -import 'subscription_set_handle.dart'; - -import '../mutable_subscription_set_handle.dart' as intf; - -class MutableSubscriptionSetHandle extends SubscriptionSetHandle implements intf.MutableSubscriptionSetHandle { - MutableSubscriptionSetHandle(Pointer pointer, RealmHandle root) : super(pointer.cast(), root); - - Pointer get _mutablePointer => super.pointer.cast(); - - @override - SubscriptionSetHandle commit() => SubscriptionSetHandle(realmLib.realm_sync_subscription_set_commit(_mutablePointer), root); - - @override - SubscriptionHandle insertOrAssignSubscription(covariant ResultsHandle results, String? name, bool update) { - if (!update) { - if (name != null && findByName(name) != null) { - throw RealmException('Duplicate subscription with name: $name'); - } - } - return using((arena) { - final outIndex = arena(); - final outInserted = arena(); - realmLib - .realm_sync_subscription_set_insert_or_assign_results( - _mutablePointer, - results.pointer, - name?.toCharPtr(arena) ?? nullptr, - outIndex, - outInserted, - ) - .raiseLastErrorIfFalse(); - return this[outIndex.value]; - }); - } - - @override - bool erase(covariant SubscriptionHandle subscription) { - return using((arena) { - final outErased = arena(); - realmLib - .realm_sync_subscription_set_erase_by_id( - _mutablePointer, - subscription.id.toNative(arena), - outErased, - ) - .raiseLastErrorIfFalse(); - return outErased.value; - }); - } - - @override - bool eraseByName(String name) { - return using((arena) { - final outErased = arena(); - realmLib - .realm_sync_subscription_set_erase_by_name( - _mutablePointer, - name.toCharPtr(arena), - outErased, - ) - .raiseLastErrorIfFalse(); - return outErased.value; - }); - } - - @override - bool eraseByResults(covariant ResultsHandle results) { - return using((arena) { - final outErased = arena(); - realmLib - .realm_sync_subscription_set_erase_by_results( - _mutablePointer, - results.pointer, - outErased, - ) - .raiseLastErrorIfFalse(); - return outErased.value; - }); - } - - @override - void clear() => realmLib.realm_sync_subscription_set_clear(_mutablePointer).raiseLastErrorIfFalse(); - - @override - // Workaround for weird compiler bug. This should be unnecessary, but if you - // remove this override, you get an error that the method is not implemented. - // I believe this is related to the covariant keyword in the method signature. - // ignore: unnecessary_overrides - SubscriptionHandle? findByResults(covariant ResultsHandle results) => super.findByResults(results); -} diff --git a/packages/realm_dart/lib/src/handles/native/realm_bindings.dart b/packages/realm_dart/lib/src/handles/native/realm_bindings.dart index 721dbca85..bb00e2f80 100644 --- a/packages/realm_dart/lib/src/handles/native/realm_bindings.dart +++ b/packages/realm_dart/lib/src/handles/native/realm_bindings.dart @@ -175,6 +175,10 @@ class RealmLibrary { ffi.Pointer, realm_free_userdata_func_t)>(); + /// If using App Services, the realm_sync_client_config_t instance is part of the + /// realm_app_config_t structure and this function returns a pointer to that + /// member property. The realm_sync_client_config_t reference returned by this + /// function should not be freed using realm_release. ffi.Pointer realm_app_config_get_sync_client_config( ffi.Pointer arg0, @@ -5650,6 +5654,22 @@ class RealmLibrary { late final _realm_get_object = _realm_get_objectPtr.asFunction< ffi.Pointer Function(ffi.Pointer, int, int)>(); + /// Get the schema version for this realm at the path. + int realm_get_persisted_schema_version( + ffi.Pointer config, + ) { + return _realm_get_persisted_schema_version( + config, + ); + } + + late final _realm_get_persisted_schema_versionPtr = _lookup< + ffi.NativeFunction)>>( + 'realm_get_persisted_schema_version'); + late final _realm_get_persisted_schema_version = + _realm_get_persisted_schema_versionPtr + .asFunction)>(); + /// Find a property by its column key. /// /// It is an error to pass a property @a key that is not present in this class. @@ -9378,17 +9398,6 @@ class RealmLibrary { ffi.Pointer, bool)>(); - ffi.Pointer realm_sync_client_config_new() { - return _realm_sync_client_config_new(); - } - - late final _realm_sync_client_config_newPtr = _lookup< - ffi - .NativeFunction Function()>>( - 'realm_sync_client_config_new'); - late final _realm_sync_client_config_new = _realm_sync_client_config_newPtr - .asFunction Function()>(); - void realm_sync_client_config_set_connect_timeout( ffi.Pointer arg0, int arg1, diff --git a/packages/realm_dart/lib/src/handles/native/realm_core.dart b/packages/realm_dart/lib/src/handles/native/realm_core.dart index e96c1ff15..e04f84852 100644 --- a/packages/realm_dart/lib/src/handles/native/realm_core.dart +++ b/packages/realm_dart/lib/src/handles/native/realm_core.dart @@ -1,13 +1,10 @@ // Copyright 2021 MongoDB, Inc. // SPDX-License-Identifier: Apache-2.0 -import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; -import 'package:crypto/crypto.dart'; import 'package:path/path.dart' as path; -import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:realm_dart/realm.dart'; import 'convert_native.dart'; @@ -48,11 +45,6 @@ class RealmCore implements intf.RealmCore { @override int get threadId => realmLib.realm_dart_get_thread_id(); - @override - void clearCachedApps() { - realmLib.realm_clear_cached_apps(); - } - // for debugging only. Enable in realm_dart.cpp // void invokeGC() { // realmLib.realm_dart_gc(); @@ -108,68 +100,6 @@ class RealmCore implements intf.RealmCore { } } - @override - String getBundleId() { - readBundleId() { - try { - if (!isFlutterPlatform || Platform.environment.containsKey('FLUTTER_TEST')) { - var pubspecPath = path.join(path.current, 'pubspec.yaml'); - var pubspecFile = File(pubspecPath); - - if (pubspecFile.existsSync()) { - final pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); - return pubspec.name; - } - } - - if (Platform.isAndroid) { - return realmLib.realm_dart_get_bundle_id().cast().toDartString(); - } - - final getBundleIdFunc = _pluginLib.lookupFunction Function(), Pointer Function()>("realm_dart_get_bundle_id"); - final bundleIdPtr = getBundleIdFunc(); - return bundleIdPtr.cast().toDartString(); - } on Exception catch (_) { - //Never fail on bundleId. Use fallback value. - } - - //Fallback value - return "realm_bundle_id"; - } - - String bundleId = readBundleId(); - const salt = [82, 101, 97, 108, 109, 32, 105, 115, 32, 103, 114, 101, 97, 116]; - return base64Encode(sha256.convert([...salt, ...utf8.encode(bundleId)]).bytes); - } - - @override - String getDefaultBaseUrl() { - return realmLib.realm_app_get_default_base_url().cast().toRealmDartString()!; - } - - @override - String getDeviceName() { - if (Platform.isAndroid || Platform.isIOS) { - return realmLib.realm_dart_get_device_name().cast().toRealmDartString()!; - } - - return ""; - } - - @override - String getDeviceVersion() { - if (Platform.isAndroid || Platform.isIOS) { - return realmLib.realm_dart_get_device_version().cast().toRealmDartString()!; - } - - return ""; - } - - @override - String getRealmLibraryCpuArchitecture() { - return realmLib.realm_get_library_cpu_arch().cast().toDartString(); - } - @override void loggerAttach() => realmLib.realm_dart_attach_logger(schedulerHandle.sendPort.nativePort); diff --git a/packages/realm_dart/lib/src/handles/native/realm_handle.dart b/packages/realm_dart/lib/src/handles/native/realm_handle.dart index 492882ab6..6a7a39259 100644 --- a/packages/realm_dart/lib/src/handles/native/realm_handle.dart +++ b/packages/realm_dart/lib/src/handles/native/realm_handle.dart @@ -23,8 +23,6 @@ import 'realm_library.dart'; import 'results_handle.dart'; import 'rooted_handle.dart'; import 'schema_handle.dart'; -import 'session_handle.dart'; -import 'subscription_set_handle.dart'; import '../realm_handle.dart' as intf; @@ -146,21 +144,11 @@ class RealmHandle extends HandleBase implements intf.RealmHandle { @override RealmHandle freeze() => RealmHandle(realmLib.realm_freeze(pointer)); - @override - SessionHandle getSession() { - return SessionHandle(realmLib.realm_sync_session_get(pointer), this); - } - @override bool get isFrozen { return realmLib.realm_is_frozen(pointer.cast()); } - @override - SubscriptionSetHandle get subscriptions { - return SubscriptionSetHandle(realmLib.realm_sync_get_active_subscription_set(pointer), this); - } - @override void disableAutoRefreshForTesting() { realmLib.realm_set_auto_refresh(pointer, false); @@ -427,9 +415,6 @@ class RealmHandle extends HandleBase implements intf.RealmHandle { case ObjectType.embeddedObject: type = EmbeddedObject; break; - case ObjectType.asymmetricObject: - type = AsymmetricObject; - break; default: throw RealmError('$baseType is not supported yet'); } diff --git a/packages/realm_dart/lib/src/handles/native/session_handle.dart b/packages/realm_dart/lib/src/handles/native/session_handle.dart deleted file mode 100644 index 9ce60d04b..000000000 --- a/packages/realm_dart/lib/src/handles/native/session_handle.dart +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:ffi'; - -import 'package:cancellation_token/cancellation_token.dart'; - -import '../../realm_dart.dart'; -import '../../session.dart'; -import '../session_handle.dart' as intf; -import 'convert_native.dart'; -import 'ffi.dart'; -import 'handle_base.dart'; -import 'realm_bindings.dart'; -import 'realm_handle.dart'; -import 'realm_library.dart'; -import 'rooted_handle.dart'; -import 'scheduler_handle.dart'; -import 'user_handle.dart'; - -class SessionHandle extends RootedHandleBase implements intf.SessionHandle { - @override - bool get shouldRoot => true; - - SessionHandle(Pointer pointer, RealmHandle root) : super(root, pointer, 24); - - @override - String get path { - return realmLib.realm_sync_session_get_file_path(pointer).cast().toRealmDartString()!; - } - - @override - ConnectionState get connectionState { - final value = realmLib.realm_sync_session_get_connection_state(pointer); - return ConnectionState.values[value]; - } - - @override - UserHandle get user { - return UserHandle(realmLib.realm_sync_session_get_user(pointer)); - } - - @override - SessionState get state { - final value = realmLib.realm_sync_session_get_state(pointer); - return _convertCoreSessionState(value); - } - - SessionState _convertCoreSessionState(int value) { - switch (value) { - case 0: // RLM_SYNC_SESSION_STATE_ACTIVE - case 1: // RLM_SYNC_SESSION_STATE_DYING - return SessionState.active; - case 2: // RLM_SYNC_SESSION_STATE_INACTIVE - case 3: // RLM_SYNC_SESSION_STATE_WAITING_FOR_ACCESS_TOKEN - case 4: // RLM_SYNC_SESSION_STATE_PAUSED - return SessionState.inactive; - default: - throw Exception("Unexpected SessionState: $value"); - } - } - - @override - void pause() { - realmLib.realm_sync_session_pause(pointer); - } - - @override - void resume() { - realmLib.realm_sync_session_resume(pointer); - } - - @override - void raiseError(int errorCode, bool isFatal) { - using((arena) { - final message = "Simulated session error".toCharPtr(arena); - realmLib.realm_sync_session_handle_error_for_testing(pointer, errorCode, message, isFatal); - }); - } - - @override - Future waitForUpload([CancellationToken? cancellationToken]) { - final completer = CancellableCompleter(cancellationToken); - if (!completer.isCancelled) { - final callback = Pointer.fromFunction)>(_waitCompletionCallback); - final userdata = realmLib.realm_dart_userdata_async_new(completer, callback.cast(), schedulerHandle.pointer); - realmLib.realm_sync_session_wait_for_upload_completion( - pointer, - realmLib.addresses.realm_dart_sync_wait_for_completion_callback, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ); - } - return completer.future; - } - - @override - Future waitForDownload([CancellationToken? cancellationToken]) { - final completer = CancellableCompleter(cancellationToken); - if (!completer.isCancelled) { - final callback = Pointer.fromFunction)>(_waitCompletionCallback); - final userdata = realmLib.realm_dart_userdata_async_new(completer, callback.cast(), schedulerHandle.pointer); - realmLib.realm_sync_session_wait_for_download_completion( - pointer, - realmLib.addresses.realm_dart_sync_wait_for_completion_callback, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ); - } - return completer.future; - } - - static void _waitCompletionCallback(Object userdata, Pointer errorCode) { - final completer = userdata as CancellableCompleter; - if (completer.isCancelled) { - return; - } - if (errorCode != nullptr) { - // Throw RealmException instead of RealmError to be recoverable by the user. - completer.completeError(RealmException(errorCode.toDart().toString())); - } else { - completer.complete(); - } - } - - @override - SyncSessionNotificationTokenHandle subscribeForConnectionStateNotifications(SessionConnectionStateController controller) { - final callback = Pointer.fromFunction(_onConnectionStateChange); - final userdata = realmLib.realm_dart_userdata_async_new(controller, callback.cast(), schedulerHandle.pointer); - return SyncSessionNotificationTokenHandle( - realmLib.realm_sync_session_register_connection_state_change_callback( - pointer, - realmLib.addresses.realm_dart_sync_connection_state_changed_callback, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ), - ); - } - - @override - SyncSessionNotificationTokenHandle subscribeForProgressNotifications( - ProgressDirection direction, - ProgressMode mode, - SessionProgressNotificationsController controller, - ) { - final isStreaming = mode == ProgressMode.reportIndefinitely; - final callback = Pointer.fromFunction(syncProgressCallback); - final userdata = realmLib.realm_dart_userdata_async_new(controller, callback.cast(), schedulerHandle.pointer); - return SyncSessionNotificationTokenHandle( - realmLib.realm_sync_session_register_progress_notifier( - pointer, - realmLib.addresses.realm_dart_sync_progress_callback, - direction.index, - isStreaming, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ), - ); - } -} - -class SyncSessionNotificationTokenHandle extends HandleBase - implements intf.SyncSessionNotificationTokenHandle { - SyncSessionNotificationTokenHandle(Pointer pointer) : super(pointer, 32); -} - -void _onConnectionStateChange(Object userdata, int oldState, int newState) { - final controller = userdata as SessionConnectionStateController; - - controller.onConnectionStateChange(ConnectionState.values[oldState], ConnectionState.values[newState]); -} - -void syncProgressCallback(Object userdata, int transferred, int transferable, double estimate) { - final controller = userdata as ProgressNotificationsController; - - controller.onProgress(estimate); -} diff --git a/packages/realm_dart/lib/src/handles/native/subscription_handle.dart b/packages/realm_dart/lib/src/handles/native/subscription_handle.dart deleted file mode 100644 index b2b6b4fed..000000000 --- a/packages/realm_dart/lib/src/handles/native/subscription_handle.dart +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:ffi'; - -import '../../realm_class.dart'; -import 'from_native.dart'; -import 'handle_base.dart'; -import 'realm_bindings.dart'; -import 'realm_library.dart'; - -import '../subscription_handle.dart' as intf; -class SubscriptionHandle extends HandleBase implements intf.SubscriptionHandle{ - SubscriptionHandle(Pointer pointer) : super(pointer, 184); - - @override - ObjectId get id => realmLib.realm_sync_subscription_id(pointer).toDart(); - - @override - String? get name => realmLib.realm_sync_subscription_name(pointer).toDart(); - - @override - String get objectClassName => realmLib.realm_sync_subscription_object_class_name(pointer).toDart()!; - - @override - String get queryString => realmLib.realm_sync_subscription_query_string(pointer).toDart()!; - - @override - DateTime get createdAt => realmLib.realm_sync_subscription_created_at(pointer).toDart(); - - @override - DateTime get updatedAt => realmLib.realm_sync_subscription_updated_at(pointer).toDart(); - - @override - bool equalTo(covariant SubscriptionHandle other) => realmLib.realm_equals(pointer.cast(), other.pointer.cast()); -} diff --git a/packages/realm_dart/lib/src/handles/native/subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/native/subscription_set_handle.dart deleted file mode 100644 index 271291913..000000000 --- a/packages/realm_dart/lib/src/handles/native/subscription_set_handle.dart +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:ffi'; - -import 'package:cancellation_token/cancellation_token.dart'; - -import '../../realm_dart.dart'; -import '../subscription_set_handle.dart' as intf; -import 'convert.dart'; -import 'convert_native.dart'; -import 'error_handling.dart'; -import 'ffi.dart'; -import 'mutable_subscription_set_handle.dart'; -import 'realm_bindings.dart'; -import 'realm_handle.dart'; -import 'realm_library.dart'; -import 'results_handle.dart'; -import 'rooted_handle.dart'; -import 'scheduler_handle.dart'; -import 'subscription_handle.dart'; -class SubscriptionSetHandle extends RootedHandleBase implements intf.SubscriptionSetHandle { - @override - bool get shouldRoot => true; - - SubscriptionSetHandle(Pointer pointer, RealmHandle root) : super(root, pointer, 128); - - @override - void refresh() => realmLib.realm_sync_subscription_set_refresh(pointer).raiseLastErrorIfFalse(); - - @override - int get size => realmLib.realm_sync_subscription_set_size(pointer); - - @override - Exception? get error { - final error = realmLib.realm_sync_subscription_set_error_str(pointer); - final message = error.cast().toRealmDartString(treatEmptyAsNull: true); - return message.convert(RealmException.new); - } - - @override - SubscriptionHandle operator [](int index) => SubscriptionHandle(realmLib.realm_sync_subscription_at(pointer, index)); - - @override - SubscriptionHandle? findByName(String name) { - return using((arena) { - final result = realmLib.realm_sync_find_subscription_by_name( - pointer, - name.toCharPtr(arena), - ); - return result.convert(SubscriptionHandle.new); - }); - } - - @override - SubscriptionHandle? findByResults(covariant ResultsHandle results) { - final result = realmLib.realm_sync_find_subscription_by_results( - pointer, - results.pointer, - ); - return result.convert(SubscriptionHandle.new); - } - - @override - int get version => realmLib.realm_sync_subscription_set_version(pointer); - - @override - SubscriptionSetState get state => SubscriptionSetState.values[realmLib.realm_sync_subscription_set_state(pointer)]; - - @override - MutableSubscriptionSetHandle toMutable() => MutableSubscriptionSetHandle(realmLib.realm_sync_make_subscription_set_mutable(pointer), root); - - static void _stateChangeCallback(Object userdata, int state) { - final completer = userdata as CancellableCompleter; - if (!completer.isCancelled) { - completer.complete(SubscriptionSetState.values[state]); - } - } - - @override - Future waitForStateChange(SubscriptionSetState notifyWhen, [CancellationToken? cancellationToken]) { - final completer = CancellableCompleter(cancellationToken); - if (!completer.isCancelled) { - final callback = Pointer.fromFunction(_stateChangeCallback); - final userdata = realmLib.realm_dart_userdata_async_new(completer, callback.cast(), schedulerHandle.pointer); - realmLib.realm_sync_on_subscription_set_state_change_async(pointer, notifyWhen.index, - realmLib.addresses.realm_dart_sync_on_subscription_state_changed_callback, userdata.cast(), realmLib.addresses.realm_dart_userdata_async_free); - } - return completer.future; - } -} diff --git a/packages/realm_dart/lib/src/handles/native/user_handle.dart b/packages/realm_dart/lib/src/handles/native/user_handle.dart deleted file mode 100644 index 643f8b20b..000000000 --- a/packages/realm_dart/lib/src/handles/native/user_handle.dart +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi'; - -import '../../credentials.dart'; -import '../../realm_dart.dart'; -import '../../user.dart'; -import 'app_handle.dart'; -import 'convert.dart'; -import 'convert_native.dart'; -import 'credentials_handle.dart'; -import 'error_handling.dart'; -import 'ffi.dart'; -import 'handle_base.dart'; -import 'realm_bindings.dart'; -import 'realm_library.dart'; -import 'scheduler_handle.dart'; - -import '../user_handle.dart' as intf; - -class UserHandle extends HandleBase implements intf.UserHandle { - UserHandle(Pointer pointer) : super(pointer, 24); - - @override - AppHandle get app { - return realmLib.realm_user_get_app(pointer).convert(AppHandle.new) ?? - (throw RealmException('User does not have an associated app. This is likely due to the user being logged out.')); - } - - @override - UserState get state { - final nativeUserState = realmLib.realm_user_get_state(pointer); - return UserState.values.fromIndex(nativeUserState); - } - - @override - String get id { - final idPtr = realmLib.realm_user_get_identity(pointer).raiseLastErrorIfNull(); - final userId = idPtr.cast().toDartString(); - return userId; - } - - @override - List get identities { - return using((arena) { - return _userGetIdentities(arena); - }); - } - - List _userGetIdentities(Arena arena, {int expectedSize = 2}) { - final actualCount = arena(); - final identitiesPtr = arena(expectedSize); - realmLib.realm_user_get_all_identities(pointer, identitiesPtr, expectedSize, actualCount).raiseLastErrorIfFalse(); - - if (expectedSize < actualCount.value) { - // The supplied array was too small - resize it - arena.free(identitiesPtr); - return _userGetIdentities(arena, expectedSize: actualCount.value); - } - - final result = []; - for (var i = 0; i < actualCount.value; i++) { - final identity = (identitiesPtr + i).ref; - - result.add(UserIdentityInternal.create( - identity.id.cast().toRealmDartString(freeRealmMemory: true)!, AuthProviderTypeInternal.getByValue(identity.provider_type))); - } - - return result; - } - - @override - Future logOut() async { - realmLib.realm_user_log_out(pointer).raiseLastErrorIfFalse(); - } - - @override - String? get deviceId { - final deviceId = realmLib.realm_user_get_device_id(pointer).raiseLastErrorIfNull(); - return deviceId.cast().toRealmDartString(treatEmptyAsNull: true, freeRealmMemory: true); - } - - @override - UserProfile get profileData { - final data = realmLib.realm_user_get_profile_data(pointer).raiseLastErrorIfNull(); - final dynamic profileData = jsonDecode(data.cast().toRealmDartString(freeRealmMemory: true)!); - return UserProfile(profileData as Map); - } - - @override - String get refreshToken { - final token = realmLib.realm_user_get_refresh_token(pointer).raiseLastErrorIfNull(); - return token.cast().toRealmDartString(freeRealmMemory: true)!; - } - - @override - String get accessToken { - final token = realmLib.realm_user_get_access_token(pointer).raiseLastErrorIfNull(); - return token.cast().toRealmDartString(freeRealmMemory: true)!; - } - - @override - String get path { - final syncConfigPtr = realmLib.realm_flx_sync_config_new(pointer).raiseLastErrorIfNull(); - try { - final path = realmLib.realm_app_sync_client_get_default_file_path_for_realm(syncConfigPtr, nullptr); - return path.cast().toRealmDartString(freeRealmMemory: true)!; - } finally { - realmLib.realm_release(syncConfigPtr.cast()); - } - } - - @override - String? get customData { - final customDataPtr = realmLib.realm_user_get_custom_data(pointer); - return customDataPtr.cast().toRealmDartString(freeRealmMemory: true, treatEmptyAsNull: true); - } - - @override - Future linkCredentials(covariant AppHandle app, covariant CredentialsHandle credentials) { - final completer = Completer(); - realmLib - .realm_app_link_user( - app.pointer, - pointer, - credentials.pointer, - realmLib.addresses.realm_dart_user_completion_callback, - createAsyncUserCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - return completer.future; - } - - @override - Future createApiKey(covariant AppHandle app, String name) { - return using((arena) { - final namePtr = name.toCharPtr(arena); - final completer = Completer(); - realmLib - .realm_app_user_apikey_provider_client_create_apikey( - app.pointer, - pointer, - namePtr, - realmLib.addresses.realm_dart_apikey_callback, - _createAsyncApikeyCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - Future fetchApiKey(covariant AppHandle app, ObjectId id) { - return using((arena) { - final completer = Completer(); - final nativeId = id.toNative(arena); - realmLib - .realm_app_user_apikey_provider_client_fetch_apikey( - app.pointer, - pointer, - nativeId.ref, - realmLib.addresses.realm_dart_apikey_callback, - _createAsyncApikeyCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - Future> fetchAllApiKeys(covariant AppHandle app) { - return using((arena) { - final completer = Completer>(); - realmLib - .realm_app_user_apikey_provider_client_fetch_apikeys( - app.pointer, - pointer, - realmLib.addresses.realm_dart_apikey_list_callback, - _createAsyncApikeyListCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - Future deleteApiKey(covariant AppHandle app, ObjectId id) { - return using((arena) { - final completer = Completer(); - final nativeId = id.toNative(arena); - realmLib - .realm_app_user_apikey_provider_client_delete_apikey( - app.pointer, - pointer, - nativeId.ref, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - Future disableApiKey(covariant AppHandle app, ObjectId objectId) { - return using((arena) { - final completer = Completer(); - final nativeId = objectId.toNative(arena); - - realmLib - .realm_app_user_apikey_provider_client_disable_apikey( - app.pointer, - pointer, - nativeId.ref, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - Future enableApiKey(covariant AppHandle app, ObjectId objectId) { - return using((arena) { - final completer = Completer(); - final nativeId = objectId.toNative(arena); - - realmLib - .realm_app_user_apikey_provider_client_enable_apikey( - app.pointer, - pointer, - nativeId.ref, - realmLib.addresses.realm_dart_void_completion_callback, - createAsyncCallbackUserdata(completer), - realmLib.addresses.realm_dart_userdata_async_free, - ) - .raiseLastErrorIfFalse(); - - return completer.future; - }); - } - - @override - UserNotificationTokenHandle subscribeForNotifications(UserNotificationsController controller) { - final callback = Pointer.fromFunction(_userChangeCallback); - final userdata = realmLib.realm_dart_userdata_async_new(controller, callback.cast(), schedulerHandle.pointer); - final notificationToken = realmLib.realm_sync_user_on_state_change_register_callback( - pointer, - realmLib.addresses.realm_dart_user_change_callback, - userdata.cast(), - realmLib.addresses.realm_dart_userdata_async_free, - ); - return UserNotificationTokenHandle(notificationToken); - } -} - -class UserNotificationTokenHandle extends HandleBase implements intf.UserNotificationTokenHandle { - UserNotificationTokenHandle(Pointer pointer) : super(pointer, 32); -} - -void _userChangeCallback(Object userdata, int data) { - final controller = userdata as UserNotificationsController; - - controller.onUserChanged(); -} - -Pointer createAsyncUserCallbackUserdata(Completer completer) { - final callback = Pointer.fromFunction< - Void Function( - Pointer, - Pointer, - Pointer, - )>(_appUserCompletionCallback); - - final userdata = realmLib.realm_dart_userdata_async_new( - completer, - callback.cast(), - schedulerHandle.pointer, - ); - - return userdata.cast(); -} - -void _appUserCompletionCallback(Pointer userdata, Pointer user, Pointer error) { - final Completer completer = userdata.toObject(); - - if (error != nullptr) { - completer.completeWithAppError(error); - return; - } - - user = realmLib.realm_clone(user.cast()).cast(); // take an extra reference to the user object - if (user == nullptr) { - completer.completeError(RealmException("Error while cloning user object.")); - return; - } - - completer.complete(UserHandle(user.cast())); -} - -Pointer _createAsyncApikeyCallbackUserdata(Completer completer) { - final callback = Pointer.fromFunction< - Void Function( - Pointer, - Pointer, - Pointer, - )>(_appApiKeyCompletionCallback); - - final userdata = realmLib.realm_dart_userdata_async_new( - completer, - callback.cast(), - schedulerHandle.pointer, - ); - - return userdata.cast(); -} - -void _appApiKeyCompletionCallback(Pointer userdata, Pointer apiKey, Pointer error) { - final Completer completer = userdata.toObject(); - if (error != nullptr) { - completer.completeWithAppError(error); - return; - } - completer.complete(apiKey.ref.toDart()); -} - -Pointer _createAsyncApikeyListCallbackUserdata(Completer> completer) { - final callback = Pointer.fromFunction< - Void Function( - Pointer, - Pointer, - Size count, - Pointer, - )>(_appApiKeyArrayCompletionCallback); - - final userdata = realmLib.realm_dart_userdata_async_new( - completer, - callback.cast(), - schedulerHandle.pointer, - ); - - return userdata.cast(); -} - -void _appApiKeyArrayCompletionCallback(Pointer userdata, Pointer apiKey, int size, Pointer error) { - final Completer> completer = userdata.toObject(); - - if (error != nullptr) { - completer.completeWithAppError(error); - return; - } - - final result = []; - for (var i = 0; i < size; i++) { - result.add(apiKey[i].toDart()); - } - - completer.complete(result); -} diff --git a/packages/realm_dart/lib/src/handles/realm_core.dart b/packages/realm_dart/lib/src/handles/realm_core.dart index 169db13c3..09a5f50cc 100644 --- a/packages/realm_dart/lib/src/handles/realm_core.dart +++ b/packages/realm_dart/lib/src/handles/realm_core.dart @@ -8,15 +8,7 @@ import 'native/realm_core.dart' if (dart.library.js_interop) 'web/realm_core.dar abstract interface class RealmCore { int get threadId; - void clearCachedApps(); - String getAppDirectory(); - String getBundleId(); - String getDeviceName(); - String getDeviceVersion(); - String getRealmLibraryCpuArchitecture(); - - String getDefaultBaseUrl(); void loggerAttach(); void loggerDetach(); diff --git a/packages/realm_dart/lib/src/handles/realm_handle.dart b/packages/realm_dart/lib/src/handles/realm_handle.dart index 9aabcd81b..dc900ae40 100644 --- a/packages/realm_dart/lib/src/handles/realm_handle.dart +++ b/packages/realm_dart/lib/src/handles/realm_handle.dart @@ -7,8 +7,6 @@ import 'handle_base.dart'; import 'object_handle.dart'; import 'results_handle.dart'; import 'schema_handle.dart'; -import 'session_handle.dart'; -import 'subscription_set_handle.dart'; import 'native/realm_handle.dart' if (dart.library.js_interop) 'web/realm_handle.dart' as impl; @@ -31,11 +29,8 @@ abstract interface class RealmHandle extends HandleBase { void writeCopy(Configuration config); ResultsHandle queryClass(int classKey, String query, List args); RealmHandle freeze(); - SessionHandle getSession(); bool get isFrozen; - SubscriptionSetHandle get subscriptions; - void disableAutoRefreshForTesting(); void close(); diff --git a/packages/realm_dart/lib/src/handles/session_handle.dart b/packages/realm_dart/lib/src/handles/session_handle.dart deleted file mode 100644 index f5c3aeb15..000000000 --- a/packages/realm_dart/lib/src/handles/session_handle.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:cancellation_token/cancellation_token.dart'; - -import '../session.dart'; -import 'handle_base.dart'; -import 'user_handle.dart'; - -abstract interface class SessionHandle extends HandleBase { - String get path; - ConnectionState get connectionState; - - UserHandle get user; - - SessionState get state; - - void pause(); - - void resume(); - - void raiseError(int errorCode, bool isFatal); - - Future waitForUpload([CancellationToken? cancellationToken]); - Future waitForDownload([CancellationToken? cancellationToken]); - SyncSessionNotificationTokenHandle subscribeForConnectionStateNotifications(SessionConnectionStateController controller); - - SyncSessionNotificationTokenHandle subscribeForProgressNotifications( - ProgressDirection direction, - ProgressMode mode, - SessionProgressNotificationsController controller, - ); -} - -abstract interface class SyncSessionNotificationTokenHandle extends HandleBase {} \ No newline at end of file diff --git a/packages/realm_dart/lib/src/handles/subscription_handle.dart b/packages/realm_dart/lib/src/handles/subscription_handle.dart deleted file mode 100644 index 7f3cc40e9..000000000 --- a/packages/realm_dart/lib/src/handles/subscription_handle.dart +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:realm_common/realm_common.dart'; - -import 'handle_base.dart'; - -abstract interface class SubscriptionHandle extends HandleBase { - ObjectId get id; - String? get name; - String get objectClassName; - String get queryString; - DateTime get createdAt; - DateTime get updatedAt; - bool equalTo(SubscriptionHandle other); -} diff --git a/packages/realm_dart/lib/src/handles/subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/subscription_set_handle.dart deleted file mode 100644 index 82a2e1abe..000000000 --- a/packages/realm_dart/lib/src/handles/subscription_set_handle.dart +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:cancellation_token/cancellation_token.dart'; - -import '../subscription.dart'; -import 'handle_base.dart'; -import 'mutable_subscription_set_handle.dart'; -import 'results_handle.dart'; -import 'subscription_handle.dart'; - -abstract class SubscriptionSetHandle extends HandleBase { - void refresh(); - - int get size; - - Exception? get error; - - SubscriptionHandle operator [](int index); - - SubscriptionHandle? findByName(String name); - - SubscriptionHandle? findByResults(ResultsHandle results); - - int get version; - SubscriptionSetState get state; - - MutableSubscriptionSetHandle toMutable(); - - Future waitForStateChange(SubscriptionSetState notifyWhen, [CancellationToken? cancellationToken]); -} diff --git a/packages/realm_dart/lib/src/handles/user_handle.dart b/packages/realm_dart/lib/src/handles/user_handle.dart deleted file mode 100644 index cf498b10f..000000000 --- a/packages/realm_dart/lib/src/handles/user_handle.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:realm_common/realm_common.dart'; - -import '../user.dart'; -import 'app_handle.dart'; -import 'credentials_handle.dart'; -import 'handle_base.dart'; - -abstract interface class UserHandle extends HandleBase { - AppHandle get app; - UserState get state; - String get id; - List get identities; - Future logOut(); - String? get deviceId; - UserProfile get profileData; - String get refreshToken; - String get accessToken; - String get path; - String? get customData; - Future linkCredentials(AppHandle app, CredentialsHandle credentials); - Future createApiKey(AppHandle app, String name); - Future fetchApiKey(AppHandle app, ObjectId id); - Future> fetchAllApiKeys(AppHandle app); - Future deleteApiKey(AppHandle app, ObjectId id); - Future disableApiKey(AppHandle app, ObjectId objectId); - Future enableApiKey(AppHandle app, ObjectId objectId); - UserNotificationTokenHandle subscribeForNotifications(UserNotificationsController controller); -} - -abstract interface class UserNotificationTokenHandle extends HandleBase {} diff --git a/packages/realm_dart/lib/src/handles/web/app_handle.dart b/packages/realm_dart/lib/src/handles/web/app_handle.dart deleted file mode 100644 index 9a20302be..000000000 --- a/packages/realm_dart/lib/src/handles/web/app_handle.dart +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../../../realm.dart'; -import '../app_handle.dart' as intf; -import 'handle_base.dart'; - -class AppHandle extends HandleBase implements intf.AppHandle { - factory AppHandle.from(AppConfiguration configuration) => webNotSupported(); - static AppHandle? get(String id, String? baseUrl) => webNotSupported(); -} diff --git a/packages/realm_dart/lib/src/handles/web/async_open_task_handle.dart b/packages/realm_dart/lib/src/handles/web/async_open_task_handle.dart deleted file mode 100644 index 35d716b51..000000000 --- a/packages/realm_dart/lib/src/handles/web/async_open_task_handle.dart +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:realm_dart/realm.dart'; - -import '../async_open_task_handle.dart' as intf; -import 'handle_base.dart'; - -class AsyncOpenTaskHandle extends HandleBase implements intf.AsyncOpenTaskHandle { - factory AsyncOpenTaskHandle.from(FlexibleSyncConfiguration config) => webNotSupported(); - - @override - noSuchMethod(Invocation invocation) => webNotSupported(); -} - -abstract class AsyncOpenTaskProgressNotificationTokenHandle implements intf.AsyncOpenTaskProgressNotificationTokenHandle { - @override - noSuchMethod(Invocation invocation) => webNotSupported(); -} diff --git a/packages/realm_dart/lib/src/handles/web/credentials_handle.dart b/packages/realm_dart/lib/src/handles/web/credentials_handle.dart deleted file mode 100644 index e68f5484d..000000000 --- a/packages/realm_dart/lib/src/handles/web/credentials_handle.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../credentials_handle.dart' as intf; -import 'handle_base.dart'; - -class CredentialsHandle extends HandleBase implements intf.CredentialsHandle { - factory CredentialsHandle.anonymous(bool reuseCredentials) => webNotSupported(); - - factory CredentialsHandle.emailPassword(String email, String password) => webNotSupported(); - - factory CredentialsHandle.jwt(String token) => webNotSupported(); - - factory CredentialsHandle.apple(String idToken) => webNotSupported(); - - factory CredentialsHandle.facebook(String accessToken) => webNotSupported(); - - factory CredentialsHandle.googleIdToken(String idToken) => webNotSupported(); - - factory CredentialsHandle.googleAuthCode(String authCode) => webNotSupported(); - - factory CredentialsHandle.function(String payload) => webNotSupported(); - - factory CredentialsHandle.apiKey(String key) => webNotSupported(); -} diff --git a/packages/realm_dart/lib/src/handles/web/mutable_subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/web/mutable_subscription_set_handle.dart deleted file mode 100644 index 05e98f401..000000000 --- a/packages/realm_dart/lib/src/handles/web/mutable_subscription_set_handle.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../mutable_subscription_set_handle.dart' as intf; -import 'handle_base.dart'; - -class MutableSubscriptionSetHandle extends HandleBase implements intf.MutableSubscriptionSetHandle {} diff --git a/packages/realm_dart/lib/src/handles/web/session_handle.dart b/packages/realm_dart/lib/src/handles/web/session_handle.dart deleted file mode 100644 index f6b74bee0..000000000 --- a/packages/realm_dart/lib/src/handles/web/session_handle.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../session_handle.dart' as intf; -import 'handle_base.dart'; - -class SessionHandle extends HandleBase implements intf.SessionHandle {} diff --git a/packages/realm_dart/lib/src/handles/web/subscription_handle.dart b/packages/realm_dart/lib/src/handles/web/subscription_handle.dart deleted file mode 100644 index df3212a92..000000000 --- a/packages/realm_dart/lib/src/handles/web/subscription_handle.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../subscription_handle.dart' as intf; -import 'handle_base.dart'; - -class SubscriptionHandle extends HandleBase implements intf.SubscriptionHandle {} diff --git a/packages/realm_dart/lib/src/handles/web/subscription_set_handle.dart b/packages/realm_dart/lib/src/handles/web/subscription_set_handle.dart deleted file mode 100644 index 20508d1b7..000000000 --- a/packages/realm_dart/lib/src/handles/web/subscription_set_handle.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../subscription_set_handle.dart' as intf; -import 'handle_base.dart'; - -class SubscriptionSetHandle extends HandleBase implements intf.SubscriptionSetHandle {} diff --git a/packages/realm_dart/lib/src/handles/web/user_handle.dart b/packages/realm_dart/lib/src/handles/web/user_handle.dart deleted file mode 100644 index a0e0638c0..000000000 --- a/packages/realm_dart/lib/src/handles/web/user_handle.dart +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import '../user_handle.dart' as intf; -import 'handle_base.dart'; - -class UserHandle extends HandleBase implements intf.UserHandle {} diff --git a/packages/realm_dart/lib/src/logging.dart b/packages/realm_dart/lib/src/logging.dart index 1555ca062..ed1428cf1 100644 --- a/packages/realm_dart/lib/src/logging.dart +++ b/packages/realm_dart/lib/src/logging.dart @@ -12,20 +12,12 @@ sealed class LogCategory { /// All possible log categories. static final values = [ realm, - realm.app, realm.sdk, realm.storage, realm.storage.notification, realm.storage.object, realm.storage.query, realm.storage.transaction, - realm.sync, - realm.sync.client, - realm.sync.client.changeset, - realm.sync.client.network, - realm.sync.client.reset, - realm.sync.client.session, - realm.sync.server, ]; /// The root category for all log messages from the Realm SDK. @@ -68,26 +60,8 @@ class _LeafLogCategory extends LogCategory { class _RealmLogCategory extends LogCategory { _RealmLogCategory() : super._('Realm', null); - late final app = _LeafLogCategory('App', this); late final sdk = _LeafLogCategory('SDK', this); late final storage = _StorageLogCategory(this); - late final sync = _SyncLogCategory(this); -} - -class _SyncLogCategory extends LogCategory { - _SyncLogCategory(LogCategory parent) : super._('Sync', parent); - - late final client = _ClientLogCategory(this); - late final server = _LeafLogCategory('Server', this); -} - -class _ClientLogCategory extends LogCategory { - _ClientLogCategory(LogCategory parent) : super._('Client', parent); - - late final changeset = _LeafLogCategory('Changeset', this); - late final network = _LeafLogCategory('Network', this); - late final reset = _LeafLogCategory('Reset', this); - late final session = _LeafLogCategory('Session', this); } class _StorageLogCategory extends LogCategory { @@ -100,15 +74,15 @@ class _StorageLogCategory extends LogCategory { } /// Specifies the criticality level above which messages will be logged -/// by the default sync client logger. +/// by the default client logger. /// {@category Realm} enum LogLevel { /// Log everything. This will seriously harm the performance of the - /// sync client and should never be used in production scenarios. + /// database and should never be used in production scenarios. all(Level.ALL), /// A version of [debug] that allows for very high volume output. - /// This may seriously affect the performance of the sync client. + /// This may seriously affect the performance of the database. trace(Level.FINEST), /// Reveal information that can aid debugging, no longer paying @@ -118,7 +92,7 @@ enum LogLevel { /// Same as [info], but prioritize completeness over minimalism. detail(Level.FINE), - /// Log operational sync client messages, but in a minimalist fashion to + /// Log operational database messages, but in a minimalist fashion to /// avoid general overhead from logging and to keep volume down. info(Level.INFO), diff --git a/packages/realm_dart/lib/src/realm_class.dart b/packages/realm_dart/lib/src/realm_class.dart index aa2c6b787..20037b252 100644 --- a/packages/realm_dart/lib/src/realm_class.dart +++ b/packages/realm_dart/lib/src/realm_class.dart @@ -9,7 +9,6 @@ import 'package:collection/collection.dart'; import 'package:realm_common/realm_common.dart'; import 'configuration.dart'; -import 'handles/async_open_task_handle.dart'; import 'handles/handle_base.dart'; import 'handles/list_handle.dart'; import 'handles/map_handle.dart'; @@ -24,9 +23,7 @@ import 'map.dart'; import 'realm_object.dart'; import 'results.dart'; import 'scheduler.dart'; -import 'session.dart'; import 'set.dart'; -import 'subscription.dart'; export 'package:cancellation_token/cancellation_token.dart' show CancellationToken, TimeoutCancellationToken, CancelledException; export 'package:realm_common/realm_common.dart' @@ -59,35 +56,18 @@ export 'package:realm_common/realm_common.dart' Uuid; // always expose with `show` to explicitly control the public API surface -export 'app.dart' show AppException, App, MetadataPersistenceMode, AppConfiguration, SyncTimeoutOptions; export 'collections.dart' show Move; export "configuration.dart" show encryptionKeySize, - AfterResetCallback, - BeforeResetCallback, - ClientResetCallback, - ClientResetError, - ClientResetHandler, - CompensatingWriteError, - CompensatingWriteInfo, Configuration, - DiscardUnsyncedChangesHandler, - DisconnectedSyncConfiguration, - FlexibleSyncConfiguration, InitialDataCallback, InMemoryConfiguration, LocalConfiguration, - ManualRecoveryHandler, MigrationCallback, RealmSchema, - RecoverOrDiscardUnsyncedChangesHandler, - RecoverUnsyncedChangesHandler, SchemaObject, - ShouldCompactCallback, - SyncError, - SyncErrorHandler; -export 'credentials.dart' show AuthProviderType, Credentials, EmailPasswordAuthProvider; + ShouldCompactCallback; export 'handles/decimal128.dart' show Decimal128; export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges, ListExtension; export 'logging.dart' hide RealmLoggerInternal; @@ -95,7 +75,6 @@ export 'map.dart' show RealmMap, RealmMapChanges, RealmMapOfObject; export 'migration.dart' show Migration; export 'realm_object.dart' show - AsymmetricObject, DynamicRealmObject, EmbeddedObject, EmbeddedObjectExtension, @@ -106,11 +85,8 @@ export 'realm_object.dart' RealmObjectChanges, UserCallbackException; export 'realm_property.dart'; -export 'results.dart' show RealmResultsOfObject, RealmResultsChanges, RealmResults, WaitForSyncMode, RealmResultsOfRealmObject; -export 'session.dart' show ConnectionStateChange, SyncProgress, ProgressDirection, ProgressMode, ConnectionState, Session, SessionState, SyncErrorCode; +export 'results.dart' show RealmResultsOfObject, RealmResultsChanges, RealmResults, WaitForSyncMode; export 'set.dart' show RealmSet, RealmSetChanges, RealmSetOfObject; -export 'subscription.dart' show Subscription, SubscriptionSet, SubscriptionSetState, MutableSubscriptionSet; -export 'user.dart' show User, UserState, ApiKeyClient, UserIdentity, ApiKey, FunctionsClient, UserChanges; /// A [Realm] instance represents a `Realm` database. /// @@ -143,11 +119,11 @@ class Realm { Realm._(this.config, [RealmHandle? handle, this._isInMigration = false]) : _handle = handle ?? _openRealm(config) { _populateMetadata(); - // The schema of a Realm file may change due to sync adding new properties/classes. We subscribe for notifications + // The schema of a Realm file may change due to another process adding new properties/classes. We subscribe for notifications // in order to update the managed schema instance in case this happens. The same is true for dynamic Realms. For // local Realms with user-supplied schema, the schema on disk may still change, but Core doesn't report the updated // schema, so even if we subscribe, we wouldn't be able to see the updates. - if (config is FlexibleSyncConfiguration || config.schemaObjects.isEmpty) { + if (config.schemaObjects.isEmpty) { // TODO: enable once https://github.com/realm/realm-core/issues/7426 is fixed. //_schemaCallbackHandle = handle!.subscribeForSchemaNotifications(this); _schemaCallbackHandle = null; @@ -158,48 +134,19 @@ class Realm { /// A method for asynchronously opening a [Realm]. /// - /// When the configuration is [FlexibleSyncConfiguration], the realm will be downloaded and fully - /// synchronized with the server prior to the completion of the returned [Future]. - /// This method could be called also for opening a local [Realm] with [LocalConfiguration]. - /// /// * `config`- a configuration object that describes the realm. /// * `cancellationToken` - an optional [CancellationToken] used to cancel the operation. - /// * `onProgressCallback` - a callback for receiving download progress notifications for synced [Realm]s. /// /// Returns `Future` that completes with the [Realm] once the remote [Realm] is fully synchronized or with a [CancelledException] if operation is canceled. /// When the configuration is [LocalConfiguration] this completes right after the local [Realm] is opened. /// Using [Realm.open] for opening a local Realm is equivalent to using the constructor of [Realm]. - static Future open(Configuration config, {CancellationToken? cancellationToken, ProgressCallback? onProgressCallback}) async { + static Future open(Configuration config, {CancellationToken? cancellationToken}) async { if (cancellationToken != null && cancellationToken.isCancelled) { throw cancellationToken.exception!; } - if (config is! FlexibleSyncConfiguration) { - final realm = Realm(config); - return await CancellableFuture.value(realm, cancellationToken); - } - - final asyncOpenHandle = AsyncOpenTaskHandle.from(config); - return await CancellableFuture.from(() async { - if (cancellationToken != null && cancellationToken.isCancelled) { - throw cancellationToken.exception!; - } - - StreamSubscription? progressSubscription; - if (onProgressCallback != null) { - final progressController = RealmAsyncOpenProgressNotificationsController._(asyncOpenHandle); - final progressStream = progressController.createStream(); - progressSubscription = progressStream.listen(onProgressCallback); - } - - late final RealmHandle realmHandle; - try { - realmHandle = await asyncOpenHandle.openAsync(cancellationToken); - return Realm._(config, realmHandle); - } finally { - await progressSubscription?.cancel(); - } - }, cancellationToken, onCancel: () => asyncOpenHandle.cancel()); + final realm = Realm(config); + return await CancellableFuture.value(realm, cancellationToken); } static RealmHandle _openRealm(Configuration config) { @@ -258,19 +205,6 @@ class Realm { return object; } - /// Ingest an [AsymmetricObject] to the [Realm]. - /// - /// Ingesting is a write only operation. The ingested objects synchronizes to - /// the App Services backend and are deleted from the device. An [AsymmetricObject] - /// can never be read from the Realm. - void ingest(T object) { - final metadata = _metadata.getByType(object.runtimeType); - final handle = _createObject(object, metadata, false); - - final accessor = RealmCoreAccessor(metadata, _isInMigration); - object.manage(this, handle, accessor, false); - } - ObjectHandle _createObject(RealmObjectBase object, RealmObjectMetadata metadata, bool update) { final key = metadata.classKey; final primaryKey = metadata.primaryKey; @@ -460,44 +394,6 @@ class Realm { return Realm._(config, handle.freeze()); } - WeakReference? _subscriptions; - - /// The active [SubscriptionSet] for this [Realm] - SubscriptionSet get subscriptions { - if (config is! FlexibleSyncConfiguration) { - throw RealmError('subscriptions is only valid on Realms opened with a FlexibleSyncConfiguration'); - } - - var result = _subscriptions?.target; - - if (result == null || result.handle.released) { - result = SubscriptionSetInternal.create(this, handle.subscriptions); - result.handle.refresh(); - _subscriptions = WeakReference(result); - } - - return result; - } - - WeakReference? _syncSession; - - /// The [Session] for this [Realm]. The sync session is responsible for two-way synchronization - /// with MongoDB Atlas. If the [Realm] is not synchronized, accessing this property will throw. - Session get syncSession { - if (config is! FlexibleSyncConfiguration) { - throw RealmError('session is only valid on synchronized Realms (i.e. opened with FlexibleSyncConfiguration)'); - } - - var result = _syncSession?.target; - - if (result == null || result.handle.released) { - result = SessionInternal.create(handle.getSession()); - _syncSession = WeakReference(result); - } - - return result; - } - @override // ignore: hash_and_equals bool operator ==(Object other) { @@ -506,7 +402,7 @@ class Realm { return handle == other.handle; } - /// The logger that will emit log messages from the database and sync operations. + /// The logger that will emit log messages from the database and SDK operations. /// To receive log messages, use the [RealmLogger.onRecord] stream. /// /// If no isolate subscribes to the stream, the trace messages will go to stdout. @@ -550,9 +446,6 @@ class Realm { } final realm = Realm(config); - if (config is FlexibleSyncConfiguration) { - realm.syncSession.pause(); - } try { return realm.handle.compact(); } finally { @@ -994,45 +887,6 @@ class MigrationRealm extends DynamicRealm { MigrationRealm._(super.realm) : super._(); } -/// The signature of a callback that will be executed while the Realm is opened asynchronously with [Realm.open]. -/// This is the registered onProgressCallback when calling [Realm.open] that receives progress notifications while the download is in progress. -/// -/// * syncProgress - an object of [SyncProgress] that contains `transferredBytes` and `transferableBytes`. -/// {@category Realm} -typedef ProgressCallback = void Function(SyncProgress syncProgress); - -/// @nodoc -class RealmAsyncOpenProgressNotificationsController implements ProgressNotificationsController { - final AsyncOpenTaskHandle _handle; - AsyncOpenTaskProgressNotificationTokenHandle? _tokenHandle; - late final StreamController _streamController; - - RealmAsyncOpenProgressNotificationsController._(this._handle); - - Stream createStream() { - _streamController = StreamController(onListen: _start, onCancel: _stop); - return _streamController.stream; - } - - @override - void onProgress(double progressEstimate) { - _streamController.add(SessionInternal.createSyncProgress(progressEstimate)); - } - - void _start() { - if (_tokenHandle != null) { - throw RealmStateError("Progress subscription already started."); - } - - _tokenHandle = _handle.registerProgressNotifier(this); - } - - void _stop() { - _tokenHandle?.release(); - _tokenHandle = null; - } -} - /// @nodoc extension RealmValueInternal on RealmValue { RealmCollectionType? get collectionType { diff --git a/packages/realm_dart/lib/src/realm_object.dart b/packages/realm_dart/lib/src/realm_object.dart index 101cd88b7..e65f560e3 100644 --- a/packages/realm_dart/lib/src/realm_object.dart +++ b/packages/realm_dart/lib/src/realm_object.dart @@ -180,8 +180,6 @@ class RealmCoreAccessor implements RealmAccessor { return object.realm.createList(handle, listMetadata); case ObjectType.embeddedObject: return object.realm.createList(handle, listMetadata); - case ObjectType.asymmetricObject: - return object.realm.createList(handle, listMetadata); default: throw RealmError('List of ${listMetadata.schema.baseType} is not supported yet'); } @@ -196,8 +194,6 @@ class RealmCoreAccessor implements RealmAccessor { return object.realm.createSet(handle, setMetadata); case ObjectType.embeddedObject: return object.realm.createSet(handle, setMetadata); - case ObjectType.asymmetricObject: - return object.realm.createSet(handle, setMetadata); default: throw RealmError('Set of ${setMetadata.schema.baseType} is not supported yet'); } @@ -221,8 +217,6 @@ class RealmCoreAccessor implements RealmAccessor { return object.realm.createMap(handle, mapMetadata); case ObjectType.embeddedObject: return object.realm.createMap(handle, mapMetadata); - case ObjectType.asymmetricObject: - return object.realm.createMap(handle, mapMetadata); default: throw RealmError('Map of ${mapMetadata.schema.baseType} is not supported yet'); } @@ -376,7 +370,6 @@ mixin RealmObjectBase on RealmEntity implements RealmObjectBaseMarker { _typeOf(): () => _ConcreteRealmObject(), EmbeddedObject: () => _ConcreteEmbeddedObject(), _typeOf(): () => _ConcreteEmbeddedObject(), - // We can never read asymmetric objects from a realm, so we don't need a factory for them. }; /// @nodoc @@ -628,17 +621,6 @@ mixin EmbeddedObject on RealmObjectBase implements EmbeddedObjectMarker { Stream> get changes => throw RealmError("Invalid usage. Use the generated inheritors of EmbeddedObject"); } -/// Base for any object that can be persisted in a [Realm], but cannot be retrieved, -/// hence cannot be modified. -/// -/// The benefit of using [AsymmetricObject] is that synchronization is one-way, and -/// thus performs much better. However, they cannot be queried, or retrieved -/// locally, which limits their use-cases greatly. -/// -/// Use [AsymmetricObject] when you have a write-/only use case. You use it by -/// parsing [ObjectType.asymmetricObject] to the [RealmModel] annotation. -mixin AsymmetricObject on RealmObjectBase implements AsymmetricObjectMarker {} - extension EmbeddedObjectExtension on EmbeddedObject { /// Retrieve the [parent] object of this embedded object. RealmObjectBase? get parent { @@ -926,8 +908,6 @@ class DynamicRealmObject { _typeOf(): RealmPropertyType.object, EmbeddedObject: RealmPropertyType.object, _typeOf(): RealmPropertyType.object, - AsymmetricObject: RealmPropertyType.object, - _typeOf(): RealmPropertyType.object, }; RealmPropertyType? _getPropertyType() => _propertyTypeMap[T]; diff --git a/packages/realm_dart/lib/src/results.dart b/packages/realm_dart/lib/src/results.dart index b878ebbcd..b8ca9f358 100644 --- a/packages/realm_dart/lib/src/results.dart +++ b/packages/realm_dart/lib/src/results.dart @@ -3,8 +3,6 @@ import 'dart:async'; -import 'package:cancellation_token/cancellation_token.dart'; - import 'collections.dart'; import 'handles/collection_changes_handle.dart'; import 'handles/handle_base.dart'; @@ -188,99 +186,6 @@ extension RealmResultsOfObject on RealmResults { Stream> changesFor([List? keyPaths]) => _changesFor(keyPaths); } -class _SubscribedRealmResult extends RealmResults { - final String? subscriptionName; - - _SubscribedRealmResult._(RealmResults results, {this.subscriptionName}) - : super._( - results.handle, - results.realm, - results.metadata, - ); -} - -extension RealmResultsOfRealmObject on RealmResults { - /// Adds this [RealmResults] query to the set of active subscriptions. - /// The query will be joined via an OR statement with any existing queries for the same type. - /// - /// If a [name] is given this allows you to later refer to the subscription by name, - /// e.g. when calling [MutableSubscriptionSet.removeByName]. - /// - /// If [update] is specified to `true`, then any existing query - /// with the same name will be replaced. - /// Otherwise a [RealmException] is thrown, in case of duplicates. - /// - /// [WaitForSyncMode] specifies how to wait or not wait for subscribed objects to be downloaded. - /// The default value is [WaitForSyncMode.firstTime]. - /// - /// The [cancellationToken] is optional and can be used to cancel - /// the waiting for objects to be downloaded. - /// If the operation is cancelled, a [CancelledException] is thrown and the download - /// continues in the background. - /// In case of using [TimeoutCancellationToken] and the time limit is exceeded, - /// a [TimeoutException] is thrown and the download continues in the background. - /// - /// {@category Sync} - Future> subscribe({ - String? name, - WaitForSyncMode waitForSyncMode = WaitForSyncMode.firstTime, - CancellationToken? cancellationToken, - bool update = false, - }) async { - final subscriptions = realm.subscriptions; - Subscription? existingSubscription = name == null ? subscriptions.find(this) : subscriptions.findByName(name); - late Subscription updatedSubscription; - subscriptions.update((mutableSubscriptions) { - updatedSubscription = mutableSubscriptions.add(this, name: name, update: update); - }); - bool shouldWait = waitForSyncMode == WaitForSyncMode.always || - (waitForSyncMode == WaitForSyncMode.firstTime && subscriptionIsChanged(existingSubscription, updatedSubscription)); - - return await CancellableFuture.from>(() async { - if (cancellationToken != null && cancellationToken.isCancelled) { - throw cancellationToken.exception!; - } - if (shouldWait) { - await subscriptions.waitForSynchronization(cancellationToken); - await realm.syncSession.waitForDownload(cancellationToken); - } - return _SubscribedRealmResult._(this, subscriptionName: name); - }, cancellationToken); - } - - /// Unsubscribe from this query result. It returns immediately - /// without waiting for synchronization. - /// - /// If the subscription is unnamed, the subscription matching - /// the query will be removed. - /// Return `false` if the [RealmResults] is not created by [subscribe]. - /// - /// {@category Sync} - bool unsubscribe() { - bool unsubscribed = false; - if (realm.config is! FlexibleSyncConfiguration) { - throw RealmError('unsubscribe is only allowed on Realms opened with a FlexibleSyncConfiguration'); - } - if (this is _SubscribedRealmResult) { - final subscriptionName = (this as _SubscribedRealmResult).subscriptionName; - realm.subscriptions.update((mutableSubscriptions) { - if (subscriptionName != null) { - unsubscribed = mutableSubscriptions.removeByName(subscriptionName); - } else { - unsubscribed = mutableSubscriptions.removeByQuery(this); - } - }); - } - return unsubscribed; - } - - bool subscriptionIsChanged(Subscription? existingSubscription, Subscription updatedSubscription) { - return existingSubscription == null || - existingSubscription.objectClassName != updatedSubscription.objectClassName || - existingSubscription.queryString != updatedSubscription.queryString; - } -} - /// @nodoc //RealmResults package internal members extension RealmResultsInternal on RealmResults { diff --git a/packages/realm_dart/lib/src/session.dart b/packages/realm_dart/lib/src/session.dart deleted file mode 100644 index 58cba843f..000000000 --- a/packages/realm_dart/lib/src/session.dart +++ /dev/null @@ -1,277 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; - -import '../realm.dart'; -import 'handles/session_handle.dart'; -import 'user.dart'; - -/// An object encapsulating a synchronization session. Sessions represent the -/// communication between the client (and a local Realm file on disk), and the -/// server. Sessions are always created by the SDK and vended out through various -/// APIs. The lifespans of sessions associated with Realms are managed automatically. -/// {@category Sync} -class Session { - final SessionHandle _handle; - - /// The on-disk path of the file backing the [Realm] this [Session] represents - String get realmPath => handle.path; - - /// The session’s current state. This is different from [connectionState] since a - /// session may be active, even if the connection is disconnected (e.g. due to the device - /// being offline). - SessionState get state => handle.state; - - /// The session’s current connection state. This is the physical state of the connection - /// and is different from the session's logical state, which is returned by [state]. - ConnectionState get connectionState => handle.connectionState; - - /// The [User] that owns the [Realm] this [Session] is synchronizing. - User get user => UserInternal.create(handle.user); - - Session._(this._handle); - - /// Pauses any synchronization with the server until the Realm is re-opened again - /// after fully closing it or [resume] is called. - void pause() => handle.pause(); - - /// Attempts to resume the session and enable synchronization with the server. - /// All sessions are active by default and calling this method is only necessary - /// if [pause] was called previously. - void resume() => handle.resume(); - - /// Waits for the [Session] to finish all pending uploads. - /// An optional [cancellationToken] can be used to cancel the wait operation. - Future waitForUpload([CancellationToken? cancellationToken]) => handle.waitForUpload(cancellationToken); - - /// Waits for the [Session] to finish all pending downloads. - /// An optional [cancellationToken] can be used to cancel the wait operation. - Future waitForDownload([CancellationToken? cancellationToken]) => handle.waitForDownload(cancellationToken); - - /// Gets a [Stream] of [SyncProgress] that can be used to track upload or download progress. - Stream getProgressStream(ProgressDirection direction, ProgressMode mode) { - final controller = SessionProgressNotificationsController(this, direction, mode); - return controller.createStream(); - } - - /// Gets a [Stream] of [ConnectionState] that can be used to be notified whenever the - /// connection state changes. - Stream get connectionStateChanges { - final controller = SessionConnectionStateController(this); - return controller.createStream(); - } -} - -/// A type containing information about the progress state at a given instant. -class SyncProgress { - /// A value between 0.0 and 1.0 representing the estimated transfer progress. This value is precise for - /// uploads, but will be based on historical data and certain heuristics applied by the server for downloads. - /// - /// Whenever the progress reporting mode is [ProgressMode.forCurrentlyOutstandingWork], that value - /// will monotonically increase until it reaches 1.0. If the progress mode is [ProgressMode.reportIndefinitely], the - /// value may either increase or decrease as new data needs to be transferred. - final double progressEstimate; - - const SyncProgress({required this.progressEstimate}); -} - -/// A type containing information about the transition of a connection state from one value to another. -class ConnectionStateChange { - /// The connection state before the transition. - final ConnectionState previous; - - /// The current connection state of the session. - final ConnectionState current; - - ConnectionStateChange._(this.previous, this.current); -} - -extension SessionInternal on Session { - static Session create(SessionHandle handle) => Session._(handle); - - SessionHandle get handle { - if (_handle.released) { - throw RealmClosedError('Cannot access a Session that belongs to a closed Realm'); - } - - return _handle; - } - - void raiseError(int errorCode, bool isFatal) => handle.raiseError(errorCode, isFatal); - - static SyncProgress createSyncProgress(double progressEstimate) => SyncProgress(progressEstimate: progressEstimate); -} - -abstract interface class ProgressNotificationsController { - void onProgress(double progressEstimate); -} - -/// @nodoc -class SessionProgressNotificationsController implements ProgressNotificationsController { - final Session _session; - final ProgressDirection _direction; - final ProgressMode _mode; - - SyncSessionNotificationTokenHandle? _tokenHandle; - late final StreamController _streamController; - - SessionProgressNotificationsController(this._session, this._direction, this._mode); - - Stream createStream() { - _streamController = StreamController(onListen: _start, onCancel: _stop); - return _streamController.stream; - } - - @override - void onProgress(double progressEstimate) { - _streamController.add(SyncProgress(progressEstimate: progressEstimate)); - - if (progressEstimate >= 1.0 && _mode == ProgressMode.forCurrentlyOutstandingWork) { - _streamController.close(); - } - } - - void _start() { - if (_tokenHandle != null) { - throw RealmStateError("Session progress subscription already started."); - } - _tokenHandle = _session.handle.subscribeForProgressNotifications(_direction, _mode, this); - } - - void _stop() { - _tokenHandle?.release(); - _tokenHandle = null; - } -} - -/// @nodoc -class SessionConnectionStateController { - final Session _session; - late final StreamController _streamController; - SyncSessionNotificationTokenHandle? _token; - - SessionConnectionStateController(this._session); - - Stream createStream() { - _streamController = StreamController(onListen: _start, onCancel: _stop); - return _streamController.stream; - } - - void onConnectionStateChange(ConnectionState oldState, ConnectionState newState) { - _streamController.add(ConnectionStateChange._(oldState, newState)); - } - - void _start() { - if (_token != null) { - throw RealmStateError("Session connection state subscription already started"); - } - _token = _session.handle.subscribeForConnectionStateNotifications(this); - } - - void _stop() { - _token?.release(); - _token = null; - } -} - -/// The current state of a [Session] object -enum SessionState { - /// The session is connected to MongoDB Atlas and is actively transferring data. - active, - - /// The session is not currently communicating with the server. - inactive, -} - -/// The current connection state of a [Session] object -enum ConnectionState { - /// The session is disconnected from MongoDB Atlas. - disconnected, - - /// The session is connecting to MongoDB Atlas. - connecting, - - /// The session is connected to MongoDB Atlas. - connected, -} - -/// The transfer direction (upload or download) tracked by a given progress notification subscription. -enum ProgressDirection { - /// Monitors upload progress. - upload, - - /// Monitors download progress. - download -} - -/// The desired behavior of a progress notification subscription. -enum ProgressMode { - /// The callback will be called forever, or until it is unregistered by closing the `Stream`. - /// Notifications will always report the latest number of transferred bytes, and the most up-to-date number of - /// total transferable bytes. - reportIndefinitely, - - /// The callback will, upon registration, store the total number of bytes to be transferred. When invoked, it will - /// always report the most up-to-date number of transferable bytes out of that original number of transferable bytes. - /// When the number of transferred bytes reaches or exceeds the number of transferable bytes, the callback will - /// be unregistered. - forCurrentlyOutstandingWork, -} - -/// Error code enumeration, indicating the type of [SyncError]. -enum SyncErrorCode { - /// Unrecognized error code. It usually indicates incompatibility between the App Services server and client SDK versions. - runtimeError, - - /// The partition value specified by the user is not valid - i.e. its the wrong type or is encoded incorrectly. - badPartitionValue, - - /// A fundamental invariant in the communication between the client and the server was not upheld. This typically indicates - /// a bug in the synchronization layer and should be reported at https://github.com/realm/realm-core/issues. - protocolInvariantFailed, - - /// The changeset is invalid. - badChangeset, - - /// The client attempted to create a subscription for a query is invalid/malformed. - invalidSubscriptionQuery, - - /// A client reset has occurred. This error code will only be reported via a [ClientResetError] and only - /// in the case manual client reset handling is required - either via [ManualRecoveryHandler] or when - /// `onManualReset` is invoked on one of the automatic client reset handlers. - clientReset, - - /// The client attempted to upload an invalid schema change - either an additive schema change - /// when developer mode is off or a destructive schema change. - invalidSchemaChange, - - /// Permission to Realm has been denied. - permissionDenied, - - /// The server permissions for this file have changed since the last time it was used. - serverPermissionsChanged, - - /// The user for this session doesn't match the user who originally created the file. This can happen - /// if you explicitly specify the Realm file path in the configuration and you open the Realm first with - /// user A, then with user B without changing the on-disk path. - userMismatch, - - /// Client attempted a write that is disallowed by permissions, or modifies an object - /// outside the current query - this will result in a [CompensatingWriteError]. - writeNotAllowed, - - /// Automatic client reset has failed. This will only be reported via [ClientResetError] - /// when an automatic client reset handler was used but it failed to perform the client reset operation - - /// typically due to a breaking schema change in the server schema or due to an exception occurring in the - /// before or after client reset callbacks. - autoClientResetFailed, - - /// The wrong sync type was used to connect to the server. This means that you're trying to connect - /// to an app configured to use partition sync. - wrongSyncType, - - /// Client attempted a write that is disallowed by permissions, or modifies an - /// object outside the current query, and the server undid the modification. - compensatingWrite; -} diff --git a/packages/realm_dart/lib/src/subscription.dart b/packages/realm_dart/lib/src/subscription.dart deleted file mode 100644 index ff814a198..000000000 --- a/packages/realm_dart/lib/src/subscription.dart +++ /dev/null @@ -1,276 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:core'; - -import 'convert.dart'; -import 'handles/mutable_subscription_set_handle.dart'; -import 'handles/subscription_handle.dart'; -import 'handles/subscription_set_handle.dart'; -import 'realm_class.dart'; -import 'results.dart'; - -/// A class representing a single query subscription. The server will continuously -/// evaluate the query that the app subscribed to and will send data -/// that matches it as well as remove data that no longer does. -/// {@category Sync} -final class Subscription { - final SubscriptionHandle _handle; - - Subscription._(this._handle); - - late final ObjectId _id = _handle.id; - - /// Name of the [Subscription], if one was provided at creation time. - String? get name => _handle.name; - - /// Class name of objects the [Subscription] refers to. - /// - /// If your types are remapped using [MapTo], the value - /// returned will be the mapped-to value - i.e. the one that Realm uses internally - /// rather than the name of the generated Dart class. - String get objectClassName => _handle.objectClassName; - - /// Query string that describes the [Subscription]. - /// - /// Objects matched by the query will be sent to the device by the server. - String get queryString => _handle.queryString; - - /// Timestamp when this [Subscription] was created. - DateTime get createdAt => _handle.createdAt; - - /// Timestamp when this [Subscription] was last updated. - DateTime get updatedAt => _handle.updatedAt; - - @override - // ignore: hash_and_equals - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! Subscription) return false; - return _handle.equalTo(other._handle); - } -} - -extension SubscriptionInternal on Subscription { - SubscriptionHandle get handle => _handle; - ObjectId get id => _id; -} - -final class _SubscriptionIterator implements Iterator { - int _index = -1; - final SubscriptionSet _subscriptions; - - _SubscriptionIterator._(this._subscriptions); - - @override - Subscription get current => _subscriptions.elementAt(_index); - - @override - bool moveNext() => ++_index < _subscriptions.length; -} - -/// {@category Sync} -enum SubscriptionSetState { - /// This subscription set has not been persisted and has not been sent to the server. - /// This state is only valid for MutableSubscriptionSets - _uncommitted, // ignore: unused_field - - /// The subscription set has been persisted locally but has not been acknowledged by the server yet. - pending, - - /// The server is currently sending the initial state that represents this subscription set to the client. - _bootstrapping, // ignore: unused_field - - /// This subscription set is the active subscription set that is currently being synchronized with the server. - complete, - - /// An error occurred while processing this subscription set on the server. Check error_str() for details. - error, - - /// The server responded to a later subscription set to this one and this one has been - /// trimmed from the local storage of subscription sets. - superseded, -} - -/// A collection representing the set of active subscriptions for a [Realm] instance. -/// -/// This is used in combination with [FlexibleSyncConfiguration] to -/// declare the set of queries you want to synchronize with the server. You can access and -/// read the subscription set freely, but mutating it must happen in an [update] -/// block. -/// -/// Any changes to the subscription set will be persisted locally and be available the next -/// time the application starts up - i.e. it's not necessary to subscribe for the same query -/// every time. Updating the subscription set can be done while offline, and only the latest -/// update will be sent to the server whenever connectivity is restored. -/// -/// It is strongly recommended that you batch updates as much as possible and request the -/// dataset your application needs upfront. Updating the set of active subscriptions for a -/// Realm is an expensive operation server-side, even if there's very little data that needs -/// downloading. -/// {@category Sync} -abstract interface class SubscriptionSet with Iterable { - final Realm _realm; - SubscriptionSetHandle _handle; - - SubscriptionSet._(this._realm, this._handle); - - /// Finds an existing [Subscription] in this set by its query - /// - /// The [query] is represented by the corresponding [RealmResults] object. - Subscription? find(RealmResults query) => _handle.findByResults(query.handle).convert(Subscription._); - - /// Finds an existing [Subscription] in this set by name. - Subscription? findByName(String name) => _handle.findByName(name).convert(Subscription._); - - Future _waitForStateChange(SubscriptionSetState state, [CancellationToken? cancellationToken]) async { - final result = await _handle.waitForStateChange(state, cancellationToken); - _handle.refresh(); - return result; - } - - /// Waits for the server to acknowledge the subscription set and return the matching objects. - /// - /// If the [state] of the subscription set is [SubscriptionSetState.complete] - /// the returned [Future] will complete immediately. If the state is - /// [SubscriptionSetState.error], the returned future will throw an - /// error. - /// An optional [cancellationToken] can be used to cancel the wait operation. - Future waitForSynchronization([CancellationToken? cancellationToken]) async { - final result = await _waitForStateChange(SubscriptionSetState.complete, cancellationToken); - if (result == SubscriptionSetState.error) { - throw error!; - } - } - - /// Returns the error if the subscription set is in the [SubscriptionSetState.error] state. - Exception? get error => _handle.error; - - @override - int get length => _handle.size; - - @override - Subscription elementAt(int index) { - RangeError.checkValidRange(index, null, length); - return Subscription._(_handle[index]); - } - - /// Gets the [Subscription] at the specified index in the set. - Subscription operator [](int index) => elementAt(index); - - @override - Iterator get iterator => _SubscriptionIterator._(this); - - /// Updates the subscription set and send the request to the server in the background. - /// - /// Calling [update] is a prerequisite for mutating the subscription set, - /// using a [MutableSubscriptionSet] passed to the [action]. - /// - /// If you want to wait for the server to acknowledge and send back the data that matches the updated - /// subscriptions, use [waitForSynchronization]. - void update(void Function(MutableSubscriptionSet mutableSubscriptions) action); - - /// Gets the version of the subscription set. - int get version => _handle.version; - - /// Gets the state of the subscription set. - SubscriptionSetState get state { - final state = _handle.state; - switch (state) { - case SubscriptionSetState._uncommitted: - case SubscriptionSetState._bootstrapping: - return SubscriptionSetState.pending; - default: - return state; - } - } -} - -extension SubscriptionSetInternal on SubscriptionSet { - SubscriptionSetHandle get handle => _handle; - - static SubscriptionSet create(Realm realm, SubscriptionSetHandle handle) => ImmutableSubscriptionSet._(realm, handle); -} - -final class ImmutableSubscriptionSet extends SubscriptionSet { - ImmutableSubscriptionSet._(super.realm, super.handle) : super._(); - - @override - void update(void Function(MutableSubscriptionSet mutableSubscriptions) action) { - final old = _handle; - final mutable = _handle.toMutable(); - try { - action(MutableSubscriptionSet._(_realm, mutable)); - _handle = mutable.commit(); - } finally { - // Release as early as possible, as we cannot start new update, until this is released! - mutable.release(); - old.release(); - } - } -} - -/// A mutable view to a [SubscriptionSet]. Obtained by calling [SubscriptionSet.update]. -/// {@category Sync} -final class MutableSubscriptionSet extends SubscriptionSet { - @override - MutableSubscriptionSetHandle get _handle => super._handle as MutableSubscriptionSetHandle; - - MutableSubscriptionSet._(super.realm, MutableSubscriptionSetHandle super.handle) : super._(); - - @override - void update(void Function(MutableSubscriptionSet mutableSubscriptions) action) { - action(this); - } - - /// Adds a [query] to the set of active subscriptions. - /// - /// The query will be joined via an OR statement with any existing queries for the same type. - /// - /// If a [name] is given, then this will be used to match with any existing query, - /// otherwise the [query] itself is used for matching. - /// - /// If [update] is specified to `true`, then any existing query will be replaced. - /// Otherwise a [RealmException] is thrown, in case of duplicates. - /// {@category Sync} - Subscription add(RealmResults query, {String? name, bool update = false}) => - Subscription._(_handle.insertOrAssignSubscription(query.handle, name, update)); - - /// Removes the [subscription] from the set, if it exists. - bool remove(Subscription subscription) => _handle.erase(subscription._handle); - - /// Removes the [query] from the set, if it exists. - bool removeByQuery(RealmResults query) => _handle.eraseByResults(query.handle); - - /// Removes the subscription from the set that matches by [name], if it exists. - bool removeByName(String name) => _handle.eraseByName(name); - - /// Removes the subscriptions from the set that matches by type, if it exists. - bool removeByType() { - final name = _realm.schema.singleWhere((e) => e.type == T).name; - var result = false; - for (var i = length - 1; i >= 0; i--) { - // reverse iteration to avoid index shifting - final subscription = this[i]; - if (subscription.objectClassName == name) { - result |= remove(subscription); - } - } - return result; - } - - /// Clears the subscription set. - /// If [unnamedOnly] is `true`, then only unnamed subscriptions will be removed. - void clear({bool unnamedOnly = false}) { - if (unnamedOnly) { - for (var i = length - 1; i >= 0; i--) { - final subscription = this[i]; - if (subscription.name == null) { - remove(subscription); - } - } - } else { - _handle.clear(); - } - } -} diff --git a/packages/realm_dart/lib/src/user.dart b/packages/realm_dart/lib/src/user.dart deleted file mode 100644 index d10347da3..000000000 --- a/packages/realm_dart/lib/src/user.dart +++ /dev/null @@ -1,407 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:convert'; - -import 'app.dart'; -import 'credentials.dart'; -import 'handles/user_handle.dart'; -import 'realm_class.dart'; - -/// Describes the changes to a [User] instance - for example when the access token is updated or the user state changes. -/// Right now, this only conveys information that the user has changed, but in the future it will be enhanced by adding -/// details about the exact properties that have been updated. -class UserChanges { - /// The user that has changed. - final User user; - - const UserChanges._(this.user); -} - -/// This class represents a `user` in an [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) application. -/// A user can log in to the server and, if access is granted, it is possible to synchronize the local Realm to MongoDB Atlas. -/// Moreover, synchronization is halted when the user is logged out. It is possible to persist a user. By retrieving a user, there is no need to log in again. -/// Persisting a user between sessions, the user's credentials are stored -/// locally on the device, and should be treated as sensitive data. -/// {@category Application} -class User { - App? _app; - final UserHandle _handle; - - /// The [App] with which the [User] is associated with. - App get app { - // The _app field may be null when we're retrieving a user from the session - // rather than from the app. - return _app ??= AppInternal.create(_handle.app); - } - - late final ApiKeyClient _apiKeys = ApiKeyClient._(this); - late final FunctionsClient _functions = FunctionsClient._(this); - - /// Gets an [ApiKeyClient] instance that exposes functionality for managing - /// user API keys. - /// [API Keys Authentication Docs](https://www.mongodb.com/docs/atlas/app-services/authentication/api-key/#api-key-authentication) - ApiKeyClient get apiKeys { - _ensureLoggedIn('access API keys'); - - return _apiKeys; - } - - /// Gets a [FunctionsClient] instance that exposes functionality for calling remote Atlas Functions. - /// A [FunctionsClient] instance scoped to this [User]. - /// [Atlas Functions Docs](hhttps://www.mongodb.com/docs/atlas/app-services/functions/#atlas-functions) - FunctionsClient get functions { - _ensureLoggedIn('access API keys'); - - return _functions; - } - - User._(this._handle, this._app); - - /// The current state of this [User]. - UserState get state { - return handle.state; - } - - /// Get this [User]'s id on MongoDB Atlas. - String get id { - return handle.id; - } - - /// Gets a collection of all identities associated with this [User]. - List get identities { - return handle.identities; - } - - /// Removes the [User]'s local credentials. This will also close any associated Sessions. - Future logOut() async { - return await handle.logOut(); - } - - /// Gets an unique identifier for the current device. - String? get deviceId { - return handle.deviceId; - } - - /// Gets the profile information for this [User]. - UserProfile get profile { - return handle.profileData; - } - - /// Gets the refresh token for this [User]. This is the user's credential for - /// accessing [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) and should be treated as sensitive data. - String get refreshToken { - return handle.refreshToken; - } - - /// Gets the access token for this [User]. This is the user's credential for - /// accessing [Atlas App Services](https://www.mongodb.com/docs/atlas/app-services/) and should be treated as sensitive data. - String get accessToken { - return handle.accessToken; - } - - /// The custom user data associated with this [User]. - dynamic get customData { - final data = handle.customData; - if (data == null) { - return null; - } - - return jsonDecode(data); - } - - /// Refreshes the custom data for a this [User]. - Future refreshCustomData() async { - await app.handle.refreshCustomData(handle); - return customData; - } - - /// Links this [User] with a new `User` identity represented by the given credentials. - /// - /// Linking a user with more credentials, mean the user can login either of these credentials. It also makes it possible to "upgrade" an anonymous user - /// by linking it with e.g. Email/Password credentials. - /// *Note: It is not possible to link two existing users of MongoDB Atlas. The provided credentials must not have been used by another user.* - /// - /// The following snippet shows how to associate an email and password with an anonymous user allowing them to login on a different device. - /// ```dart - /// final app = App(configuration); - /// final user = await app.logIn(Credentials.anonymous()); - /// - /// // This step is only needed for email password auth - a password record must exist before you can link a user to it. - /// final authProvider = EmailPasswordAuthProvider(app); - /// await authProvider.registerUser("username", "password"); - /// - /// await user.linkCredentials(Credentials.emailPassword("username", "password")); - /// ``` - Future linkCredentials(Credentials credentials) async { - final userHandle = await handle.linkCredentials(app.handle, credentials.handle); - return UserInternal.create(userHandle, app); - } - - @override - // ignore: hash_and_equals - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (other is! User) return false; - return handle == other.handle; - } - - void _ensureLoggedIn([String clarification = 'perform this action']) { - if (state != UserState.loggedIn) { - throw RealmError('User must be logged in to $clarification'); - } - } - - /// Gets a [Stream] of [UserChanges] that can be used to receive notifications when the user changes. - Stream get changes { - final controller = UserNotificationsController(this); - return controller.createStream(); - } -} - -/// @nodoc -class UserNotificationsController { - UserNotificationTokenHandle? tokenHandle; - - void start() { - if (tokenHandle != null) { - throw RealmStateError("User notifications subscription already started"); - } - - tokenHandle = user.handle.subscribeForNotifications(this); - } - - void stop() { - // If handle is null or released, no-op - if (tokenHandle?.released != false) { - return; - } - - tokenHandle!.release(); - tokenHandle = null; - } - - User user; - - late final StreamController streamController; - - UserNotificationsController(this.user); - - Stream createStream() { - streamController = StreamController(onListen: start, onCancel: stop); - return streamController.stream; - } - - void onUserChanged() { - final changes = UserChanges._(user); - streamController.add(changes); - } - - void onError(RealmError error) { - streamController.addError(error); - } -} - -/// The current state of a [User]. -enum UserState { - /// The user is logged out. Call [App.logIn] to log the user back in. - loggedOut, - - /// The user is logged in, and any Realms associated with it are synchronizing with MongoDB Atlas. - loggedIn, - - /// The user has been logged out and their local data has been removed. - removed, -} - -/// The user identity associated with a [User] -class UserIdentity { - /// The unique identifier for this [UserIdentity]. - final String id; - - /// The [AuthProviderType] defining this identity. - final AuthProviderType provider; - - const UserIdentity._(this.id, this.provider); -} - -/// A class containing profile information about [User]. -class UserProfile { - final Map _data; - - /// Gets the name of the [User]. - String? get name => _data["name"] as String?; - - /// Gets the first name of the [User]. - String? get firstName => _data["firstName"] as String?; - - /// Gets the last name of the [User]. - String? get lastName => _data["lastName"] as String?; - - /// Gets the email of the [User]. - String? get email => _data["email"] as String?; - - /// Gets the gender of the [User]. - String? get gender => _data["gender"] as String?; - - /// Gets the birthday of the user. - String? get birthDay => _data["birthDay"] as String?; - - /// Gets the minimum age of the [User]. - String? get minAge => _data["minAge"] as String?; - - /// Gets the maximum age of the [User]. - String? get maxAge => _data["maxAge"] as String?; - - /// Gets the url for the [User]'s profile picture. - String? get pictureUrl => _data["pictureUrl"] as String?; - - /// Gets a profile property of the [User]. - dynamic operator [](String property) => _data[property]; - - const UserProfile(this._data); -} - -/// A class exposing functionality for users to manage API keys from the client. It is always scoped -/// to a particular [User] and can only be accessed via [User.apiKeys] -class ApiKeyClient { - final User _user; - - ApiKeyClient._(this._user); - - /// Creates a new API key with the given name. The value of the returned key - /// must be persisted as this is the only time it is available. - Future create(String name) async { - _user._ensureLoggedIn('create an API key'); - - return _user.handle.createApiKey(_user.app.handle, name); - } - - /// Fetches a specific API key by id. - Future fetch(ObjectId id) { - _user._ensureLoggedIn('fetch an API key'); - - return _user.handle.fetchApiKey(_user.app.handle, id).handle404(); - } - - /// Fetches all API keys associated with the user. - Future> fetchAll() async { - _user._ensureLoggedIn('fetch all API keys'); - - return _user.handle.fetchAllApiKeys(_user.app.handle); - } - - /// Deletes a specific API key by id. - Future delete(ObjectId objectId) { - _user._ensureLoggedIn('delete an API key'); - - return _user.handle.deleteApiKey(_user.app.handle, objectId).handle404(); - } - - /// Disables an API key by id. - Future disable(ObjectId objectId) { - _user._ensureLoggedIn('disable an API key'); - - return _user.handle.disableApiKey(_user.app.handle, objectId).handle404(id: objectId); - } - - /// Enables an API key by id. - Future enable(ObjectId objectId) { - _user._ensureLoggedIn('enable an API key'); - - return _user.handle.enableApiKey(_user.app.handle, objectId).handle404(id: objectId); - } -} - -/// A class representing an API key for a [User]. It can be used to represent the user when logging in -/// instead of their regular credentials. These keys are created or fetched through [User.apiKeys]. -class ApiKey { - /// The unique identifier for this [ApiKey]. - final ObjectId id; - - /// The name of this [ApiKey]. - final String name; - - /// The value of this [ApiKey]. This is only returned when the ApiKey is created via [ApiKeyClient.create]. - /// In all other cases, it'll be `null`. - final String? value; - - /// A value indicating whether the ApiKey is enabled. If this is false, then the ApiKey cannot be used to - /// authenticate the user. - final bool isEnabled; - - ApiKey._(this.id, this.name, this.value, this.isEnabled); - - @override - bool operator ==(Object other) { - return identical(this, other) || (other is ApiKey && other.id == id); - } - - @override - int get hashCode => id.hashCode; -} - -/// A class exposing functionality for calling remote Atlas Functions. -class FunctionsClient { - final User _user; - - FunctionsClient._(this._user); - - /// Calls a remote function with the supplied arguments. - /// @name The name of the Atlas function to call. - /// @functionArgs - Arguments that will be sent to the Atlas function. They have to be json serializable values. - Future call(String name, [List functionArgs = const []]) async { - _user._ensureLoggedIn('call Atlas function'); - final args = jsonEncode(functionArgs); - final response = await _user.app.handle.callAppFunction(_user.handle, name, args); - return jsonDecode(response); - } -} - -/// @nodoc -extension UserIdentityInternal on UserIdentity { - static UserIdentity create(String identity, AuthProviderType provider) => UserIdentity._(identity, provider); -} - -/// @nodoc -extension UserInternal on User { - UserHandle get handle => _handle; - - static User create(UserHandle handle, [App? app]) => User._(handle, app); - - static ApiKey createApiKey(ObjectId id, String name, String? value, bool isEnabled) => ApiKey._(id, name, value, isEnabled); -} - -extension on Future { - Future handle404({ObjectId? id}) async { - try { - await this; - } on AppException catch (e) { - if (e.statusCode == 404) { - // If we have an id, we can provide a more specific error message. Otherwise, we ignore the exception - if (id != null) { - throw AppInternal.createException("Failed to execute operation because ApiKey with Id: $id doesn't exist.", e.linkToServerLogs, 404); - } - - return; - } - - rethrow; - } - } -} - -extension on Future { - Future handle404() async { - try { - return await this; - } on AppException catch (e) { - if (e.statusCode == 404) { - return null; - } - - rethrow; - } - } -} diff --git a/packages/realm_dart/src/CMakeLists.txt b/packages/realm_dart/src/CMakeLists.txt index b050f2ec2..eef169ed3 100644 --- a/packages/realm_dart/src/CMakeLists.txt +++ b/packages/realm_dart/src/CMakeLists.txt @@ -1,6 +1,9 @@ option(REALM_BUILD_CORE_FROM_SOURCE "Build Realm Core from source" ON) + if(REALM_BUILD_CORE_FROM_SOURCE) set(REALM_BUILD_LIB_ONLY ON) + set(REALM_ENABLE_SYNC OFF) + set(REALM_APP_SERVICES OFF) add_subdirectory(realm-core EXCLUDE_FROM_ALL) endif() @@ -12,7 +15,6 @@ set(SOURCES realm_dart_logger.cpp realm_dart_decimal128.cpp realm_dart_scheduler.cpp - realm_dart_sync.cpp realm-core/src/external/IntelRDFPMathLib20U2/LIBRARY/src/bid128_noncomp.c ) @@ -21,8 +23,6 @@ set(HEADERS realm_dart.hpp realm_dart_logger.h realm_dart_scheduler.h - realm_dart_scheduler.h - realm_dart_sync.h realm-core/src/realm.h ) @@ -42,6 +42,7 @@ else() endif() string(APPEND OUTPUT_DIR "${PROJECT_SOURCE_DIR}/binary") + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") string(APPEND OUTPUT_DIR "/windows") elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") diff --git a/packages/realm_dart/src/realm_dart_sync.cpp b/packages/realm_dart/src/realm_dart_sync.cpp deleted file mode 100644 index 5c80d3c30..000000000 --- a/packages/realm_dart/src/realm_dart_sync.cpp +++ /dev/null @@ -1,388 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2022 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include - -#include "realm_dart.hpp" -#include "realm_dart_sync.h" - -RLM_API void realm_dart_http_request_callback(realm_userdata_t userdata, realm_http_request_t request, void* request_context) { - // the pointers in request are to stack values, we need to make copies and move them into the scheduler invocation - struct request_copy_buf { - std::string url; - std::string body; - std::vector> headers_values; - std::vector headers; - } buf; - - buf.url = request.url; - buf.body = std::string(request.body, request.body_size); - buf.headers_values.reserve(request.num_headers); - buf.headers.reserve(request.num_headers); - for (size_t i = 0; i < request.num_headers; i++) { - auto& [name, value] = buf.headers_values.emplace_back(request.headers[i].name, request.headers[i].value); - buf.headers.push_back({ name.c_str(), value.c_str() }); - } - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, request = std::move(request), buf = std::move(buf), request_context]() mutable { - //we moved buf so we need to update the request pointers here. - request.url = buf.url.c_str(); - request.body = buf.body.data(); - request.headers = buf.headers.data(); - (reinterpret_cast(ud->dart_callback)(ud->handle, request, request_context)); - }); -} - -RLM_API void realm_dart_sync_error_handler_callback(realm_userdata_t userdata, realm_sync_session_t* session, realm_sync_error_t error) -{ - // the pointers in error are to stack values, we need to make copies and move them into the scheduler invocation - struct compensating_write_copy { - std::string reason; - std::string object_name; - realm_value_t primary_key; - }; - - struct error_copy { - std::string message; - realm_errno_e error; - realm_error_categories categories; - std::string original_file_path_key; - std::string recovery_file_path_key; - bool is_fatal; - bool is_client_reset_requested; - std::vector> user_info_values; - std::vector user_info; - std::vector compensating_writes_errors_info_copy; - std::vector compensating_writes_errors_info; - } buf; - - buf.message = std::string(error.status.message); - buf.categories = error.status.categories; - buf.error = error.status.error; - // TODO: Map usercode_error and path when issue https://github.com/realm/realm-core/issues/6925 is fixed - buf.original_file_path_key = std::string(error.c_original_file_path_key); - buf.recovery_file_path_key = std::string(error.c_recovery_file_path_key); - buf.is_fatal = error.is_fatal; - buf.is_client_reset_requested = error.is_client_reset_requested; - buf.user_info_values.reserve(error.user_info_length); - buf.user_info.reserve(error.user_info_length); - buf.compensating_writes_errors_info_copy.reserve(error.compensating_writes_length); - buf.compensating_writes_errors_info.reserve(error.compensating_writes_length); - - for (size_t i = 0; i < error.user_info_length; i++) { - auto& [key, value] = buf.user_info_values.emplace_back(error.user_info_map[i].key, error.user_info_map[i].value); - buf.user_info.push_back({ key.c_str(), value.c_str() }); - } - for (size_t i = 0; i < error.compensating_writes_length; i++) { - const auto& cw = error.compensating_writes[i]; - const auto& cw_buf = buf.compensating_writes_errors_info_copy.emplace_back(compensating_write_copy{ - std::string(cw.reason), - std::string(cw.object_name), - cw.primary_key - }); - buf.compensating_writes_errors_info.push_back(realm_sync_error_compensating_write_info_t{ - cw_buf.reason.c_str(), - cw_buf.object_name.c_str(), - cw_buf.primary_key - }); - } - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, session = *session, error = std::move(error), buf = std::move(buf)]() mutable { - //we moved buf so we need to update the error pointers here. - error.status.message = buf.message.c_str(); - error.status.error = buf.error; - error.status.categories = buf.categories; - error.c_original_file_path_key = buf.original_file_path_key.c_str(); - error.c_recovery_file_path_key = buf.recovery_file_path_key.c_str(); - error.is_fatal = buf.is_fatal; - error.is_client_reset_requested = buf.is_client_reset_requested; - error.user_info_map = buf.user_info.data(); - error.compensating_writes = buf.compensating_writes_errors_info.data(); - (reinterpret_cast(ud->dart_callback))(ud->handle, const_cast(&session), error); - }); -} - -RLM_API void realm_dart_sync_wait_for_completion_callback(realm_userdata_t userdata, realm_error_t* error) -{ - // we need to make a deep copy of error, because the message pointer points to stack memory - struct realm_dart_sync_error_code : realm_error_t - { - realm_dart_sync_error_code(const realm_error& error_input) - : message_buffer(error_input.message) - { - error = error_input.error; - categories = error_input.categories; - message = message_buffer.c_str(); - } - - const std::string message_buffer; - }; - - std::unique_ptr error_copy; - if (error != nullptr) { - error_copy = std::make_unique(*error); - } - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, error = std::move(error_copy)]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, error.get()); - }); -} - -RLM_API void realm_dart_sync_progress_callback(realm_userdata_t userdata, uint64_t transferred_bytes, uint64_t total_bytes, double estimate) -{ - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, transferred_bytes, total_bytes, estimate]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, transferred_bytes, total_bytes, estimate); - }); -} - -RLM_API void realm_dart_sync_connection_state_changed_callback(realm_userdata_t userdata, - realm_sync_connection_state_e old_state, - realm_sync_connection_state_e new_state) -{ - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, old_state, new_state]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, old_state, new_state); - }); -} - - -RLM_API void realm_dart_user_change_callback(realm_userdata_t userdata, realm_user_state_e state) -{ - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, state]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, state); - }); -} - -RLM_API void realm_dart_sync_on_subscription_state_changed_callback(realm_userdata_t userdata, realm_flx_sync_subscription_set_state_e state) -{ - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, state]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, state); - }); -} - -bool invoke_dart_and_await_result(realm::util::UniqueFunction*)>* userCallback) -{ - std::condition_variable condition; - std::mutex mutex; - realm_userdata_t user_error = nullptr; - bool completed = false; - - realm::util::UniqueFunction unlockFunc = [&](realm_userdata_t error) { - std::unique_lock lock(mutex); - user_error = error; - completed = true; - condition.notify_one(); - }; - - std::unique_lock lock(mutex); - (*userCallback)(&unlockFunc); - condition.wait(lock, [&]() { return completed; }); - - if (user_error != nullptr) { - realm_register_user_code_callback_error(user_error); - return false; - } - - return true; -} - -RLM_API bool realm_dart_sync_before_reset_handler_callback(realm_userdata_t userdata, realm_t* realm) -{ - auto ud = reinterpret_cast(userdata); - realm::util::UniqueFunction userCallback = [ud, realm](realm::util::UniqueFunction* unlockFunc) { - ud->scheduler->invoke([ud, realm, unlockFunc]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, realm, unlockFunc); - }); - }; - return invoke_dart_and_await_result(&userCallback); -} - -RLM_API bool realm_dart_sync_after_reset_handler_callback(realm_userdata_t userdata, realm_t* before_realm, realm_thread_safe_reference_t* after_realm, bool did_recover) -{ - auto ud = reinterpret_cast(userdata); - realm::util::UniqueFunction userCallback = [ud, before_realm, after_realm, did_recover](realm::util::UniqueFunction* unlockFunc) { - ud->scheduler->invoke([ud, before_realm, after_realm, did_recover, unlockFunc]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, before_realm, after_realm, did_recover, unlockFunc); - }); - }; - return invoke_dart_and_await_result(&userCallback); -} - -RLM_API void realm_dart_async_open_task_callback(realm_userdata_t userdata, realm_thread_safe_reference_t* realm, const realm_async_error_t* error) -{ - auto ud = reinterpret_cast(userdata); - realm_async_error_t* error_clone = error ? error->clone() : nullptr; - ud->scheduler->invoke([ud, realm, error_clone]() { - (reinterpret_cast(ud->dart_callback))(ud->handle, realm, error_clone); - delete error_clone; - }); -} - -std::unique_ptr realm_app_error_copy(const realm_app_error_t* error) -{ - // we make a deep copy of error, so it is valid after callback returns - struct error_buf : realm_app_error - { - error_buf(const realm_app_error& error_input) - : message_buffer(error_input.message), - link_to_server_logs_buffer(error_input.link_to_server_logs ? error_input.link_to_server_logs : "") - { - error = error_input.error; - categories = error_input.categories; - http_status_code = error_input.http_status_code; - message = message_buffer.c_str(); - link_to_server_logs = link_to_server_logs_buffer.c_str(); - } - - const std::string message_buffer; - const std::string link_to_server_logs_buffer; - }; - - std::unique_ptr error_copy; - if (error != nullptr) { - error_copy = std::make_unique(*error); - } - - - return error_copy; -} - -RLM_API void realm_dart_user_completion_callback(realm_userdata_t userdata, realm_user_t* user, const realm_app_error_t* error) -{ - // we need to make a deep copy of error, because the message pointer points to stack memory - auto error_copy = realm_app_error_copy(error); - - // take an extra ref to the user, so that it doesn't get deleted before we invoke the callback - std::shared_ptr user_copy; - if (user != nullptr) { - user_copy = realm_user(*user); - } - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, error = std::move(error_copy), user = realm_user(user_copy)]() mutable { - (reinterpret_cast(ud->dart_callback))(ud->handle, &user, error.get()); - }); -} - -RLM_API void realm_dart_void_completion_callback(realm_userdata_t userdata, const realm_app_error_t* error) -{ - // we need to make a deep copy of error, because the message pointer points to stack memory - auto error_copy = realm_app_error_copy(error); - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, error = std::move(error_copy)]() mutable { - (reinterpret_cast(ud->dart_callback))(ud->handle, error.get()); - }); -} - -struct apikey_buf : realm_app_user_apikey -{ - apikey_buf(const realm_app_user_apikey& apikey_input) - : key_buffer(apikey_input.key ? apikey_input.key : ""), - name_buffer(apikey_input.name ? apikey_input.name : "") - { - id = apikey_input.id; - key = key_buffer.c_str(); - name = name_buffer.c_str(); - disabled = apikey_input.disabled; - } - - const std::string key_buffer; - const std::string name_buffer; -}; - -std::unique_ptr realm_apikey_copy(const realm_app_user_apikey_t* apikey) -{ - std::unique_ptr apikey_copy; - if (apikey != nullptr) { - apikey_copy = std::make_unique(*apikey); - } - return apikey_copy; -} - -RLM_API void realm_dart_apikey_callback(realm_userdata_t userdata, realm_app_user_apikey_t* apikey, const realm_app_error_t* error) { - // we need to make a deep copies as the pointers point to stack memory - auto error_copy = realm_app_error_copy(error); - auto apikey_copy = realm_apikey_copy(apikey); - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, apikey = std::move(apikey_copy), error = std::move(error_copy)]() mutable { - (reinterpret_cast(ud->dart_callback))(ud->handle, apikey.get(), error.get()); - }); -} - -std::vector realm_apikey_list_copy(const realm_app_user_apikey_t apikey_list[], size_t count) -{ - // we make a deep copy of error, so it is valid after callback returns - std::vector apikey_list_copy; - if (apikey_list != nullptr) { - apikey_list_copy.reserve(count); - std::transform( - apikey_list, - apikey_list + count, - std::back_inserter(apikey_list_copy), - [](const realm_app_user_apikey_t& apikey) { - return apikey_buf(apikey); - } - ); - } - return apikey_list_copy; -} - - -RLM_API void realm_dart_apikey_list_callback(realm_userdata_t userdata, realm_app_user_apikey_t apikey_list[], size_t count, const realm_app_error_t* error) { - auto error_copy = realm_app_error_copy(error); - auto apikey_list_copy = realm_apikey_list_copy(apikey_list, count); - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, apikey_list_buf = std::move(apikey_list_copy), error = std::move(error_copy)]() mutable { - std::vector apikey_list; - apikey_list.reserve(apikey_list_buf.size()); - std::transform( - apikey_list_buf.begin(), - apikey_list_buf.end(), - std::back_inserter(apikey_list), - [](const apikey_buf& apikey) { - return realm_app_user_apikey{ - apikey.id, - apikey.key_buffer.c_str(), - apikey.name_buffer.c_str(), - apikey.disabled - }; - } - ); - (reinterpret_cast(ud->dart_callback))(ud->handle, apikey_list.data(), apikey_list.size(), error.get()); - }); -} - -RLM_API void realm_dart_return_string_callback(realm_userdata_t userdata, const char* serialized_ejson_response, const realm_app_error_t* error) { - auto error_copy = realm_app_error_copy(error); - std::string buf{ serialized_ejson_response ? serialized_ejson_response : "" }; - - auto ud = reinterpret_cast(userdata); - ud->scheduler->invoke([ud, buf = std::move(buf), error = std::move(error_copy)]() mutable { - (reinterpret_cast(ud->dart_callback))(ud->handle, buf.data(), error.get()); - }); -} diff --git a/packages/realm_dart/src/realm_dart_sync.h b/packages/realm_dart/src/realm_dart_sync.h deleted file mode 100644 index 15952e013..000000000 --- a/packages/realm_dart/src/realm_dart_sync.h +++ /dev/null @@ -1,56 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2022 Realm Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -//////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include -typedef void (*realm_sync_before_client_reset_begin_func_t)(realm_userdata_t userdata, realm_t* before_realm, void* unlockFunc); - -typedef void (*realm_sync_after_client_reset_begin_func_t)(realm_userdata_t userdata, realm_t* before_realm, realm_thread_safe_reference_t* after_realm, bool did_recover, void* unlockFunc); - -RLM_API void realm_dart_http_request_callback(realm_userdata_t userdata, realm_http_request_t request, void* request_context); - -RLM_API void realm_dart_sync_error_handler_callback(realm_userdata_t userdata, realm_sync_session_t* session, realm_sync_error_t error); - -RLM_API void realm_dart_sync_wait_for_completion_callback(realm_userdata_t userdata, realm_error_t* error); - -RLM_API void realm_dart_sync_progress_callback(realm_userdata_t userdata, uint64_t transferred_bytes, uint64_t total_bytes, double estimate); - -RLM_API void realm_dart_sync_connection_state_changed_callback(realm_userdata_t userdata, - realm_sync_connection_state_e old_state, - realm_sync_connection_state_e new_state); - -RLM_API void realm_dart_user_change_callback(realm_userdata_t userdata, realm_user_state_e state); - -RLM_API void realm_dart_sync_on_subscription_state_changed_callback(realm_userdata_t userdata, realm_flx_sync_subscription_set_state_e state); - -RLM_API bool realm_dart_sync_before_reset_handler_callback(realm_userdata_t userdata, realm_t* realm); - -RLM_API bool realm_dart_sync_after_reset_handler_callback(realm_userdata_t userdata, realm_t* before_realm, realm_thread_safe_reference_t* after_realm, bool did_recover); - -RLM_API void realm_dart_async_open_task_callback(realm_userdata_t userdata, realm_thread_safe_reference_t* realm, const realm_async_error_t* error); - -RLM_API void realm_dart_user_completion_callback(realm_userdata_t userdata, realm_user_t* user, const realm_app_error_t* error); - -RLM_API void realm_dart_void_completion_callback(realm_userdata_t userdata, const realm_app_error_t* error); - -RLM_API void realm_dart_apikey_callback(realm_userdata_t userdata, realm_app_user_apikey_t* apikey, const realm_app_error_t* error); - -RLM_API void realm_dart_apikey_list_callback(realm_userdata_t userdata, realm_app_user_apikey_t apikey_list[], size_t count, const realm_app_error_t* error); - -RLM_API void realm_dart_return_string_callback(realm_userdata_t userdata, const char* serialized_ejson_response, const realm_app_error_t* error); diff --git a/packages/realm_dart/test/app_test.dart b/packages/realm_dart/test/app_test.dart deleted file mode 100644 index 684659e02..000000000 --- a/packages/realm_dart/test/app_test.dart +++ /dev/null @@ -1,419 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:convert'; -import 'dart:isolate'; - -import 'package:crypto/crypto.dart'; -import 'package:http/http.dart'; -import 'package:path/path.dart' as path; -import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/handles/realm_core.dart'; - -import 'test.dart'; -import 'utils/platform_util.dart'; - -void main() { - setupTests(); - - test('AppConfiguration can be initialized', () { - Configuration.defaultRealmPath = path.join(Configuration.defaultStoragePath, Configuration.defaultRealmName); - final defaultAppConfig = AppConfiguration('myapp'); - expect(defaultAppConfig.appId, 'myapp'); - expect(defaultAppConfig.baseFilePath, Configuration.defaultStoragePath); - expect(defaultAppConfig.baseUrl, Uri.parse('https://services.cloud.mongodb.com')); - expect(defaultAppConfig.defaultRequestTimeout, const Duration(minutes: 1)); - expect(defaultAppConfig.metadataPersistenceMode, MetadataPersistenceMode.plaintext); - - final httpClient = Client(); - final appConfig = AppConfiguration( - 'myapp1', - baseFilePath: platformUtil.systemTempPath, - baseUrl: Uri.parse('https://not_re.al'), - defaultRequestTimeout: const Duration(seconds: 2), - metadataPersistenceMode: MetadataPersistenceMode.disabled, - maxConnectionTimeout: const Duration(minutes: 1), - httpClient: httpClient, - ); - expect(appConfig.appId, 'myapp1'); - expect(appConfig.baseFilePath, platformUtil.systemTempPath); - expect(appConfig.baseUrl, Uri.parse('https://not_re.al')); - expect(appConfig.defaultRequestTimeout, const Duration(seconds: 2)); - expect(appConfig.metadataPersistenceMode, MetadataPersistenceMode.disabled); - expect(appConfig.maxConnectionTimeout, const Duration(minutes: 1)); - expect(appConfig.httpClient, httpClient); - }); - - test('AppConfiguration can be created with defaults', () { - final appConfig = AppConfiguration('myapp1'); - expect(appConfig.appId, 'myapp1'); - expect(appConfig.baseUrl, Uri.parse('https://services.cloud.mongodb.com')); - expect(appConfig.defaultRequestTimeout, const Duration(minutes: 1)); - expect(appConfig.metadataPersistenceMode, MetadataPersistenceMode.plaintext); - expect(appConfig.maxConnectionTimeout, const Duration(minutes: 2)); - expect(appConfig.httpClient, isNotNull); - - // Check that the app constructor works - App(appConfig); - }); - - test('AppConfiguration can be created', () { - final httpClient = Client(); - final appConfig = AppConfiguration( - 'myapp1', - baseFilePath: platformUtil.systemTempPath, - baseUrl: Uri.parse('https://not_re.al'), - defaultRequestTimeout: const Duration(seconds: 2), - metadataPersistenceMode: MetadataPersistenceMode.encrypted, - metadataEncryptionKey: base64.decode("ekey"), - maxConnectionTimeout: const Duration(minutes: 1), - httpClient: httpClient, - ); - - expect(appConfig.appId, 'myapp1'); - expect(appConfig.baseFilePath, platformUtil.systemTempPath); - expect(appConfig.baseUrl, Uri.parse('https://not_re.al')); - expect(appConfig.defaultRequestTimeout, const Duration(seconds: 2)); - expect(appConfig.metadataPersistenceMode, MetadataPersistenceMode.encrypted); - expect(appConfig.maxConnectionTimeout, const Duration(minutes: 1)); - expect(appConfig.httpClient, httpClient); - - // Check that the app constructor works - App(appConfig); - }); - - test('App can be created', () async { - final configuration = AppConfiguration(generateRandomString(10)); - final app = App(configuration); - expect(app.id, configuration.appId); - }); - - test('AppConfiguration.baseUrl points to the correct value', () { - final configuration = AppConfiguration('abc'); - expect(configuration.baseUrl, Uri.parse('https://services.cloud.mongodb.com')); - }); - - baasTest('App log in', (configuration) async { - final app = App(configuration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - expect(user.state, UserState.loggedIn); - expect(user.refreshToken, isNotEmpty); - expect(user.accessToken, isNotEmpty); - }); - - test('Application get all users', () { - final configuration = AppConfiguration(generateRandomString(10)); - final app = App(configuration); - var users = app.users; - expect(users.isEmpty, true); - }); - - baasTest('App remove user', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - expect(user.state, UserState.loggedIn); - await app.removeUser(user); - expect(user.state, UserState.removed); - }); - - baasTest('App log out anonymous user is marked as removed', (configuration) async { - final app = App(configuration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - expect(user.state, UserState.loggedIn); - await user.logOut(); - expect(user.state, UserState.removed); - }); - - baasTest('App remove anonymous user', (configuration) async { - final app = App(configuration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - expect(user.state, UserState.loggedIn); - await app.removeUser(user); - expect(user.state, UserState.removed); - }); - - baasTest('App get current user', (configuration) async { - final app = App(configuration); - final credentials = Credentials.anonymous(); - expect(app.currentUser, isNull); - - final user = await app.logIn(credentials); - - expect(app.currentUser, isNotNull); - expect(app.currentUser, user); - }); - - baasTest('App switch user', (configuration) async { - final app = App(configuration); - expect(app.currentUser, isNull); - - final user1 = await app.logIn(Credentials.anonymous()); - expect(app.currentUser, user1); - - final user2 = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - expect(app.currentUser, user2); - - app.switchUser(user1); - expect(app.currentUser, user1); - }); - - baasTest('App get users', (configuration) async { - final app = App(configuration); - expect(app.currentUser, isNull); - expect(app.users.length, 0); - - final user = await app.logIn(Credentials.anonymous()); - final user1 = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - expect(app.users, {user1, user}); - }); - - baasTest('App delete user', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = getAutoverifiedEmail(); - const String strongPassword = "SWV23R#@T#VFQDV"; - await authProvider.registerUser(username, strongPassword); - final user = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - expect(user, isNotNull); - expect(user.state, UserState.loggedIn); - - await app.deleteUser(user); - expect(user.state, UserState.removed); - - await expectLater( - () => loginWithRetry(app, Credentials.emailPassword(username, strongPassword)), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), - ); - }); - - baasTest('Call Atlas function that does not exist', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - await expectLater(user.functions.call('notExisitingFunction'), throws("function not found")); - }); - - baasTest('Call Atlas function with no arguments', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - final dynamic response = await user.functions.call('userFuncNoArgs'); - expect(response, isNotNull); - }); - - baasTest('Call Atlas function on background isolate', (configuration) async { - final app = App(configuration); - final appId = app.id; - expect(Isolate.run( - () async { - final app = App.getById(appId)!; - final user = await app.logIn(Credentials.anonymous()); - await user.functions.call('userFuncNoArgs'); - }, - ), completes); - }); - - baasTest('Call Atlas function with one argument', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - const arg1 = 'Jhonatan'; - final dynamic response = await user.functions.call('userFuncOneArg', [arg1]); - expect(response, isNotNull); - final map = response as Map; - expect(map['arg'], arg1); - }); - - baasTest('Call Atlas function with two arguments', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - const arg1 = 'Jhonatan'; - const arg2 = 'Michael'; - final dynamic response = await user.functions.call('userFuncTwoArgs', [arg1, arg2]); - expect(response, isNotNull); - final map = response as Map; - expect(map['arg1'], arg1); - expect(map['arg2'], arg2); - }); - - baasTest('Call Atlas function with two arguments but pass one', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - const arg1 = 'Jhonatan'; - final dynamic response = await user.functions.call('userFuncTwoArgs', [arg1]); - expect(response, isNotNull); - final map = response as Map; - expect(map['arg1'], arg1); - expect(map['arg2'], {'\$undefined': true}); - }); - - baasTest('Call Atlas function with two Object arguments', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - final arg1 = Person("Jhonatan"); - final arg2 = Person('Michael'); - final dynamic response = await user.functions.call('userFuncTwoArgs', [arg1.toJson(), arg2.toJson()]); - expect(response, isNotNull); - final map = response as Map; - final receivedPerson1 = PersonExt.fromJson(map['arg1'] as Map); - final receivedPerson2 = PersonExt.fromJson(map['arg2'] as Map); - expect(receivedPerson1.name, arg1.name); - expect(receivedPerson2.name, arg2.name); - }); - - baasTest('App.reconnect', (appConfiguration) async { - final app = App(appConfiguration); - final realm = await getIntegrationRealm(app: app); - final session = realm.syncSession; - - // TODO: We miss a way to force a disconnect. Once we implement GenericNetworkTransport - // we can inject a fake HttpClient to toggle connectivity. - // <-- force disconnect here - session.pause(); // ensure we go to ConnectionState.disconnected immediately - expect(session.connectionState, ConnectionState.disconnected); - - expectLater( - session.connectionStateChanges.map((c) => c.current).distinct(), - emitsInOrder([ - ConnectionState.connecting, - ConnectionState.connected, - ]), - ); - - session.resume(); - app.reconnect(); // <-- this is not currently needed for this test to pass see above - }); - - baasTest('App switch to logout user throws', (configuration) async { - final app = App(configuration); - expect(app.currentUser, isNull); - - final user1 = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - await user1.logOut(); - - final user2 = await app.logIn(Credentials.anonymous()); - expect(app.currentUser, user2); - expect( - () => app.switchUser(user1), - throws("User is no longer valid or is logged out"), - ); - }); - - baasTest('App get Base URL', (configuration) async { - final app = App(configuration); - expect(app.baseUrl, configuration.baseUrl); - }); - - baasTest('App update Base URL', (appConfig) async { - final config = await baasHelper!.getAppConfig(customBaseUrl: 'https://services.cloud.mongodb.com'); - final app = App(config); - expect(app.baseUrl, Uri.parse('https://services.cloud.mongodb.com')); - // Set it to the same thing to confirm the function works, it's not actually going to update the location - await app.updateBaseUrl(Uri.parse(baasHelper!.baseUrl)); - expect(app.baseUrl, appConfig.baseUrl); - expect(app.baseUrl, isNot(Uri.parse('https://services.cloud.mongodb.com'))); - }); - - test('bundleId is salted, hashed and encoded', () { - final text = isFlutterPlatform ? "realm_tests" : "realm_dart"; - const salt = [82, 101, 97, 108, 109, 32, 105, 115, 32, 103, 114, 101, 97, 116]; - final expected = base64Encode(sha256.convert([...salt, ...utf8.encode(text)]).bytes); - expect(realmCore.getBundleId(), expected); - }); - - test('app.getById without apps returns null', () { - clearCachedApps(); - final app = App.getById('abc'); - expect(app, null); - }); - - test('app.logIn unsuccessful logIn attempt on background isolate', () { - // This test was introduced due to: https://github.com/realm/realm-dart/issues/1467 - const appId = 'fake-app-id'; - App(AppConfiguration(appId, baseUrl: Uri.parse('https://this-is-a-fake-url.com'))); - expect(Isolate.run( - () async { - final app = App.getById(appId); - await app!.logIn(Credentials.anonymous()); // <-- this line used to crash - }, - ), throwsA(isA())); - }); - - baasTest('app.logIn successful logIn on background isolate', (configuration) { - // This test was introduced due to: https://github.com/realm/realm-dart/issues/1467 - final appId = configuration.appId; - App(configuration); - expect(Isolate.run( - () async { - final app = App.getById(appId); - await app!.logIn(Credentials.anonymous()); // <-- this line used to crash - }, - ), completes); - }); - - baasTest('app.getById with different baseUrl returns null', (appConfig) { - final app = App(appConfig); - expect(App.getById(app.id, baseUrl: Uri.parse('https://foo.bar')), null); - expect(App.getById(app.id, baseUrl: appConfig.baseUrl), isNotNull); - }); - - baasTest('App(AppConfiguration) on background isolate logs warning', (appConfig) async { - Realm.logger.setLogLevel(LogLevel.warn); - - final sb = StringBuffer(); - Realm.logger.onRecord.listen((event) { - sb.writeln('${event.category} ${event.level}: ${event.message}'); - }); - - await Isolate.run(() { - App(AppConfiguration('abc')); - }); - - final log = sb.toString(); - - expect(log, contains('App constructor called on Isolate')); - }); - - test('AppConfiguration(empty-id) throws', () { - expect(() => AppConfiguration(''), throwsA(isA())); - }); - - baasTest('AppConfiguration.syncTimeouts are passed correctly to Core', (appConfig) async { - Realm.logger.setLogLevel(LogLevel.debug); - final buffer = StringBuffer(); - final sub = Realm.logger.onRecord.listen((r) => buffer.writeln('[${r.category}] ${r.level}: ${r.message}')); - - final customConfig = AppConfiguration(appConfig.appId, - baseUrl: appConfig.baseUrl, - baseFilePath: appConfig.baseFilePath, - defaultRequestTimeout: appConfig.defaultRequestTimeout, - syncTimeoutOptions: SyncTimeoutOptions( - connectTimeout: Duration(milliseconds: 1234), - connectionLingerTime: Duration(milliseconds: 3456), - pingKeepAlivePeriod: Duration(milliseconds: 5678), - pongKeepAliveTimeout: Duration(milliseconds: 7890), - fastReconnectLimit: Duration(milliseconds: 9012))); - - final realm = await getIntegrationRealm(appConfig: customConfig); - await realm.syncSession.waitForDownload(); - - final log = buffer.toString(); - expect(log, contains('Config param: connect_timeout = 1234 ms')); - expect(log, contains('Config param: connection_linger_time = 3456 ms')); - expect(log, contains('Config param: ping_keepalive_period = 5678 ms')); - expect(log, contains('Config param: pong_keepalive_timeout = 7890 ms')); - expect(log, contains('Config param: fast_reconnect_limit = 9012 ms')); - - await sub.cancel(); - }); -} - -extension PersonExt on Person { - static Person fromJson(Map json) => Person(json['name'] as String); - Map toJson() => {'name': name}; -} diff --git a/packages/realm_dart/test/asymmetric_test.dart b/packages/realm_dart/test/asymmetric_test.dart deleted file mode 100644 index 8bd4d5841..000000000 --- a/packages/realm_dart/test/asymmetric_test.dart +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2023 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:test/expect.dart' hide throws; - -import 'package:realm_dart/realm.dart'; -import 'test.dart'; - -void main() { - setupTests(); - - baasTest('Asymmetric objects die even before upload', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - realm.syncSession.pause(); - - final oid = ObjectId(); - realm.write(() { - realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new))); - }); - - // Find & query on an Asymmetric object is compile time error, but you can cheat with dynamic - expect(realm.dynamic.find('Asymmetric', oid), null); - expect(() => realm.dynamic.all('Asymmetric'), throws('Query on ephemeral objects not allowed')); - - realm.syncSession.resume(); - await realm.syncSession.waitForUpload(); - }); - - baasTest('Asymmetric re-add same PK', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - - final oid = ObjectId(); - realm.write(() { - realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3].map(Embedded.new))); - expect(() => realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3, 4].map(Embedded.new))), - throws("Attempting to create an object of type 'Asymmetric' with an existing primary key value")); - }); - - realm.write(() { - // okay to ingest again in another transaction, because object already dead to us - realm.ingest(Asymmetric(oid, embeddedObjects: [1, 2, 3, 5].map(Embedded.new))); - }); - - await realm.syncSession.waitForUpload(); - }); - - baasTest('Asymmetric add non-embedded links', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - }); - - realm.write(() { - final s = realm.add(Symmetric(ObjectId())); - realm.ingest(Asymmetric(ObjectId(), symmetric: s)); - realm.ingest(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, symmetric: s)])); - realm.ingest(Asymmetric(ObjectId(), embeddedObjects: [Embedded(1, any: RealmValue.from(s))])); - }); - - await realm.syncSession.waitForUpload(); - }); - - test("Asymmetric don't work local realms", () { - expect(() => Realm(Configuration.local([Asymmetric.schema, Embedded.schema, Symmetric.schema])), - throws("Asymmetric table 'Asymmetric' not allowed in a local Realm")); - }); - - test("Asymmetric don't work with disconnectedSync", () { - final config = Configuration.disconnectedSync([Asymmetric.schema, Embedded.schema, Symmetric.schema], path: generateRandomRealmPath()); - expect(() => Realm(config), throws()); - }); - - // TODO - // Test that asymmetric objects are actually transferred to backend, once we have - // a mongoClient to query the backend with. -} diff --git a/packages/realm_dart/test/baas_helper.dart b/packages/realm_dart/test/baas_helper.dart deleted file mode 100644 index 66154823e..000000000 --- a/packages/realm_dart/test/baas_helper.dart +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/cli/atlas_apps/baas_client.dart'; -import 'package:realm_dart/src/handles/realm_core.dart'; -import 'package:test/test.dart' as testing; - -import 'utils/platform_util.dart'; - -export 'package:realm_dart/src/cli/atlas_apps/baas_client.dart' show AppName; - -const String publicRSAKeyForJWTValidation = '''-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvNHHs8T0AHD7SJ+CKvVR -leeJa4wqYTnaVYV+5bX9FmFXVoN+vHbMLEteMvSw4L3kSRZdcqxY7cTuhlpAvkXP -Yq6qSI+bW8T4jGW963uCc83UhVMx4MH/PzipAlfcPjVO2u4c+dmpgZQpgEmA467u -tauXUhmTsGpgNg2Gvc61B7Ny4LphshsyrfaJ9WjA/NM6LOmEBW3JPNcVG2qyU+gt -O8BM8KOSx9wGyoGs4+OusvRkJizhPaIwa3FInLs4r+xZW9Bp6RndsmVECtvXRv5d -87ztpg6o3DZJRmTp2lAnkNLmxXlFkOSNIwiT3qqyRZOh4DuxPOpfg9K+vtFmRdEJ -RwIDAQAB ------END PUBLIC KEY-----'''; - -enum Env { - baasUrl('BAAS_URL', String.fromEnvironment('BAAS_URL')), - baasCluster('BAAS_CLUSTER', String.fromEnvironment('BAAS_CLUSTER')), - baasApiKey('BAAS_API_KEY', String.fromEnvironment('BAAS_API_KEY')), - baasPrivateApiKey('BAAS_PRIVATE_API_KEY', String.fromEnvironment('BAAS_PRIVATE_API_KEY')), - baasProjectId('BAAS_PROJECT_ID', String.fromEnvironment('BAAS_PROJECT_ID')), - baasAasApiKey('BAAS_BAASAAS_API_KEY', String.fromEnvironment('BAAS_BAASAAS_API_KEY')), - differentiator('BAAS_DIFFERENTIATOR', String.fromEnvironment('BAAS_DIFFERENTIATOR')), - ; - - final String name; - final String _dartDefined; - - const Env(this.name, this._dartDefined); - - String? get dartDefined => _dartDefined.emptyAsNull; - String? get shellDefined => platformUtil.environment[name]; - String? get value => dartDefined ?? shellDefined; - - bool get isDefined => value != null; - bool get isNotDefined => !isDefined; - - String? call() => value; -} - -extension on String? { - String? get emptyAsNull { - final self = this; - if (self == null || self.isEmpty) return null; - return self; - } -} - -class BaasHelper { - final BaasClient _baasClient; - final _baasApps = {}; - - String get baseUrl => _baasClient.baseUrl; - - static Object? _error; - - static Future setupBaas() async { - try { - final client = await _setupClient(); - if (client == null) { - return null; - } - - final result = BaasHelper._(client); - - await result._setupApps(); - - return result; - } catch (e) { - print(e); - _error = e; - rethrow; - } - } - - static bool get shouldRunBaasTests { - return Env.baasUrl.isDefined || Env.baasAasApiKey.isDefined; - } - - BaasHelper._(this._baasClient); - - static Future _setupClient() async { - var baasUrl = Env.baasUrl(); - final cluster = Env.baasCluster(); - final apiKey = Env.baasApiKey(); - final privateApiKey = Env.baasPrivateApiKey(); - final projectId = Env.baasProjectId(); - final differentiator = Env.differentiator() ?? 'local'; - - if (baasUrl == null) { - final baasAasApiKey = Env.baasAasApiKey(); - if (baasAasApiKey != null) { - if (cluster != null) { - throw "BAAS_BAASAAS_API_KEY can't be combined with BAAS_CLUSTER"; - } - - (baasUrl, _) = await BaasClient.retry(() => BaasClient.getOrDeployContainer( - baasAasApiKey, - differentiator, - )); - } - } - - if (baasUrl == null) { - return null; - } - - final client = await BaasClient.retry(() => (cluster == null - ? BaasClient.docker(baasUrl!, differentiator) - : BaasClient.atlas(baasUrl!, cluster, apiKey!, privateApiKey!, projectId!, differentiator))); - - client.publicRSAKey = publicRSAKeyForJWTValidation; - return client; - } - - Future _setupApps() async { - try { - final apps = await _baasClient.getOrCreateApps(); - - for (final app in apps) { - _baasApps[app.name] = app; - if (app.name == AppName.flexible.name || app.name == AppName.staticSchema.name) { - await _waitForInitialSync(app); - } - } - } catch (error) { - print(error); - _error = error; - } - } - - Future _waitForInitialSync(BaasApp app) async { - while (true) { - try { - print('Validating initial sync for $app is complete...'); - await _baasClient.waitForInitialSync(app); - return; - } catch (e) { - print(e); - } finally { - realmCore.clearCachedApps(); - } - } - } - - Future createServerApiKey(App app, String name, {bool enabled = true}) { - final baasApp = _baasApps.values.firstWhere((ba) => ba.clientAppId == app.id); - return _baasClient.createApiKey(baasApp.appId, name, enabled); - } - - static void throwIfSetupFailed() { - if (_error != null) { - throw _error!; - } - } - - void printSplunkLogLink(AppName appName, String? uriVariable) { - if (uriVariable == null) { - return; - } - - final app = _baasApps[appName.name] ?? (throw RealmError("No BAAS apps")); - final baasUri = Uri.parse(uriVariable); - - testing.printOnFailure("App service name: ${app.uniqueName}"); - final host = baasUri.host.endsWith('-qa.mongodb.com') ? "-qa" : ""; - final splunk = Uri.encodeFull( - "https://splunk.corp.mongodb.com/en-US/app/search/search?q=search index=baas$host \"${app.uniqueName}-*\" | reverse | top error msg&earliest=-7d&latest=now&display.general.type=visualizations"); - testing.printOnFailure("Splunk logs: $splunk"); - } - - Future getAppConfig({AppName appName = AppName.flexible, String? customBaseUrl}) => - _getAppConfig(appName.name, customBaseUrl: customBaseUrl); - - Future _getAppConfig(String appName, {String? customBaseUrl}) async { - final app = _baasApps[appName] ?? - _baasApps.values.firstWhere((element) => element.name == BaasClient.defaultAppName, orElse: () => throw RealmError("No BAAS apps")); - if (app.error != null) { - throw app.error!; - } - - final temporaryPath = await platformUtil.createTempPath(); - return AppConfiguration( - app.clientAppId, - baseUrl: Uri.parse(customBaseUrl ?? baseUrl), - baseFilePath: temporaryPath, - defaultRequestTimeout: Duration(minutes: 7), - ); - } - - String getClientAppId({AppName appName = AppName.flexible}) => _baasApps[appName.name]!.clientAppId; - - Future disableAutoRecoveryForApp(AppName appName) async { - await _baasClient.setAutomaticRecoveryEnabled(appName.name, false); - } - - Future enableAutoRecoveryForApp(AppName appName) async { - await _baasClient.setAutomaticRecoveryEnabled(appName.name, true); - } - - Future triggerClientReset(Realm realm, {bool restartSession = true}) async { - final config = realm.config; - if (config is! FlexibleSyncConfiguration) { - throw RealmError('This should only be invoked for sync realms'); - } - - final session = realm.syncSession; - if (restartSession) { - session.pause(); - } - - final userId = config.user.id; - final appId = _baasApps.values.firstWhere((element) => element.clientAppId == config.user.app.id).appId; - - for (var i = 0; i < 5; i++) { - try { - final result = await config.user.functions.call('triggerClientResetOnSyncServer', [userId, appId]) as Map; - if (result['status'] != 'success') { - throw 'Unsuccessful status: ${result['status']}'; - } - break; - } catch (e) { - if (i == 4) { - rethrow; - } - - print('Failed to trigger client reset: $e'); - await Future.delayed(Duration(seconds: i)); - } - } - - if (restartSession) { - session.resume(); - } - } -} diff --git a/packages/realm_dart/test/client_reset_test.dart b/packages/realm_dart/test/client_reset_test.dart deleted file mode 100644 index 3f96576d3..000000000 --- a/packages/realm_dart/test/client_reset_test.dart +++ /dev/null @@ -1,625 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; - -import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/configuration.dart' show ClientResetHandlerInternal, ClientResyncModeInternal; -import 'test.dart'; - -const defaultWaitTimeout = Duration(seconds: 300); - -void main() { - setupTests(); - - baasTest("Configuration.flexibleSync set recoverOrDiscard as a default resync mode", (appConfiguration) async { - final user = await getIntegrationUser(appConfig: appConfiguration); - expect( - Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: ManualRecoveryHandler((syncError) {}), - ).clientResetHandler.clientResyncMode, - ClientResyncModeInternal.manual); - expect( - Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: const DiscardUnsyncedChangesHandler(), - ).clientResetHandler.clientResyncMode, - ClientResyncModeInternal.discardLocal); - expect( - Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: const RecoverUnsyncedChangesHandler(), - ).clientResetHandler.clientResyncMode, - ClientResyncModeInternal.recover); - - expect( - Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: const RecoverOrDiscardUnsyncedChangesHandler(), - ).clientResetHandler.clientResyncMode, - ClientResyncModeInternal.recoverOrDiscard); - - expect(Configuration.flexibleSync(user, getSyncSchema()).clientResetHandler.clientResyncMode, ClientResyncModeInternal.recoverOrDiscard); - }); - - baasTest('ManualRecoveryHandler error is reported in callback', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final resetCompleter = Completer(); - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: ManualRecoveryHandler((syncError) { - resetCompleter.completeError(syncError); - }), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.triggerClientReset(realm); - final clientResetFuture = resetCompleter.future.wait(defaultWaitTimeout, "ManualRecoveryHandler is not reported."); - await expectLater(clientResetFuture, throws('Bad client file identifier')); - }); - - baasTest('Initiate resetRealm after ManualRecoveryHandler callback', (appConfig) async { - final app = App(appConfig); - final user = await getAnonymousUser(app); - - final resetCompleter = Completer(); - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: ManualRecoveryHandler((clientResetError) { - resetCompleter.completeError(clientResetError); - }), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - final resetRealmFuture = resetCompleter.future.onError((error, stackTrace) { - final clientResetError = error as ClientResetError; - realm.close(); - clientResetError.resetRealm(); - }, test: (error) => error is ClientResetError); - - await baasHelper!.triggerClientReset(realm); - - await resetRealmFuture.wait(defaultWaitTimeout, "ManualRecoveryHandler is not reported."); - - expect(Realm.existsSync(config.path), isFalse); - }); - - baasTest('Initiate resetRealm after ManualRecoveryHandler callback fails when Realm is opened', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final resetCompleter = Completer(); - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: ManualRecoveryHandler((clientResetError) { - resetCompleter.completeError(clientResetError); - }), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - final resetRealmFuture = resetCompleter.future.onError((error, stackTrace) { - final clientResetError = error as ClientResetError; - return clientResetError.resetRealm(); - }, test: (error) => error is ClientResetError); - - await baasHelper!.triggerClientReset(realm); - - expect(await resetRealmFuture.timeout(defaultWaitTimeout), !Platform.isWindows); - expect(Realm.existsSync(config.path), Platform.isWindows); // posix and windows semantics are different - }); - - for (Type clientResetHandlerType in [ - RecoverOrDiscardUnsyncedChangesHandler, - RecoverUnsyncedChangesHandler, - DiscardUnsyncedChangesHandler, - ]) { - baasTest('$clientResetHandlerType.onManualResetFallback invoked when throw in onBeforeReset', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final onManualResetFallback = Completer(); - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: Creator.create( - clientResetHandlerType, - onBeforeReset: (beforeResetRealm) => throw Exception("This fails!"), - onManualResetFallback: (clientResetError) => onManualResetFallback.completeError(clientResetError), - )); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.triggerClientReset(realm); - - final clientResetFuture = onManualResetFallback.future.wait(defaultWaitTimeout, "onManualResetFallback is not reported."); - await expectLater( - clientResetFuture, - throwsA(isA().having((e) => e.code, 'code', SyncErrorCode.autoClientResetFailed)), - ); - }); - - baasTest('$clientResetHandlerType.onManualResetFallback invoked when throw in onAfterReset', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final onManualResetFallback = Completer(); - void onAfterReset(Realm beforeResetRealm, Realm afterResetRealm) { - throw Exception("This fails too!"); - } - - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: Creator.create( - clientResetHandlerType, - onAfterRecovery: clientResetHandlerType != DiscardUnsyncedChangesHandler ? onAfterReset : null, - onAfterDiscard: clientResetHandlerType != RecoverUnsyncedChangesHandler ? onAfterReset : null, - onManualResetFallback: (clientResetError) => onManualResetFallback.completeError(clientResetError), - )); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.triggerClientReset(realm); - - final clientResetFuture = onManualResetFallback.future.wait(defaultWaitTimeout, "onManualResetFallback is not reported."); - await expectLater( - clientResetFuture, - throwsA(isA().having((e) => e.code, 'code', SyncErrorCode.autoClientResetFailed)), - ); - }); - - baasTest('$clientResetHandlerType.onBeforeReset and onAfterReset are invoked', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final onBeforeCompleter = Completer(); - final onAfterCompleter = Completer(); - void onAfterReset(Realm beforeResetRealm, Realm afterResetRealm) { - onAfterCompleter.complete(); - } - - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: Creator.create( - clientResetHandlerType, - onBeforeReset: (beforeResetRealm) => onBeforeCompleter.complete(), - onAfterRecovery: clientResetHandlerType != DiscardUnsyncedChangesHandler ? onAfterReset : null, - onAfterDiscard: clientResetHandlerType != RecoverUnsyncedChangesHandler ? onAfterReset : null, - )); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.triggerClientReset(realm); - - await onBeforeCompleter.future.timeout(defaultWaitTimeout, onTimeout: () => throw TimeoutException("onBeforeReset is not reported")); - await onAfterCompleter.future.timeout(defaultWaitTimeout, onTimeout: () => throw TimeoutException("onAfterReset is not reported.")); - }); - - if (clientResetHandlerType != RecoverUnsyncedChangesHandler) { - final baasAppName = AppName.flexible; - final shouldDisableAutoRecoveryForApp = clientResetHandlerType == RecoverOrDiscardUnsyncedChangesHandler; - baasTest('$clientResetHandlerType notifications for deleted local data when DiscardUnsynced', appName: baasAppName, (appConfig) async { - try { - final user = await getIntegrationUser(appConfig: appConfig); - int onBeforeResetOccurred = 0; - int onAfterDiscardOccurred = 0; - int onAfterRecoveryOccurred = 0; - final onAfterCompleter = Completer(); - - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: Creator.create( - clientResetHandlerType, - onBeforeReset: (beforeResetRealm) => onBeforeResetOccurred++, - onAfterRecovery: (beforeResetRealm, afterResetRealm) { - onAfterRecoveryOccurred++; - }, - onAfterDiscard: (beforeResetRealm, afterResetRealm) { - onAfterDiscardOccurred++; - onAfterCompleter.complete(); - }, - onManualResetFallback: (clientResetError) => onAfterCompleter.completeError(clientResetError), - )); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - final objectId = ObjectId(); - final addedObjectId = ObjectId(); - final query = realm.query(r'_id IN $0', [ - [objectId, addedObjectId] - ]); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - await realm.subscriptions.waitForSynchronization(); - await realm.syncSession.waitForDownload(); - final tasksCount = query.length; - - realm.syncSession.pause(); - - realm.write(() => realm.add(Task(addedObjectId))); - expect(tasksCount, lessThan(query.length)); - - final notifications = []; - final subscription = query.changes.listen((event) { - notifications.add(event); - }); - - await waitForCondition(() => notifications.length == 1, timeout: Duration(seconds: 3)); - if (shouldDisableAutoRecoveryForApp) { - await baasHelper!.disableAutoRecoveryForApp(baasAppName); - } - await baasHelper!.triggerClientReset(realm, restartSession: false); - realm.syncSession.resume(); - await onAfterCompleter.future.wait(defaultWaitTimeout, "Neither onAfterDiscard nor onManualResetFallback is reported."); - - await waitForCondition(() => notifications.length == 2, timeout: Duration(seconds: 3)); - - expect(onBeforeResetOccurred, 1); - expect(onAfterDiscardOccurred, 1); - expect(onAfterRecoveryOccurred, 0); - - await subscription.cancel(); - expect(notifications.firstWhere((n) => n.deleted.isNotEmpty), isNotNull); - } finally { - if (shouldDisableAutoRecoveryForApp) { - await baasHelper!.enableAutoRecoveryForApp(baasAppName); - } - } - }); - } - - baasTest('$clientResetHandlerType check data in beforeResetRealm realm and after realm when recover or discard', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final onAfterCompleter = Completer(); - - final syncedId = ObjectId(); - final maybeId = ObjectId(); - - comparer(Product p1, ObjectId expectedId) => p1.id == expectedId; - - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: Creator.create( - clientResetHandlerType, - onBeforeReset: (beforeResetRealm) { - _checkProducts(beforeResetRealm, comparer, expectedList: [syncedId, maybeId]); - }, - onAfterRecovery: (beforeResetRealm, afterResetRealm) { - _checkProducts(beforeResetRealm, comparer, expectedList: [syncedId, maybeId]); - _checkProducts(afterResetRealm, comparer, expectedList: [syncedId, maybeId]); - onAfterCompleter.complete(); - }, - onAfterDiscard: (beforeResetRealm, afterResetRealm) { - _checkProducts(beforeResetRealm, comparer, expectedList: [syncedId, maybeId]); - _checkProducts(afterResetRealm, comparer, expectedList: [syncedId], notExpectedList: [maybeId]); - onAfterCompleter.complete(); - }, - onManualResetFallback: (clientResetError) => onAfterCompleter.completeError(clientResetError), - )); - - final realm = await getRealmAsync(config); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id IN $0', [ - [syncedId, maybeId] - ])); - }); - await realm.subscriptions.waitForSynchronization(); - - realm.write(() => realm.add(Product(syncedId, "always synced"))); - await realm.syncSession.waitForUpload(); - - realm.syncSession.pause(); - realm.write(() => realm.add(Product(maybeId, "maybe synced"))); - - await baasHelper!.triggerClientReset(realm, restartSession: false); - realm.syncSession.resume(); - await onAfterCompleter.future.wait(defaultWaitTimeout, "Neither onAfterDiscard, onAfterDiscard nor onManualResetFallback is reported."); - }); - } - - { - final baasAppName = AppName.flexible; - baasTest('Disabled server recovery - onAfterDiscard callback is invoked for RecoverOrDiscardUnsyncedChangesHandler', appName: baasAppName, - (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final onBeforeCompleter = Completer(); - final onAfterCompleter = Completer(); - bool recovery = false; - bool discard = false; - - final config = Configuration.flexibleSync(user, getSyncSchema(), - clientResetHandler: RecoverOrDiscardUnsyncedChangesHandler( - onBeforeReset: (beforeResetRealm) => onBeforeCompleter.complete(), - onAfterRecovery: (Realm beforeResetRealm, Realm afterResetRealm) { - onAfterCompleter.complete(); - recovery = true; - }, - onAfterDiscard: (Realm beforeResetRealm, Realm afterResetRealm) { - onAfterCompleter.complete(); - discard = true; - }, - )); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.disableAutoRecoveryForApp(baasAppName); - try { - await baasHelper!.triggerClientReset(realm); - - await onBeforeCompleter.future.wait(defaultWaitTimeout, "onBeforeReset is not reported."); - await onAfterCompleter.future.wait(defaultWaitTimeout, "Neither onAfterRecovery nor onAfterDiscard is reported."); - - expect(recovery, isFalse); - expect(discard, isTrue); - } finally { - await baasHelper!.enableAutoRecoveryForApp(baasAppName); - } - }); - } - - baasTest('onAfterReset is reported after async onBeforeReset completes', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - int onBeforeResetOccurred = 0; - int onAfterResetOccurred = 0; - final onAfterCompleter = Completer(); - - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: DiscardUnsyncedChangesHandler( - onBeforeReset: (beforeResetRealm) async { - await Future.delayed(Duration(seconds: 1)); - onBeforeResetOccurred++; - }, - onAfterReset: (beforeResetRealm, afterResetRealm) { - if (onBeforeResetOccurred == 0) { - onAfterCompleter.completeError(Exception("BeforeResetCallback is still not completed")); - } - onAfterResetOccurred++; - onAfterCompleter.complete(); - }, - ), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - await baasHelper!.triggerClientReset(realm); - - await onAfterCompleter.future.wait(defaultWaitTimeout, "onAfterReset is not reported."); - - expect(onAfterResetOccurred, 1); - expect(onBeforeResetOccurred, 1); - }); - - baasTest('onManualResetFallback is reported after async onAfterReset throws', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - int onBeforeResetOccurred = 0; - int onAfterResetOccurred = 0; - int manualResetFallbackOccurred = 0; - final manualResetFallbackCompleter = Completer(); - - late ClientResetError clientResetErrorOnManualFallback; - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: DiscardUnsyncedChangesHandler( - onBeforeReset: (beforeResetRealm) { - onBeforeResetOccurred++; - }, - onAfterReset: (beforeResetRealm, afterResetRealm) async { - await Future.delayed(Duration(seconds: 1)); - onAfterResetOccurred++; - throw Exception("Cause onManualResetFallback"); - }, - onManualResetFallback: (clientResetError) { - manualResetFallbackOccurred++; - clientResetErrorOnManualFallback = clientResetError; - if (onAfterResetOccurred == 0) { - manualResetFallbackCompleter.completeError(Exception("AfterResetCallback is still not completed when onManualResetFallback starts.")); - } - manualResetFallbackCompleter.complete(); - }, - ), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - await baasHelper!.triggerClientReset(realm); - - await manualResetFallbackCompleter.future.wait(defaultWaitTimeout, "onManualResetFallback is not reported."); - - expect(manualResetFallbackOccurred, 1); - expect(onAfterResetOccurred, 1); - expect(onBeforeResetOccurred, 1); - - expect(clientResetErrorOnManualFallback.message, isNotEmpty); - expect(clientResetErrorOnManualFallback.innerError, isNotNull); - expect(clientResetErrorOnManualFallback.innerError.toString(), 'Exception: Cause onManualResetFallback'); - }); - - // 1. userA adds [task0, task1, task2] and syncs it, then disconnects - // 2. userB starts and downloads the same tasks, then disconnects - // 3. While offline, userA deletes task2 while userB inserts task3 - // 4. A client reset is triggered on the server - // 5. userA goes online and uploads the changes - // 6. only now userB goes online, downloads and merges the changes. userB will have [task0, task1, task3] - // 7. userA will also have [task0, task1, task3] - baasTest('RecoverUnsyncedChangesHandler integration test with two users', (appConfig) async { - final app = App(appConfig); - final afterRecoverCompleterA = Completer(); - final afterRecoverCompleterB = Completer(); - - final userA = await getAnonymousUser(app); - final userB = await getAnonymousUser(app); - final task0Id = ObjectId(); - final task1Id = ObjectId(); - final task2Id = ObjectId(); - final task3Id = ObjectId(); - List filterByIds = [task0Id, task1Id, task2Id, task3Id]; - comparer(Task t1, ObjectId id) => t1.id == id; - - final configA = Configuration.flexibleSync(userA, getSyncSchema(), clientResetHandler: RecoverUnsyncedChangesHandler( - onAfterReset: (beforeResetRealm, afterResetRealm) { - try { - _checkProducts(beforeResetRealm, comparer, expectedList: [task0Id, task1Id], notExpectedList: [task2Id, task3Id]); - _checkProducts(afterResetRealm, comparer, expectedList: [task0Id, task1Id], notExpectedList: [task2Id]); - afterRecoverCompleterA.complete(); - } catch (e) { - afterRecoverCompleterA.completeError(e); - } - }, - )); - - final configB = Configuration.flexibleSync(userB, getSyncSchema(), clientResetHandler: RecoverUnsyncedChangesHandler( - onAfterReset: (beforeResetRealm, afterResetRealm) { - try { - _checkProducts(beforeResetRealm, comparer, expectedList: [task0Id, task1Id, task2Id, task3Id]); - _checkProducts(afterResetRealm, comparer, expectedList: [task0Id, task1Id, task3Id], notExpectedList: [task2Id]); - afterRecoverCompleterB.complete(); - } catch (e) { - afterRecoverCompleterB.completeError(e); - } - }, - )); - - final realmA = await _syncRealmForUser(configA, filterByIds, [Task(task0Id), Task(task1Id), Task(task2Id)]); - final realmB = await _syncRealmForUser(configB, filterByIds); - - realmA.syncSession.pause(); - realmB.syncSession.pause(); - realmA.write(() { - final task2 = realmA.find(task2Id); - realmA.delete(task2!); - }); - - realmB.write(() => realmB.add(Task(task3Id))); - - await baasHelper!.triggerClientReset(realmA); - await realmA.syncSession.waitForUpload(); - await afterRecoverCompleterA.future.wait(defaultWaitTimeout, "onAfterReset for realmA is not reported."); - - await baasHelper!.triggerClientReset(realmB, restartSession: false); - realmB.syncSession.resume(); - await realmB.syncSession.waitForUpload(); - await afterRecoverCompleterB.future.wait(defaultWaitTimeout, "onAfterReset for realmB is not reported."); - - await realmA.syncSession.waitForDownload(); - - _checkProducts(realmA, comparer, expectedList: [task0Id, task1Id, task3Id], notExpectedList: [task2Id]); - _checkProducts(realmB, comparer, expectedList: [task0Id, task1Id, task3Id], notExpectedList: [task2Id]); - }); - - baasTest('ClientResetError details are received', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - final resetCompleter = Completer(); - late ClientResetError clientResetError; - final config = Configuration.flexibleSync( - user, - getSyncSchema(), - clientResetHandler: ManualRecoveryHandler((syncError) { - clientResetError = syncError; - resetCompleter.complete(); - }), - ); - - final realm = await getRealmAsync(config); - await realm.syncSession.waitForUpload(); - - await baasHelper!.triggerClientReset(realm); - await resetCompleter.future.wait(defaultWaitTimeout, "ClientResetError is not reported."); - - expect(clientResetError.message, isNotEmpty); - expect(clientResetError.backupFilePath, isNotEmpty); - }); -} - -Future _syncRealmForUser(FlexibleSyncConfiguration config, List filterByIds, [List? items]) async { - final realm = getRealm(config); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id IN $0', [filterByIds])); - }); - await realm.subscriptions.waitForSynchronization(); - - if (items != null) { - realm.write(() => realm.deleteAll()); - realm.write(() => realm.addAll(items)); - await realm.syncSession.waitForUpload(); - } - await realm.syncSession.waitForDownload(); - return realm; -} - -void _checkProducts(Realm realm, bool Function(T, ObjectId) truePredicate, - {required List expectedList, List? notExpectedList}) { - final all = realm.all(); - for (var expected in expectedList) { - if (!all.any((p) => truePredicate(p, expected))) { - throw Exception("Expected realm object does not exist"); - } - } - if (notExpectedList != null) { - for (var notExpected in notExpectedList) { - if (all.any((p) => truePredicate(p, notExpected))) { - throw Exception("Not expected realm object exists"); - } - } - } -} - -class Creator { - static final _constructors = { - RecoverOrDiscardUnsyncedChangesHandler: ( - {BeforeResetCallback? onBeforeReset, - AfterResetCallback? onAfterRecovery, - AfterResetCallback? onAfterDiscard, - ClientResetCallback? onManualResetFallback}) => - RecoverOrDiscardUnsyncedChangesHandler( - onBeforeReset: onBeforeReset, onAfterRecovery: onAfterRecovery, onAfterDiscard: onAfterDiscard, onManualResetFallback: onManualResetFallback), - RecoverUnsyncedChangesHandler: ( - {BeforeResetCallback? onBeforeReset, - AfterResetCallback? onAfterRecovery, - AfterResetCallback? onAfterDiscard, - ClientResetCallback? onManualResetFallback}) => - RecoverUnsyncedChangesHandler( - onBeforeReset: onBeforeReset, - onAfterReset: onAfterRecovery, - onManualResetFallback: onManualResetFallback, - ), - DiscardUnsyncedChangesHandler: ( - {BeforeResetCallback? onBeforeReset, - AfterResetCallback? onAfterRecovery, - AfterResetCallback? onAfterDiscard, - ClientResetCallback? onManualResetFallback}) => - DiscardUnsyncedChangesHandler( - onBeforeReset: onBeforeReset, - onAfterReset: onAfterDiscard, - onManualResetFallback: onManualResetFallback, - ), - }; - static ClientResetHandler create(Type type, - {BeforeResetCallback? onBeforeReset, - AfterResetCallback? onAfterRecovery, - AfterResetCallback? onAfterDiscard, - ClientResetCallback? onManualResetFallback}) { - return _constructors[type]!( - onBeforeReset: onBeforeReset, onAfterRecovery: onAfterRecovery, onAfterDiscard: onAfterDiscard, onManualResetFallback: onManualResetFallback); - } -} - -extension on Future { - Future wait(Duration duration, [String message = "Timeout waiting a future to complete."]) { - return timeout(duration, onTimeout: () => throw TimeoutException(message)); - } -} diff --git a/packages/realm_dart/test/configuration_test.dart b/packages/realm_dart/test/configuration_test.dart index f8c53a434..dd69343c5 100644 --- a/packages/realm_dart/test/configuration_test.dart +++ b/packages/realm_dart/test/configuration_test.dart @@ -60,60 +60,6 @@ void main() { expect(path.dirname(realm1.config.path), path.dirname(customDefaultRealmPath1)); }); - baasTest('Configuration defaultRealmName can be set for FlexibleSyncConfiguration', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - - var customDefaultRealmName = "myRealmName.realm"; - Configuration.defaultRealmName = customDefaultRealmName; - var config = Configuration.flexibleSync(user, getSyncSchema()); - expect(path.basename(config.path), path.basename(customDefaultRealmName)); - - var realm = getRealm(config); - expect(path.basename(realm.config.path), customDefaultRealmName); - - //set a new defaultRealmName - customDefaultRealmName = "anotherRealmName.realm"; - Configuration.defaultRealmName = customDefaultRealmName; - config = Configuration.flexibleSync(user, getSyncSchema()); - realm = getRealm(config); - expect(path.basename(realm.config.path), customDefaultRealmName); - }); - - baasTest('Configuration defaultRealmPath can be set for FlexibleSyncConfiguration', (_) async { - var customDefaultRealmPath = path.join(await platformUtil.createTempPath(), Configuration.defaultRealmName); - Configuration.defaultRealmPath = customDefaultRealmPath; - - final appClientId = baasHelper!.getClientAppId(appName: AppName.flexible); - final baasUrl = baasHelper!.baseUrl; - var appConfig = AppConfiguration(appClientId, baseUrl: Uri.parse(baasUrl)); - expect(appConfig.baseFilePath, path.dirname(customDefaultRealmPath)); - - var app = App(appConfig); - var user = await app.logIn(Credentials.anonymous()); - - var config = Configuration.flexibleSync(user, getSyncSchema()); - expect(path.dirname(config.path), startsWith(path.dirname(customDefaultRealmPath))); - - var realm = getRealm(config); - expect(path.dirname(realm.config.path), startsWith(path.dirname(customDefaultRealmPath))); - - //set a new defaultRealmPath - customDefaultRealmPath = path.join(await platformUtil.createTempPath(), Configuration.defaultRealmName); - Configuration.defaultRealmPath = customDefaultRealmPath; - - appConfig = AppConfiguration(appClientId, baseUrl: Uri.parse(baasUrl)); - expect(appConfig.baseFilePath, path.dirname(customDefaultRealmPath)); - - clearCachedApps(); - - app = App(appConfig); - user = await app.logIn(Credentials.anonymous()); - config = Configuration.flexibleSync(user, getSyncSchema()); - realm = getRealm(config); - expect(path.dirname(realm.config.path), startsWith(path.dirname(customDefaultRealmPath))); - }); - test('Configuration get/set path', () { final config = Configuration.local([Car.schema]); expect(config.path, endsWith('.realm')); @@ -474,71 +420,6 @@ void main() { }); } - baasTest('Configuration.flexibleSync shouldCompactCallback is invoked', (appConfig) async { - final app = App(appConfig); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - var invoked = false; - var config = Configuration.flexibleSync(user, getSyncSchema(), shouldCompactCallback: (totalSize, usedSize) { - invoked = true; - return false; - }); - - expect(() => getRealm(config), returnsNormally); - expect(invoked, isTrue); - }); - - baasTest('Configuration.flexibleSync suggests correct path', (appConfig) async { - final app = App(appConfig); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - final config = Configuration.flexibleSync(user, getSyncSchema()); - - expect(config.path, contains(user.id)); - expect(config.path, contains(appConfig.appId)); - }); - - baasTest('Configuration.flexibleSync when path is supplied, uses that', (appConfig) async { - final app = App(appConfig); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - final config = Configuration.flexibleSync(user, getSyncSchema(), path: 'my-custom-path.realm'); - - expect(config.path, 'my-custom-path.realm'); - }); - - baasTest('Configuration.flexibleSync when path is supplied, open realm', (appConfig) async { - final app = App(appConfig); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - var customPath = path.join( - platformUtil.createTempPathSync(), - 'my-custom-realm-name.realm', - ); - final config = Configuration.flexibleSync(user, getSyncSchema(), path: customPath); - expect(() => getRealm(config), returnsNormally); - }); - - baasTest('Configuration.disconnectedSync', (appConfig) async { - final app = App(appConfig); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - - final temporaryPath = await platformUtil.createTempPath(); - final realmPath = path.join(temporaryPath, 'test.realm'); - - final flexibleSyncConfig = Configuration.flexibleSync(user, getSyncSchema(), path: realmPath); - final realm = getRealm(flexibleSyncConfig); - final oid = ObjectId(); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id == $0', [oid])); - }); - realm.write(() => realm.add(Task(oid))); - realm.close(); - - final disconnectedSyncConfig = Configuration.disconnectedSync([Task.schema], path: realmPath); - final disconnectedRealm = getRealm(disconnectedSyncConfig); - expect(disconnectedRealm.find(oid), isNotNull); - }); - test('Configuration.local set too short encryption key size', () { List key = [1, 2, 3]; expect( @@ -561,18 +442,6 @@ void main() { expect(config.encryptionKey, key); }); - baasTest('FlexibleSyncConfiguration set too long encryption key size', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - - List key = List.generate(encryptionKeySize + 10, (i) => random.nextInt(256)); - expect( - () => Configuration.flexibleSync(user, getSyncSchema(), encryptionKey: key), - throws("Wrong encryption key size"), - ); - }); - test('LocalConfiguration.maxNumberOfActiveVersions - throw when exceeded', () { var config = Configuration.local([Dog.schema, Person.schema], maxNumberOfActiveVersions: 1); @@ -587,28 +456,6 @@ void main() { expect(() => realm.write(() {}), throws("Number of active versions (2) in the Realm exceeded the limit of 1")); }); - baasTest('FlexibleSyncConfiguration.maxNumberOfActiveVersions - throw when exceeded', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - - final config = Configuration.flexibleSync(user, getSyncSchema(), maxNumberOfActiveVersions: 1); - final realm = await getRealmAsync(config); // First writing to the Realm when opening - realm.subscriptions.update((mutableSubscriptions) => mutableSubscriptions.add(realm.all())); - expect(() => realm.write(() {}), throws("in the Realm exceeded the limit of 1")); - }); - - baasTest('DisconnectedSyncConfiguration.maxNumberOfActiveVersions - throw when exceeded', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final config = Configuration.flexibleSync(user, getSyncSchema()); - - final disconnectedConfig = Configuration.disconnectedSync([Task.schema], path: config.path, maxNumberOfActiveVersions: 1); - final realm = getRealm(disconnectedConfig); // First writing to the Realm when opening - expect(() => realm.write(() {}), throws("in the Realm exceeded the limit of 1")); - }); - test('LocalConfiguration.maxNumberOfActiveVersions - freeze to exceed the version and then throw', () { var config = Configuration.local([Dog.schema, Person.schema], maxNumberOfActiveVersions: 2); diff --git a/packages/realm_dart/test/credentials_test.dart b/packages/realm_dart/test/credentials_test.dart deleted file mode 100644 index b93508d67..000000000 --- a/packages/realm_dart/test/credentials_test.dart +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'package:test/test.dart' hide test, throws; -import 'package:realm_dart/realm.dart'; -import 'test.dart'; - -void main() { - const String strongPassword = "SWV23R#@T#VFQDV"; - - setupTests(); - - test('Credentials anonymous', () { - final credentials = Credentials.anonymous(); - expect(credentials.provider, AuthProviderType.anonymous); - }); - - baasTest('Anonymous - new user', (configuration) async { - final app = App(configuration); - final user1 = await app.logIn(Credentials.anonymous()); - final user2 = await app.logIn(Credentials.anonymous()); - final user3 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - - expect(user1, user2); - expect(user1, isNot(user3)); - expect(user1.identities.length, 1); - expect(user1.identities.first.provider, AuthProviderType.anonymous); - expect(user3.identities.length, 1); - expect(user3.identities.first.provider, AuthProviderType.anonymous); - }); - - test('Credentials email/password', () { - final credentials = Credentials.emailPassword("test@email.com", "000000"); - expect(credentials.provider, AuthProviderType.emailPassword); - }); - - baasTest('Email/Password - register user confirmation throws', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - await expectLater(() { - // For confirmationType = 'runConfirmationFunction' as it is by default - // only usernames that contain 'realm_tests_do_autoverify' are confirmed. - return authProvider.registerUser(username, strongPassword); - }, throws("failed to confirm user")); - }); - - baasTest('Email/Password - register user', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = getAutoverifiedEmail(); - await authProvider.registerUser(username, strongPassword); - final user = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - expect(user, isNotNull); - }); - - baasTest('Email/Password - register user auto confirm', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - // For application with name 'autoConfirm' and with confirmationType = 'auto' - // all the usernames are automatically confirmed. - - await authProvider.registerUser(username, strongPassword); - final user = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - expect(user, isNotNull); - }, appName: AppName.autoConfirm); - - baasTest('Email/Password - register user twice throws', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - await authProvider.registerUser(username, strongPassword); - await expectLater(() => authProvider.registerUser(username, strongPassword), throws("name already in use")); - }, appName: AppName.autoConfirm); - - baasTest('Email/Password - register user with weak/empty password throws', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - await expectLater(() => authProvider.registerUser(username, "pwd"), throws("password must be between 6 and 128 characters")); - await expectLater(() => authProvider.registerUser(username, ""), throws("password must be between 6 and 128 characters")); - }); - - baasTest('Email/Password - register user with empty email throws', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await expectLater(() => authProvider.registerUser("", "password"), throws("email invalid")); - }); - - baasTest('Email/Password - confirm user token expired', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await expectLater( - () => authProvider.confirmUser( - "0e6340a446e68fe02a1af1b53c34d5f630b601ebf807d73d10a7fed5c2e996d87d04a683030377ac6058824d8555b24c1417de79019b40f1299aada7ef37fddc", - "6268f7dd73fafea76b730fc9"), - throws("userpass token is expired or invalid")); - }, appName: AppName.emailConfirm); - - baasTest('Email/Password - confirm user token invalid', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await expectLater(() => authProvider.confirmUser("abc", "123"), throws("invalid token data")); - }, appName: AppName.emailConfirm); - - baasTest('Email/Password - retry custom confirmation function', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = "realm_tests_pending_confirm_${generateRandomEmail()}"; - await authProvider.registerUser(username, strongPassword); - - await authProvider.retryCustomConfirmationFunction(username); - - final user = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - expect(user, isNotNull); - }); - - baasTest('Email/Password - retry custom confirmation after user is confirmed', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = getAutoverifiedEmail(); - // Custom confirmation function confirms automatically username with 'realm_tests_do_autoverify'. - await authProvider.registerUser(username, strongPassword); - - await expectLater(() => authProvider.retryCustomConfirmationFunction(username), throws("already confirmed")); - }); - - baasTest('Email/Password - retry custom confirmation for not registered user', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - await expectLater(() => authProvider.retryCustomConfirmationFunction(username), throws("user not found")); - }); - - baasTest('Email/Password - reset password of non-existent user throws', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String username = generateRandomEmail(); - await expectLater(() => authProvider.resetPassword(username), throws("user not found")); - }, appName: AppName.emailConfirm); - - baasTest('Email/Password - call reset password function and login with the new password', (configuration) async { - final app = App(configuration); - String username = generateRandomEmail(); - const String newPassword = "!@#!DQXQWD!223eda"; - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.registerUser(username, strongPassword); - await authProvider.callResetPasswordFunction(username, newPassword, functionArgs: ['success']); - await app.logIn(Credentials.emailPassword(username, newPassword)); - await expectLater( - app.logIn(Credentials.emailPassword(username, strongPassword)), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), - ); - }, appName: AppName.autoConfirm); - - baasTest('Email/Password - call reset password function with no additional arguments', (configuration) async { - final app = App(configuration); - String username = generateRandomEmail(); - const String newPassword = "!@#!DQXQWD!223eda"; - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.registerUser(username, strongPassword); - await expectLater( - // Calling this function with no additional arguments fails for the test - // because of the specific implementation of resetFunc in the cloud. - // resetFunc returns status 'fail' in case no other status is passed. - authProvider.callResetPasswordFunction(username, newPassword), - throwsA(isA() - .having((e) => e.message, 'message', contains('failed to reset password for user "$username"')) - .having((e) => e.statusCode, 'statusCode', 400) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), - ); - }, appName: AppName.autoConfirm); - - /// JWT Payload data - /// { - /// "sub": "62f394e9bcb9fee0c9aecb76", //User.identities.id: If it is a new id the user is created, if it is an existing id the user and profile are updated. - /// "name": { - /// "firstName": "John", - /// "lastName": "Doe" - /// }, - /// "email": "JWT_privatekey_validated_user@realm.io", - /// "gender": "male", - /// "birthDay": "1999-10-11", - /// "minAge": "10", - /// "maxAge": "90", - /// "company": "Realm", - /// "iat": 1660145686, - /// "exp": 4813745686, //100 years after Aug 2022 - /// "aud": "mongodb.com", - /// "iss": "https://realm.io" - /// } - /// JWT with private key validation is configured in flexible app wich is used by the tests by default. - baasTest('JWT validation by specified public key - login', (configuration) async { - final app = App(configuration); - String username = "JWT_privatekey_validated_user@realm.io"; - String userId = "62f394e9bcb9fee0c9aecb76"; - var token = - "eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2MmYzOTRlOWJjYjlmZWUwYzlhZWNiNzYiLCJuYW1lIjp7ImZpcnN0TmFtZSI6IkpvaG4iLCJsYXN0TmFtZSI6IkRvZSJ9LCJlbWFpbCI6IkpXVF9wcml2YXRla2V5X3ZhbGlkYXRlZF91c2VyQHJlYWxtLmlvIiwiZ2VuZGVyIjoibWFsZSIsImJpcnRoRGF5IjoiMTk5OS0xMC0xMSIsIm1pbkFnZSI6IjEwIiwibWF4QWdlIjoiOTAiLCJjb21wYW55IjoiUmVhbG0iLCJpYXQiOjE2NjAxNDU2ODYsImV4cCI6NDgxMzc0NTY4NiwiYXVkIjoibW9uZ29kYi5jb20iLCJpc3MiOiJodHRwczovL3JlYWxtLmlvIn0.NAy60d4zpzRyJayO9qa6i7T3Yui4vrEJNK5FYhlQGAPCCKmPpBBrPZnOH2QwTsE1sW5jr9EsUPix6PLIauSY4nE-s4JrFb9Yu1QmhzYiXAzzyRK_yJOLmrOujqnWb57Z1KvZo5CsUafTgB5-mbs4t4-udIZEubEgr7sgH51rHK7F1r7EArwT3Fbx-EjPDTN1cWn4945Hku6wk0WgdXwVg6TEaNtT0RrEegw9t63sW1UvOYsgXpHfCePGH8VRX7yYYqu1xBnS1S1ZHNgGNZp3t8pu4lod6jHho0dPetAq9oMSmUP9H2uiKkwqFmWC_bVEjTxX4bGSbLGKZQRkiOn38w"; - final credentials = Credentials.jwt(token); - final user = await app.logIn(credentials); - - expect(user.state, UserState.loggedIn); - expect(user.identities[0].id, userId); - expect(user.identities[0].provider, AuthProviderType.jwt); - expect(user.profile.email, username); - expect(user.profile.name, username); - expect(user.profile.gender, "male"); - expect(user.profile.birthDay, "1999-10-11"); - expect(user.profile.minAge, "10"); - expect(user.profile.maxAge, "90"); - expect(user.profile.firstName, "John"); - expect(user.profile.lastName, "Doe"); - expect(user.profile["company"], "Realm"); - }); - - /// JWT Payload data - /// { - /// "sub": "62f3840b4ac43f38a50b9e2b", //User.identities.id of the existing user realm-test@realm.io - /// "name": { - /// "firstName": "John", - /// "lastName": "Doe" - /// }, - /// "email": "realm_tests_do_autoverify_jwt_user@realm.io", - /// "gender": "male", - /// "birthDay": "1999-10-11", - /// "minAge": "10", - /// "maxAge": "90", - /// "company": "Realm", - /// "iat": 1660145055, - /// "exp": 4813745055, //100 years after Aug 2022 - /// "aud": "mongodb.com", - /// "iss": "https://realm.io" - /// } - baasTest('JWT - login with existing user and edit profile', (configuration) async { - final app = App(configuration); - const username = "realm_tests_do_autoverify_jwt_user@realm.io"; - final authProvider = EmailPasswordAuthProvider(app); - // Always register jwt_user@#r@D@realm.io as a new user. - try { - await authProvider.registerUser(username, strongPassword); - } on AppException catch (e) { - { - if (e.message.contains("name already in use")) { - // If the user exists, delete it and register a new one with the same name and empty profile - final user1 = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - await app.deleteUser(user1); - await authProvider.registerUser(username, strongPassword); - } - } - } - final user = await loginWithRetry(app, Credentials.emailPassword(username, strongPassword)); - UserIdentity emailIdentity = user.identities.singleWhere((identity) => identity.provider == AuthProviderType.emailPassword); - expect(emailIdentity.provider, isNotNull); - var userId = emailIdentity.id; - - expect(user.state, UserState.loggedIn); - expect(user.identities.first.provider, AuthProviderType.emailPassword); - expect(user.profile.email, username); - expect(user.profile.name, isNull); - expect(user.profile.gender, isNull); - expect(user.profile.birthDay, isNull); - expect(user.profile.minAge, isNull); - expect(user.profile.maxAge, isNull); - expect(user.profile.firstName, isNull); - expect(user.profile.lastName, isNull); - expect(user.profile["company"], isNull); - - var token = - "eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2MmYzODQwYjRhYzQzZjM4YTUwYjllMmIiLCJuYW1lIjp7ImZpcnN0TmFtZSI6IkpvaG4iLCJsYXN0TmFtZSI6IkRvZSJ9LCJlbWFpbCI6InJlYWxtX3Rlc3RzX2RvX2F1dG92ZXJpZnlfand0X3VzZXJAcmVhbG0uaW8iLCJnZW5kZXIiOiJtYWxlIiwiYmlydGhEYXkiOiIxOTk5LTEwLTExIiwibWluQWdlIjoiMTAiLCJtYXhBZ2UiOiI5MCIsImNvbXBhbnkiOiJSZWFsbSIsImlhdCI6MTY4MDI4MDg3NSwiZXhwIjo0ODMzODgwODc1LCJhdWQiOiJtb25nb2RiLmNvbSIsImlzcyI6Imh0dHBzOi8vcmVhbG0uaW8ifQ.Wc-jGXtVqLSCmRP644Uocm1B2nE4DQtRMhDeIyZWa1NNGZrI62o6g8MguUePTqCw0Qc4fn7gdE98JAHrblT2ZtdHnnNjaUQ8p1EikkKzS6h_GgWjUv4hIAEHtwAPbxVJGXQcwBCoDtBknLMxn9pErjI9xJyqM9B7T7RAELQDH4vNlEUN1KrZQATU5PQGPqjWVxWqt3T3WaNlvyHC2L4pfddhwocEu0ALHux2CZy4ixnUJ3CYqh3Lka5saxWa1djhcy4Uku4fsA948sduwQF1UdI4mjQN0gwNIODQVb9HjaSSZh3nuUCDocB2VokmBczT1WGgVRAVbDlmyGKf6BvRjg"; - await user.linkCredentials(Credentials.jwt(token)); - - UserIdentity jwtIdentity = user.identities.singleWhere((identity) => identity.provider == AuthProviderType.jwt); - expect(jwtIdentity.provider, isNotNull); - var jwtUserId = jwtIdentity.id; - - var jwtUser = await loginWithRetry(app, Credentials.jwt(token)); - - expect(jwtUser.state, UserState.loggedIn); - expect(jwtUser.identities.singleWhere((identity) => identity.provider == AuthProviderType.jwt).id, jwtUserId); - expect(jwtUser.identities.singleWhere((identity) => identity.provider == AuthProviderType.emailPassword).id, userId); - expect(jwtUser.profile.email, username); - expect(jwtUser.profile.name, username); - expect(jwtUser.profile.gender, "male"); - expect(jwtUser.profile.birthDay, "1999-10-11"); - expect(jwtUser.profile.minAge, "10"); - expect(jwtUser.profile.maxAge, "90"); - expect(jwtUser.profile.firstName, "John"); - expect(jwtUser.profile.lastName, "Doe"); - expect(jwtUser.profile["company"], "Realm"); - }); - - /// Token signed with private key different than the one configured in Atlas 'flexible' app JWT authentication provider - /// JWT Payload data - /// { - /// "sub": "62f396888af8720b373ff06a", - /// "email": "wong_signiture_key@realm.io", - /// "iat": 1660142215, - /// "exp": 4813742215, //100 years after Aug 2022 - /// "aud": "mongodb.com", - /// "iss": "https://realm.io" - /// } - baasTest('JWT with wrong signiture key - login fails', (configuration) async { - final app = App(configuration); - var token = - "eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYiLCJ0eXAiOiJKV1QifQ.eyJzdWIiOiI2MmYzOTY4ODhhZjg3MjBiMzczZmYwNmEiLCJlbWFpbCI6Indvbmdfc2lnbml0dXJlX2tleUByZWFsbS5pbyIsImlhdCI6MTY2MDE0MjIxNSwiZXhwIjo0ODEzNzQyMjE1LCJhdWQiOiJtb25nb2RiLmNvbSIsImlzcyI6Imh0dHBzOi8vcmVhbG0uaW8ifQ.Af--ZUCL_KC7lAhrD_d1lq91O7qVwu7GqXifwxKojkLCkbjmAER9K2Xa7BPO8xNstFeX8m9uBo4BCD5B6XmngSmyCj5OZWdiG5LTR_uhA3MnpqcV3Vu40K4Yx8XrjPuCL39xVPnEfPKLGz5TjEcMLa8xMPqo51byX0q3mR2eSS4w1A7c5TiTNuQ23_SCO8aK95SyXwuUmU4mH0iR4sHPtf64WyoAXkx8w5twXExzky1_h473CwtAERdMsBhwz1YzFKP0kxU31pg5SRciF5Ly66sK1fSPTMQPuVdS_wKvAYll8_trWnWS83M3_PWs4UxzOdjSpoK0uqhN-_IC38YOGg"; - final credentials = Credentials.jwt(token); - await expectLater( - () => app.logIn(credentials), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), - ); - }); - - baasTest('Facebook credentials - invalid or expired token', (configuration) async { - final app = App(configuration); - final accessToken = 'invalid or expired token'; - final credentials = Credentials.facebook(accessToken); - await expectLater( - app.logIn(credentials), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id='))), - ); - }); - - baasTest('Function credentials - wrong payload', (configuration) { - final payload = 'Wrong EJSON format'; - expect(() => Credentials.function(payload), throws("parse error")); - }); - - baasTest('Function credentials - login with new user', (configuration) async { - final app = App(configuration); - var userId = ObjectId().toString(); - String username = generateRandomEmail(); - final payload = '{"username":"$username","userId":"$userId"}'; - final credentials = Credentials.function(payload); - final user = await app.logIn(credentials); - expect(user.identities[0].id, userId); - expect(user.identities[0].provider, AuthProviderType.function); - }); - - baasTest('Function credentials - login with existing user', (configuration) async { - final app = App(configuration); - var userId = ObjectId().toString(); - final payload = '{"userId":"$userId"}'; - - final credentials = Credentials.function(payload); - final user = await app.logIn(credentials); - expect(user.identities[0].id, userId); - expect(user.identities[0].provider, AuthProviderType.function); - user.logOut(); - - final sameUser = await app.logIn(credentials); - expect(sameUser.id, user.id); - - expect(sameUser.identities[0].id, userId); - expect(sameUser.identities[0].provider, AuthProviderType.function); - }); - - test('Credentials providers', () { - expect(Credentials.anonymous().provider, AuthProviderType.anonymous); - expect(Credentials.anonymous(reuseCredentials: false).provider, AuthProviderType.anonymous); - expect(Credentials.apiKey("").provider, AuthProviderType.apiKey); - expect(Credentials.apple("").provider, AuthProviderType.apple); - expect(Credentials.emailPassword("", "").provider, AuthProviderType.emailPassword); - expect(Credentials.facebook("").provider, AuthProviderType.facebook); - expect(Credentials.function("{}").provider, AuthProviderType.function); - expect(Credentials.googleAuthCode("").provider, AuthProviderType.google); - expect(Credentials.googleIdToken("").provider, AuthProviderType.google); - expect(Credentials.jwt("").provider, AuthProviderType.jwt); - }); -} diff --git a/packages/realm_dart/test/dynamic_realm_test.dart b/packages/realm_dart/test/dynamic_realm_test.dart index 8d2580c5b..52c1aa068 100644 --- a/packages/realm_dart/test/dynamic_realm_test.dart +++ b/packages/realm_dart/test/dynamic_realm_test.dart @@ -1411,100 +1411,4 @@ void main() { // await sub1.cancel(); // await sub2.cancel(); }, skip: 'Requires https://github.com/realm/realm-core/issues/7426'); - - Realm openPausedSyncRealm(User user, List schemas) { - // Some tests validate that adding a property in the schema will update the Realm.schema collection - // It goes through sync, because that's the only way to add a property without triggering a migration. - // It is necessary to immediately stop the sync sessions to make sure those changes don't make it to the - // server, otherwise the schema for all tests will be adjusted, which may pollute the test run. - - final config = Configuration.flexibleSync(user, schemas); - - final realm = getRealm(config); - realm.syncSession.pause(); - - realm.subscriptions.update((mutableSubscriptions) { - for (final schema in schemas) { - mutableSubscriptions.add(realm.dynamic.all(schema.name)); - } - }); - - return realm; - } - - baasTest('Realm.schema is updated with a new property', (config) async { - final user = await getIntegrationUser(appConfig: config); - - final v1Realm = openPausedSyncRealm(user, [Task.schema]); - v1Realm.syncSession.pause(); - - final v2Realm = openPausedSyncRealm(user, [Taskv2.schema]); - - final taskId = ObjectId(); - v2Realm.write(() { - v2Realm.add(Taskv2(taskId, 'lorem ipsum')); - }); - - expect(v2Realm.schema, hasLength(1)); - assertSchemaExists(v2Realm, Taskv2.schema); - - v1Realm.refresh(); - expect(v1Realm.schema, hasLength(1)); - assertSchemaExists(v1Realm, Taskv2.schema); - - final tasks = v1Realm.all(); - expect(tasks, hasLength(1)); - expect(tasks.single.id, taskId); - expect(tasks.single.dynamic.get('description'), 'lorem ipsum'); - - assertSchemaMatches(tasks.single.objectSchema, Taskv2.schema); - }, skip: 'Requires https://github.com/realm/realm-core/issues/7426'); - - baasTest('RealmObject.schema is updated with a new property', (config) async { - final user = await getIntegrationUser(appConfig: config); - - final v1Realm = openPausedSyncRealm(user, [Task.schema]); - final task = v1Realm.write(() => v1Realm.add(Task(ObjectId()))); - assertSchemaMatches(task.objectSchema, Task.schema); - - final v2Realm = openPausedSyncRealm(user, [Taskv2.schema]); - - expect(v2Realm.schema, hasLength(1)); - assertSchemaExists(v2Realm, Taskv2.schema); - - v2Realm.write(() { - final v2Task = v2Realm.find(task.id)!; - v2Task.description = 'lorem ipsum'; - }); - - v1Realm.refresh(); - expect(v1Realm.schema, hasLength(1)); - assertSchemaExists(v1Realm, Taskv2.schema); - - assertSchemaMatches(task.objectSchema, Taskv2.schema); - expect(task.dynamic.get('description'), 'lorem ipsum'); - }, skip: 'Requires https://github.com/realm/realm-core/issues/7426'); - - baasTest('UnmanagedObject.schema is updated with a new property', (config) async { - final user = await getIntegrationUser(appConfig: config); - - final v1Realm = openPausedSyncRealm(user, [Task.schema]); - - // Update the schema - openPausedSyncRealm(user, [Taskv2.schema]); - - final task = Task(ObjectId()); - expect(() => task.dynamic.get('description'), - throwsA(isA().having((p0) => p0.message, 'message', "Property 'description' does not exist on object of type 'Task'"))); - assertSchemaMatches(task.objectSchema, Task.schema); - - v1Realm.write(() { - v1Realm.add(task); - }); - - assertSchemaMatches(task.objectSchema, Taskv2.schema); - - // Schema was updated so description shouldn't throw now - expect(task.dynamic.get('description'), ''); - }, skip: 'Requires https://github.com/realm/realm-core/issues/7426'); } diff --git a/packages/realm_dart/test/embedded_test.dart b/packages/realm_dart/test/embedded_test.dart index baf5c570f..2dc54af8b 100644 --- a/packages/realm_dart/test/embedded_test.dart +++ b/packages/realm_dart/test/embedded_test.dart @@ -1,7 +1,6 @@ // Copyright 2022 MongoDB, Inc. // SPDX-License-Identifier: Apache-2.0 - import 'package:realm_dart/realm.dart'; // This is required to be able to use the API for querying embedded objects. import 'package:realm_dart/src/realm_class.dart' show RealmInternal; @@ -29,13 +28,6 @@ void main() { expect(schema.single.baseType, ObjectType.embeddedObject); }); - baasTest('Synchronized Realm with orphan embedded schemas throws', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final config = Configuration.flexibleSync(user, getSyncSchema()); - - expect(() => getRealm(config), throws("Embedded object 'AllTypesEmbedded' is unreachable by any link path from top level objects")); - }, skip: "This test requires a new app service with missing embedded parent schema."); - test('Embedded object roundtrip', () { final realm = getLocalRealm(); @@ -372,56 +364,6 @@ void main() { expect(embedded3s.length, 0); }); - baasTest('Embedded objects synchronization', (config) async { - final realm1 = await getIntegrationRealm(appConfig: config); - - final differentiator = Uuid.v4(); - realm1.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm1.query(r'differentiator = $0', [differentiator])); - }); - - final obj1 = realm1.write(() { - return realm1.add(ObjectWithEmbedded(Uuid.v4().toString(), - differentiator: differentiator, - recursiveObject: RecursiveEmbedded1('1.1', child: RecursiveEmbedded2('2.1'), children: [RecursiveEmbedded2('2.2')]), - recursiveList: [RecursiveEmbedded1('1.2')])); - }); - - await realm1.subscriptions.waitForSynchronization(); - await realm1.syncSession.waitForUpload(); - - final realm2 = await getIntegrationRealm(appConfig: config); - realm2.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm2.query(r'differentiator = $0', [differentiator])); - }); - - await realm2.subscriptions.waitForSynchronization(); - await realm2.syncSession.waitForDownload(); - - final obj2 = realm2.all().single; - - expect(obj2.recursiveObject!.value, '1.1'); - expect(obj2.recursiveObject!.child!.value, '2.1'); - expect(obj2.recursiveObject!.children.length, 1); - expect(obj2.recursiveObject!.children[0].value, '2.2'); - expect(obj2.recursiveList.length, 1); - expect(obj2.recursiveList[0].value, '1.2'); - expect(obj2.recursiveList[0].child, isNull); - expect(obj2.recursiveList[0].children, isEmpty); - - realm2.write(() { - obj2.recursiveObject = null; - }); - - await realm2.syncSession.waitForUpload(); - await realm1.syncSession.waitForDownload(); - - expect(obj1.recursiveObject, isNull); - - expect(realm1.allEmbedded().length, 1); - expect(realm1.allEmbedded().length, 0); - }); - for (final isDynamic in [true, false]) { Realm getDynamicRealm(Realm original) { if (isDynamic) { diff --git a/packages/realm_dart/test/manual_test.dart b/packages/realm_dart/test/manual_test.dart deleted file mode 100644 index d4eec1f06..000000000 --- a/packages/realm_dart/test/manual_test.dart +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -@TestOn('browser') // This file only contain manual tests - -import 'package:test/test.dart' hide test, throws; -import 'package:realm_dart/realm.dart'; -import 'test.dart'; - -void main() { - const String strongPassword = "SWV23R#@T#VFQDV"; - - setupTests(); - - // The tests in this group are for manual testing, since they require interaction with mail box. - group('Manual tests', () { - // Please enter a valid data in the variables under comments. - // Run test 1, then copy token and tokenId from mail box. - // Set the variables with token details and then run test 2. - // Go to the application and check whether the new registered user is confirmed. - // Make sure the email haven't been already registered in application. - group("Manual test: Email/Password - confirm user", () { - // Enter a valid email that is not registered - const String validUsername = "valid_email@mail.com"; - - baasTest('Manual test 1. Register a valid user for email confirmation', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.registerUser(validUsername, strongPassword); - }, appName: AppName.emailConfirm, skip: "It is a manual test"); - - baasTest('Manual test 2. Take the recieved token from the email and confirm the user', (configuration) async { - // Enter valid token and tokenId from the received email - String token = "3a8bdfa28e147f38e531cf5aca93d452a11efc4fc9a81f00219b0cb29cfb93858f6b174123659a6ef47b58a2b80eac3b406d7803605c17ef44401ec6cf2c8fa6"; - String tokenId = "626934dcb4e7e5a0e2f1d85e"; - - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.confirmUser(token, tokenId); - final user = await loginWithRetry(app, Credentials.emailPassword(validUsername, strongPassword)); - expect(user, isNotNull); - }, appName: AppName.emailConfirm, skip: "Run this test manually after test 1 and after setting token and tokenId"); - }); - - // The tests in this group are for manual testing, since they require interaction with mail box. - // Please enter a valid data in the variables under comments. - // Run test 1, then make sure you have received two emails. - // Copy token and tokenId from the second email. - // Set the variables with token details and then run test 2. - // Go to the application and check whether the new registered user is confirmed. - // Make sure the email haven't been already registered in application. - group("Manual test: Email/Password - resend confirm", () { - // Enter a valid email that is not registered - const String validUsername = "valid_email@mail.com"; - baasTest('Manual test 1. Register a valid user and resend email confirmation', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.registerUser(validUsername, strongPassword); - await authProvider.resendUserConfirmation(validUsername); - }, appName: AppName.emailConfirm, skip: "It is a manual test"); - - baasTest('Manual test 2. Take recieved token from any of both emails and confirm the user', (configuration) async { - // Make sure you have recieved two emails. - // Enter valid token and tokenId from the second received email - String token = "3eb9e380e925075af761fbf36273ad32c5ad898e7cd5fc2e7cf5d0296c5850222ecb55d5d39601f95fc81a67f4b4ca1f7386bc6fef62a0b27498c3157332e155"; - String tokenId = "626b1977dbc08e4014bad1ec"; - - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.confirmUser(token, tokenId); - final user = await loginWithRetry(app, Credentials.emailPassword(validUsername, strongPassword)); - expect(user, isNotNull); - }, appName: AppName.emailConfirm, skip: "Run this test manually after test 1 and after setting token and tokenId"); - }); - - // The tests in this group are for manual testing, since they require interaction with mail box. - // Please enter a valid data in the variables under comments. - // The email should be a valid and existing one in order you to be able to receive automatic emails. - // Run first two steps (test 1 and test 2) to create and confirm the user. - // Before running test 2 set the variables with token details received as link query parameters in the confirmation email. - // Then run test 3, then make sure you have received an email with link for reset password. - // Copy token and tokenId from the email link query parameters. - // Set the variables with token details and then run test 4. - // Test 4 will set the password and will login the user with the new password. - group("Manual test: Email/Password - reset password", () { - // Enter a valid email that is not registered - const String validUsername = "valid_email@realm.io"; - - baasTest('Manual test 1 (resetPassword). Register a valid user', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.registerUser(validUsername, strongPassword); - }, appName: AppName.emailConfirm, skip: "It is a manual test"); - - baasTest('Manual test 2 (resetPassword). Take recieved token from the received email and confirm the user', (configuration) async { - // Enter valid token and tokenId from the received email - String token = "3e23e2e689fe1fdbbb51d3c090a216a4195a4f0a004a578787618d9dd39c791f4169511ee3820e4b6fa2bfdc14430f1e58356223d78e3bed3c86042c3a91a4db"; - String tokenId = "6278cecd9106aa5b645999ba"; - - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.confirmUser(token, tokenId); - final user = await loginWithRetry(app, Credentials.emailPassword(validUsername, strongPassword)); - expect(user, isNotNull); - }, appName: AppName.emailConfirm, skip: "It is a manual test"); - - baasTest('Manual test 3 (resetPassword). Reset user password email', (configuration) async { - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - await authProvider.resetPassword(validUsername); - }, appName: AppName.emailConfirm, skip: "It is a manual test"); - - baasTest('Manual test 4 (resetPassword). Take recieved token from the email and complete resetting new password', (configuration) async { - // Make sure you have recieved an emails with hyperlink ResetPassword. - // Find the token and tokenId in the query parameters of the link received in the email and enter them in the following variables. - String token = "fb485146b15497209a9d1b67128ae29199cdff2c26f389e0ee5d52ae6bc4228e5738b29256eade976e24767804bfb4dc68198075e3a461cd4f73864901fb09be"; - String tokenId = "6272619334f5b3a770a7dc2c"; - - final app = App(configuration); - final authProvider = EmailPasswordAuthProvider(app); - String newPassword = "RWE@#EDE"; - await authProvider.completeResetPassword(newPassword, token, tokenId); - final user = await app.logIn(Credentials.emailPassword(validUsername, strongPassword)); - expect(user, isNotNull); - }, appName: AppName.emailConfirm, skip: "Run this test manually after test 1 and after setting token and tokenId"); - }); - - ///See test/README.md section 'Manually configure Facebook, Google and Apple authentication providers'" - baasTest('Facebook credentials - login', (configuration) async { - final app = App(configuration); - final accessToken = - 'EAARZCEokqpOMBAKoIHgaG6bqY6LLseGHcQjYdoPhv9FdB89mkVZBWQFOmZCuVeuRfIa5cMtQANLpZBUQI0n4qb4TZCZCAI3vXZC9Oud2qRiieQDtXqE4abZBQJorcBMzECVfsDlus7hk63zW3XzuFCZAxF4BCdRZBHXlGXIzaHhFHhY72aU1apX0tC'; - final credentials = Credentials.facebook(accessToken); - final user = await app.logIn(credentials); - expect(user.state, UserState.loggedIn); - expect(user.identities[0].provider, AuthProviderType.facebook); - expect(user.profile.name, "Open Graph Test User"); - }, skip: "Manual test"); - }, skip: "Manual tests"); -} diff --git a/packages/realm_dart/test/realm_test.dart b/packages/realm_dart/test/realm_test.dart index af1becc95..9c0fb4453 100644 --- a/packages/realm_dart/test/realm_test.dart +++ b/packages/realm_dart/test/realm_test.dart @@ -7,8 +7,6 @@ import 'dart:isolate'; import 'package:path/path.dart' as p; import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/configuration.dart'; -import 'package:realm_dart/src/handles/realm_core.dart'; import 'package:timezone/data/latest.dart' as tz; import 'package:timezone/timezone.dart' as tz; @@ -981,21 +979,6 @@ void main() { openEncryptedRealm(generateEncryptionKey(), generateEncryptionKey(), afterEncrypt: (realm) => realm.close()); }); - baasTest('Realm - open synced encrypted realm with encryption key', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - List key = List.generate(encryptionKeySize, (i) => random.nextInt(256)); - final configuration = Configuration.flexibleSync(user, getSyncSchema(), encryptionKey: key); - - final realm = getRealm(configuration); - expect(realm.isClosed, false); - expect( - () => getRealm(Configuration.flexibleSync(user, getSyncSchema())), - throws("already opened with a different encryption key"), - ); - }); - test('Realm.beginWriteAsync starts write transaction', () async { final realm = getRealm(Configuration.local([Person.schema])); final transaction = await realm.beginWriteAsync(); @@ -1228,16 +1211,6 @@ void main() { expect(realm.isInTransaction, true); }); - baasTest('Realm.open (flexibleSync)', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final realm = await getRealmAsync(configuration); - expect(realm.isClosed, false); - }); - test('Realm.open (local)', () async { final configuration = Configuration.local([Car.schema]); final realm = await getRealmAsync(configuration); @@ -1251,159 +1224,6 @@ void main() { await expectLater(getRealmAsync(configuration, cancellationToken: cancellationToken), throwsA(isA())); }); - baasTest('Realm.open (flexibleSync) - cancel before open', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final cancellationToken = CancellationToken(); - cancellationToken.cancel(); - await expectLater(getRealmAsync(configuration, cancellationToken: cancellationToken), throwsA(isA())); - }); - - baasTest('Realm.open (flexibleSync) - cancel right after open', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final cancellationToken = CancellationToken(); - final isRealmCancelled = getRealmAsync(configuration, cancellationToken: cancellationToken).isCancelled(); - cancellationToken.cancel(); - expect(await isRealmCancelled, isTrue); - }); - - baasTest('Realm.open (flexibleSync) - open twice the same realm with the same CancelationToken cancels all', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final cancellationToken = CancellationToken(); - - Future.delayed(const Duration(milliseconds: 10), () => cancellationToken.cancel()); - final isRealm1Cancelled = getRealmAsync(configuration, cancellationToken: cancellationToken).isCancelled(); - final isRealm2Cancelled = getRealmAsync(configuration, cancellationToken: cancellationToken).isCancelled(); - expect(await isRealm1Cancelled, isTrue); - expect(await isRealm2Cancelled, isTrue); - }); - - baasTest('Realm.open (flexibleSync) - open the same realm twice and only cancel the first call', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final cancellationToken1 = CancellationToken(); - final isRealm1Cancelled = getRealmAsync(configuration, cancellationToken: cancellationToken1).isCancelled(); - - final cancellationToken2 = CancellationToken(); - final isRealm2Cancelled = getRealmAsync(configuration, cancellationToken: cancellationToken2).isCancelled(); - cancellationToken1.cancel(); - expect(await isRealm1Cancelled, isTrue); - expect(await isRealm2Cancelled, isFalse); - }); - - baasTest('Realm.open (flexibleSync) - open two different Realms for two different users and cancel only the second call', (appConfiguration) async { - final app = App(appConfiguration); - - final user1 = await app.logIn(Credentials.anonymous()); - final configuration1 = Configuration.flexibleSync(user1, getSyncSchema()); - final cancellationToken1 = CancellationToken(); - final isRealm1Cancelled = getRealmAsync(configuration1, cancellationToken: cancellationToken1).isCancelled(); - - final user2 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final configuration2 = Configuration.flexibleSync(user2, getSyncSchema()); - final cancellationToken2 = CancellationToken(); - final isRealm2Cancelled = getRealmAsync(configuration2, cancellationToken: cancellationToken2).isCancelled(); - - cancellationToken2.cancel(); - expect(await isRealm2Cancelled, isTrue); - expect(await isRealm1Cancelled, isFalse); - }); - - baasTest('Realm.open (flexibleSync) - cancel after realm is returned is no-op', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - final cancellationToken = CancellationToken(); - final realm = await getRealmAsync(configuration, cancellationToken: cancellationToken); - - expect(realm, isNotNull); - expect(realm.isClosed, false); - - cancellationToken.cancel(); - expect(realm.isClosed, false); - }); - - baasTest('Realm.open (flexibleSync) - listen for download progress on an empty realm', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, getSyncSchema()); - - double progressEstimate = -1; - bool progressReported = false; - var syncedRealm = await getRealmAsync(configuration, onProgressCallback: (syncProgress) { - progressEstimate = syncProgress.progressEstimate; - progressReported = true; - }); - - await Future.delayed(Duration(milliseconds: 500)); - - expect(syncedRealm.isClosed, false); - - // For FLX realms with no subscriptions, the server won't report any progress before it resolves the - // Realm.open future. - expect(progressEstimate, -1); - expect(progressReported, false); - }); - - baasTest('Realm.open (flexibleSync) - download a populated realm', (appConfiguration) async { - final app = App(appConfiguration); - final queryDifferentiator = generateRandomString(10); - const itemsCount = 200; - final config = await _subscribeForAtlasAddedData(app, queryDifferentiator: queryDifferentiator, itemsCount: itemsCount); - var syncedRealm = await getRealmAsync(config); - expect(syncedRealm.isClosed, false); - final data = syncedRealm.query(r'name BEGINSWITH $0', [queryDifferentiator]); - expect(data.length, itemsCount); - }); - - baasTest('Realm.open (flexibleSync) - listen for download progress of a populated realm', (appConfiguration) async { - final app = App(appConfiguration); - final config = await _subscribeForAtlasAddedData(app); - - int printCount = 0; - double progressEstimate = 0; - - final syncedRealm = await getRealmAsync(config, onProgressCallback: (syncProgress) { - printCount++; - progressEstimate = syncProgress.progressEstimate; - }); - - expect(syncedRealm.isClosed, false); - expect(printCount, isNot(0)); - expect(progressEstimate, 1.0); - }); - - baasTest('Realm.open (flexibleSync) - listen and cancel download progress of a populated realm', (appConfiguration) async { - final app = App(appConfiguration); - final config = await _subscribeForAtlasAddedData(app); - - final cancellationToken = CancellationToken(); - bool progressReturned = false; - final realmIsCancelled = getRealmAsync(config, cancellationToken: cancellationToken, onProgressCallback: (syncProgress) { - progressReturned = true; - }).isCancelled(); - cancellationToken.cancel(); - expect(await realmIsCancelled, isTrue); - expect(progressReturned, isFalse); - }); - void addDataForCompact(Realm realm, String compactTest) { realm.write(() { for (var i = 0; i < 2500; i++) { @@ -1424,20 +1244,8 @@ void main() { var realm = getRealm(config); final compactTest = generateRandomString(10); - if (config is FlexibleSyncConfiguration) { - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query("name CONTAINS '$compactTest'")); - }); - await realm.subscriptions.waitForSynchronization(); - } - addDataForCompact(realm, compactTest); - if (config is FlexibleSyncConfiguration) { - await realm.syncSession.waitForDownload(); - await realm.syncSession.waitForUpload(); - } - final beforeSize = platformUtil.sizeOnStorage(config); realm.close(); @@ -1519,46 +1327,6 @@ void main() { expect(() => getRealm(config), returnsNormally); }); - baasTest('Realm - disconnected sync realm can be compacted', (appConfiguration) async { - final config = Configuration.disconnectedSync([Product.schema], path: generateRandomRealmPath()); - - final beforeCompactSize = await createRealmForCompact(config); - - final compacted = Realm.compact(config); - - validateCompact(compacted, config, beforeCompactSize); - - // test the realm can be opened. - expect(() => getRealm(config), returnsNormally); - }); - - baasTest('Realm - synced realm can be compacted', (appConfiguration) async { - final user = await getIntegrationUser(appConfig: appConfiguration); - final config = Configuration.flexibleSync(user, getSyncSchema(), path: generateRandomRealmPath()); - final beforeCompactSize = await createRealmForCompact(config); - - final compacted = await runWithRetries(() => Realm.compact(config)); - validateCompact(compacted, config, beforeCompactSize); - - // test the realm can be opened. - expect(() => getRealm(config), returnsNormally); - }); - - baasTest('Realm - synced encrypted realm can be compacted', (appConfiguration) async { - final app = App(appConfiguration); - final credentials = Credentials.anonymous(reuseCredentials: false); - var user = await app.logIn(credentials); - List key = List.generate(encryptionKeySize, (i) => random.nextInt(256)); - final config = Configuration.flexibleSync(user, getSyncSchema(), encryptionKey: key, path: generateRandomRealmPath()); - final beforeCompactSize = await createRealmForCompact(config); - - final compacted = await runWithRetries(() => Realm.compact(config)); - validateCompact(compacted, config, beforeCompactSize); - - // test the realm can be opened. - expect(() => getRealm(config), returnsNormally); - }); - test('Realm writeCopy local to existing file', () { final config = Configuration.local([Car.schema]); final realm = getRealm(config); @@ -1576,18 +1344,6 @@ void main() { Platform.isWindows ? "The system cannot find the path specified." : "Failed to open file at path '$path': parent directory does not exist")); }); - baasTest('Realm writeCopy Local->Sync is not supported', (appConfiguration) async { - final originalConfig = Configuration.local([Product.schema]); - final originalRealm = getRealm(originalConfig); - - final app = App(appConfiguration); - final credentials = Credentials.anonymous(reuseCredentials: false); - var user = await app.logIn(credentials); - final configCopy = Configuration.flexibleSync(user, getSyncSchema()); - expect(() => originalRealm.writeCopy(configCopy), - throws("Realm cannot be converted to a flexible sync realm unless flexible sync is already enabled")); - }); - test('Realm writeCopy Local->Local inside a write block is not allowed.', () { final originalConfig = Configuration.local([Car.schema]); final originalRealm = getRealm(originalConfig); @@ -1689,82 +1445,6 @@ void main() { } } - // writeCopy Sync to Sync realm - for (List? sourceEncryptedKey in [null, generateEncryptionKey()]) { - for (List? destinationEncryptedKey in [sourceEncryptedKey, generateEncryptionKey()]) { - final sourceEncryptedState = '${sourceEncryptedKey != null ? "encrypted " : ""}Sync'; - final destinationEncryptedState = - 'to ${destinationEncryptedKey != null ? "encrypted with ${sourceEncryptedKey != null && sourceEncryptedKey == destinationEncryptedKey ? "the same" : "different"} key " : ""}Sync'; - final testDescription = '$sourceEncryptedState $destinationEncryptedState'; - baasTest('Realm writeCopy Sync->Sync - $testDescription can be opened and synced', (appConfiguration) async { - final app = App(appConfiguration); - var user1 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final originalConfig = Configuration.flexibleSync(user1, getSyncSchema(), encryptionKey: sourceEncryptedKey); - final originalRealm = getRealm(originalConfig); - var itemsCount = 2; - final productNamePrefix = generateRandomString(10); - await _addDataToAtlas(originalRealm, productNamePrefix, itemsCount: itemsCount); - - var user2 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final configCopy = Configuration.flexibleSync(user2, getSyncSchema(), encryptionKey: destinationEncryptedKey); - originalRealm.writeCopy(configCopy); - originalRealm.close(); - - expect(Realm.existsSync(configCopy.path), isTrue); - // Check data in copied realm before synchronization - final disconnectedConfig = Configuration.disconnectedSync([Product.schema], path: configCopy.path, encryptionKey: destinationEncryptedKey); - final disconnectedCopiedRealm = getRealm(disconnectedConfig); - expect(disconnectedCopiedRealm.all().length, itemsCount); - disconnectedCopiedRealm.close(); - - // Sync copied realm to the server - final copiedRealm = getRealm(configCopy); - await _addSubscriptions(copiedRealm, productNamePrefix); - await copiedRealm.syncSession.waitForUpload(); - await copiedRealm.syncSession.waitForDownload(); - expect(copiedRealm.all().length, itemsCount); - copiedRealm.close(); - - // Create another user's realm and download the data - var anotherUser = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final anotherUserRealm = getRealm(Configuration.flexibleSync(anotherUser, getSyncSchema())); - await _addSubscriptions(anotherUserRealm, productNamePrefix); - await anotherUserRealm.syncSession.waitForUpload(); - await anotherUserRealm.syncSession.waitForDownload(); - expect(anotherUserRealm.all().length, itemsCount); - anotherUserRealm.close(); - }); - } - } - - // writeCopy Sync to Local realm - for (List? sourceEncryptedKey in [null, generateEncryptionKey()]) { - for (List? destinationEncryptedKey in [sourceEncryptedKey, generateEncryptionKey()]) { - final sourceEncryptedState = '${sourceEncryptedKey != null ? "encrypted " : ""}Sync'; - final destinationEncryptedState = - 'to ${destinationEncryptedKey != null ? "encrypted with ${sourceEncryptedKey != null && sourceEncryptedKey == destinationEncryptedKey ? "the same" : "different"} key " : ""}Local'; - final testDescription = '$sourceEncryptedState $destinationEncryptedState'; - baasTest('Realm writeCopy Sync->Local - $testDescription can be opened and synced', (appConfiguration) async { - final app = App(appConfiguration); - var user = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final originalConfig = Configuration.flexibleSync(user, getSyncSchema(), encryptionKey: sourceEncryptedKey); - final originalRealm = getRealm(originalConfig); - var itemsCount = 2; - final productNamePrefix = generateRandomString(10); - await _addDataToAtlas(originalRealm, productNamePrefix, itemsCount: itemsCount); - - final pathCopy = originalConfig.path.replaceFirst(p.basenameWithoutExtension(originalConfig.path), generateRandomString(10)); - final configCopy = Configuration.local([Product.schema], path: pathCopy, encryptionKey: destinationEncryptedKey); - originalRealm.writeCopy(configCopy); - originalRealm.close(); - - expect(Realm.existsSync(pathCopy), isTrue); - final copiedRealm = getRealm(configCopy); - expect(copiedRealm.all().length, itemsCount); - copiedRealm.close(); - }); - } - } test('Realm.refresh no changes', () async { final realm = getRealm(Configuration.local([Person.schema])); final result = realm.refresh(); @@ -1853,18 +1533,6 @@ void main() { receivePort.close(); }); - test('Device info', () { - late Matcher matcher; - if (Platform.isAndroid || Platform.isIOS) { - matcher = isNotEmpty; - } else { - matcher = isEmpty; - } - - expect(realmCore.getDeviceName(), matcher); - expect(realmCore.getDeviceVersion(), matcher); - }); - test('Realm path with unicode symbols', () { final config = Configuration.local([Car.schema], path: generateRandomRealmPath(useUnicodeCharacters: true)); var realm = getRealm(config); @@ -1881,19 +1549,6 @@ void main() { expect(query[0].name, productName); }); - baasTest('Realm synced add/query/sync data with unicode symbols', (appConfiguration) async { - final app = App(appConfiguration); - final productName = generateRandomUnicodeString(); - final user = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final config = Configuration.flexibleSync(user, getSyncSchema()); - final realm = getRealm(config); - await _addSubscriptions(realm, productName); - realm.write(() => realm.add(Product(ObjectId(), productName))); - final query = realm.query(r'name == $0', [productName]); - expect(query.length, 1); - expect(query[0].name, productName); - }); - test('Realm case-insensitive query', () { final productName = generateRandomString(10).toUpperCase(); final config = Configuration.local([Product.schema]); @@ -1904,74 +1559,10 @@ void main() { expect(query[0].name, productName); }); - baasTest('Synchronized Realm can be opened on multiple isolates', (appConfiguration) async { - clearCachedApps(); - - final app = App(appConfiguration); - final user = await getAnonymousUser(app); - final config = Configuration.flexibleSync(user, getSyncSchema()); - final realm = getRealm(config); - - final receivePort = ReceivePort(); - - final subscriptionId = ObjectId(); - - await Isolate.spawn((List args) async { - Realm? bgRealm; - - final sendPort = args[0] as SendPort; - try { - final appId = args[1] as String; - final baseUrl = args[2] as Uri; - final userId = args[3] as String; - final realmPath = args[4] as String; - final subscriptionId = args[5] as ObjectId; - final bgApp = App.getById(appId, baseUrl: baseUrl)!; - if (bgApp.id != appId) throw 'Expected App.id ${bgApp.id} == $appId'; - if (bgApp.currentUser?.id != userId) throw 'Expected User.id ${bgApp.currentUser?.id} == $userId'; - if (bgApp.users.length != 1) throw 'Expected users.length == 1'; - - final bgUser = bgApp.users.singleWhere((element) => element.id == userId); - final bgConfig = Configuration.flexibleSync(bgUser, getSyncSchema(), path: realmPath); - bgRealm = Realm(bgConfig); - await bgRealm.query('id == \$0', [subscriptionId]).subscribe(); - - bgRealm.write(() { - bgRealm!.add(Product(subscriptionId, 'abc')); - }); - - Isolate.exit(sendPort, null); - } catch (e) { - Isolate.exit(sendPort, e); - } finally { - bgRealm?.close(); - } - }, [receivePort.sendPort, app.id, appConfiguration.baseUrl, user.id, realm.config.path, subscriptionId]); - - final exitInfo = await receivePort.first; - expect(exitInfo, null); - - realm.refresh(); - - final product = realm.all().single; - expect(product.id, subscriptionId); - expect(product.name, 'abc'); - }); - test('Local realm can be opened with orphaned embedded objects', () { final config = Configuration.local([Car.schema, AllTypesEmbedded.schema], path: generateRandomRealmPath()); expect(() => getRealm(config), returnsNormally); }); - - baasTest('Sync realm with orphaned embedded objects, throws', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - final config = Configuration.flexibleSync(user, [Task.schema, AllTypesEmbedded.schema])..sessionStopPolicy = SessionStopPolicy.immediately; - - expect( - () => getRealm(config), - throwsA(isA() - .having((e) => e.message, 'message', contains("Embedded object 'AllTypesEmbedded' is unreachable by any link path from top level objects")))); - }); } List generateEncryptionKey() { @@ -1996,54 +1587,6 @@ void openEncryptedRealm(List? encryptionKey, List? decryptionKey, {voi } } -extension on Future { - Future isCancelled() async { - try { - final value = await this; - expect(value, isNotNull); - expect(value.isClosed, false); - return false; - } on CancelledException { - return true; - } - } -} - -Future _subscribeForAtlasAddedData(App app, {String? queryDifferentiator, int itemsCount = 100}) async { - final productNamePrefix = queryDifferentiator ?? generateRandomString(10); - final user1 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final config1 = Configuration.flexibleSync(user1, getSyncSchema()); - final realm1 = getRealm(config1); - await _addSubscriptions(realm1, productNamePrefix); - realm1.close(); - - final user2 = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final config2 = Configuration.flexibleSync(user2, getSyncSchema()); - final realm2 = getRealm(config2); - await _addDataToAtlas(realm2, productNamePrefix, itemsCount: itemsCount); - realm2.close(); - return config1; -} - -Future _addDataToAtlas(Realm realm, String productNamePrefix, {int itemsCount = 100}) async { - await _addSubscriptions(realm, productNamePrefix); - realm.write(() { - for (var i = 0; i < itemsCount; i++) { - realm.add(Product(ObjectId(), "${productNamePrefix}_${i + 1}")); - } - }); - await realm.syncSession.waitForUpload(); - await realm.syncSession.waitForDownload(); -} - -Future _addSubscriptions(Realm realm, String searchByPrefix) async { - final query = realm.query(r'name BEGINSWITH $0', [searchByPrefix]); - if (realm.subscriptions.find(query) == null) { - realm.subscriptions.update((mutableSubscriptions) => mutableSubscriptions.add(query)); - } - await realm.subscriptions.waitForSynchronization(); -} - extension on When { tz.TZDateTime get dateTime => tz.TZDateTime.from(dateTimeUtc, tz.getLocation(locationName)); } diff --git a/packages/realm_dart/test/realm_value_test.dart b/packages/realm_dart/test/realm_value_test.dart index d67c1e47f..08583d5e4 100644 --- a/packages/realm_dart/test/realm_value_test.dart +++ b/packages/realm_dart/test/realm_value_test.dart @@ -9,7 +9,6 @@ import 'package:realm_common/realm_common.dart' show memEquals; import 'package:realm_dart/realm.dart'; import 'package:test/test.dart' hide test, throws; -import 'session_test.dart' show validateSessionStates; import 'test.dart'; part 'realm_value_test.realm.dart'; @@ -27,32 +26,6 @@ void main() { return getRealm(config); } - Future logInAndGetSyncedRealm(AppConfiguration appConfig, ObjectId differentiator) async { - final realm = await getIntegrationRealm(appConfig: appConfig, differentiator: differentiator); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'differentiator = $0', [differentiator])); - mutableSubscriptions.add(realm.query(r'differentiator = $0', [differentiator])); - }); - await realm.subscriptions.waitForSynchronization(); - - return realm; - } - - Future<(Realm, Realm)> logInAndGetSyncedRealms(AppConfiguration appConfig, ObjectId differentiator) async { - final realm1 = await logInAndGetSyncedRealm(appConfig, differentiator); - final realm2 = await logInAndGetSyncedRealm(appConfig, differentiator); - expect(realm1.all().isEmpty, true); - expect(realm2.all().isEmpty, true); - - return (realm1, realm2); - } - - Future waitForSynchronization({required Realm uploadRealm, required Realm downloadRealm}) async { - await uploadRealm.syncSession.waitForUpload(); - await downloadRealm.syncSession.waitForDownload(); - downloadRealm.refresh(); - } - group('RealmValue', () { final primitiveValues = [ null, @@ -76,24 +49,6 @@ void main() { expect(something.oneAny, RealmValue.from(x)); }); - baasTest('Roundtrip ${x.runtimeType} $x', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(x)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object2.oneAny.value.runtimeType, x.runtimeType); - expect(object2.oneAny.value, x); - expect(object2.oneAny, RealmValue.from(x)); - }); - final queryArg = RealmValue.from(x); test('Query @type == ${queryArg.type} $x', () { final realm = getMixedRealm(); @@ -121,36 +76,6 @@ void main() { expect(parent.oneAny.as().i, 123); }); - baasTest('Roundtrip object', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final child1 = ObjectWithInt(ObjectId(), differentiator: differentiator, i: 123); - final parent1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(child1)); - realm1.write(() => realm1.add(parent1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - expect(realm2.all().single.i, 123); - final parent2 = realm2.all().single; - expect(parent2.id, parent1.id); - - expect(parent2.oneAny.value.runtimeType, ObjectWithInt); - final child2 = parent2.oneAny.as(); - expect(child2.i, 123); - - // Update child object in second realm. - const newValue = 456; - realm2.write(() => child2.i = newValue); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check updated object in first realm. - expect(parent1.oneAny.as().i, newValue); - }); - test('Query @type == object', () { final realm = getMixedRealm(); realm.write(() { @@ -318,34 +243,6 @@ void main() { expect(something.manyAny, values.map(RealmValue.from)); }); - baasTest('Roundtrip', (appConfig) async { - final values = getValues(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, manyAny: values.map(RealmValue.from)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - expect(realm2.all().single.i, 42); - expect(realm2.all().length, 2); - final object2 = realm2.query(r'_id == $0', [object1.id]).single; - expect(object2.manyAny.length, values.length); - expect(object2.manyAny[0].value, values[0]); - - // Add new item in second realm. - const newValue = 'new value'; - realm2.write(() => object2.manyAny.add(RealmValue.from(newValue))); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new item in first realm. - expect(object1.manyAny.length, values.length + 1); - expect(object1.manyAny.last.value, newValue); - }); - test('Query with list of realm values in arguments', () { final values = getValues(); final realm = getMixedRealm(); @@ -370,22 +267,6 @@ void main() { expect(obj.setOfAny, unorderedMatches([RealmValue.int(0), RealmValue.bool(false), RealmValue.nullValue()])); }); - baasTest('With numeric values', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator); - realm1.write(() => realm1.add(object1)..setOfAny.addAll(numericValues)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object2.setOfAny, unorderedMatches([RealmValue.int(0), RealmValue.bool(false), RealmValue.nullValue()])); - }); - test('Removes duplicates', () { final realm = getMixedRealm(); final values = [ @@ -493,47 +374,6 @@ void main() { expect(obj.dictOfAny['value']!.asList()[1].value, 'abc'); }); - baasTest('List get and set', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final list = RealmValue.from([5]); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: list, manyAny: [list], dictOfAny: {'value': list}); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object2.oneAny.value, isA>()); - expect(object2.oneAny.asList().length, 1); - expect(object2.oneAny.asList().single.value, 5); - - expect(object2.manyAny[0].value, isA>()); - expect(object2.manyAny[0].asList().length, 1); - expect(object2.manyAny[0].asList().single.value, 5); - - expect(object2.dictOfAny['value']!.value, isA>()); - expect(object2.dictOfAny['value']!.asList().length, 1); - expect(object2.dictOfAny['value']!.asList().single.value, 5); - - // Add new items in second realm. - realm2.write(() { - object2.oneAny.asList().add(RealmValue.from('abc')); - object2.manyAny[0].asList().add(RealmValue.from('abc')); - object2.dictOfAny['value']!.asList().add(RealmValue.from('abc')); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new items in first realm. - expect(object1.oneAny.asList()[1].value, 'abc'); - expect(object1.manyAny[0].asList()[1].value, 'abc'); - expect(object1.dictOfAny['value']!.asList()[1].value, 'abc'); - }); - test('Map get and set', () { final realm = getMixedRealm(); final map = RealmValue.from({'foo': 5}); @@ -579,47 +419,6 @@ void main() { expect(obj.dictOfAny['value']!.asMap()['bar']!.value, 'abc'); }); - baasTest('Map get and set', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final map = RealmValue.from({'foo': 5}); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: map, manyAny: [map], dictOfAny: {'value': map}); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object1.oneAny.value, isA>()); - expect(object1.oneAny.asMap().length, 1); - expect(object1.oneAny.asMap()['foo']!.value, 5); - - expect(object1.manyAny[0].value, isA>()); - expect(object1.manyAny[0].asMap().length, 1); - expect(object1.manyAny[0].asMap()['foo']!.value, 5); - - expect(object1.dictOfAny['value']!.value, isA>()); - expect(object1.dictOfAny['value']!.asMap().length, 1); - expect(object1.dictOfAny['value']!.asMap()['foo']!.value, 5); - - // Add new items in second realm. - realm2.write(() { - object2.oneAny.asMap()['bar'] = RealmValue.from('abc'); - object2.manyAny[0].asMap()['bar'] = RealmValue.from('abc'); - object2.dictOfAny['value']!.asMap()['bar'] = RealmValue.from('abc'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new items in first realm. - expect(object1.oneAny.asMap()['bar']!.value, 'abc'); - expect(object1.manyAny[0].asMap()['bar']!.value, 'abc'); - expect(object1.dictOfAny['value']!.asMap()['bar']!.value, 'abc'); - }); - for (var isManaged in [true, false]) { final managedString = isManaged ? 'managed' : 'unmanaged'; RealmValue persistIfNecessary(RealmValue rv, Realm realm) { @@ -689,71 +488,6 @@ void main() { expect(storedDict.asMap()['non-existent'], null); }); - // This test only needs to run once, but it's placed - // here to be collocated with the above test. - if (isManaged) { - baasTest('List works with all types', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final originalList = getListAllTypes(differentiator: differentiator); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(originalList)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - - final foundValue = object2.oneAny; - expect(foundValue.value, isA>()); - expect(foundValue.type, RealmValueType.list); - - final foundList = foundValue.asList(); - expect(foundList.length, originalList.length); - - // Last 3 elements are objects/collections, so they are treated specially. - final primitiveCount = originalList.length - 3; - for (var i = 0; i < primitiveCount; i++) { - expect(foundList[i].value, originalList[i]); - } - - final storedObjIndex = primitiveCount; - final storedObj = foundList[storedObjIndex]; - expect(storedObj.value, isA()); - expect(storedObj.as().isManaged, true); - expect(storedObj.as().i, 123); - - final storedListIndex = primitiveCount + 1; - final storedList = foundList[storedListIndex]; - expectMatches(storedList, [5, 'abc']); - - final storedDictIndex = primitiveCount + 2; - final storedDict = foundList[storedDictIndex]; - expectMatches(storedDict, {'int': -10, 'string': 'abc'}); - expect(storedDict.asMap()['non-existent'], null); - - // Update and add items in second realm. - realm2.write(() { - storedObj.as().i = 456; - storedList.asList()[0] = RealmValue.from('updated'); - storedList.asList().add(RealmValue.from('new-value')); - storedDict.asMap()['string'] = RealmValue.from('updated'); - storedDict.asMap()['new-value'] = RealmValue.from('new-value'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check updated items in first realm. - final list = object1.oneAny.asList(); - expect(list[storedObjIndex].as().i, 456); - expectMatches(list[storedListIndex], ['updated', 'abc', 'new-value']); - expectMatches(list[storedDictIndex], {'int': -10, 'string': 'updated', 'new-value': 'new-value'}); - }); - } - test('List when $managedString can be reassigned', () { final realm = getMixedRealm(); final obj = ObjectWithRealmValue(ObjectId(), oneAny: RealmValue.from([true, 5.3])); @@ -774,44 +508,6 @@ void main() { expectMatches(obj.oneAny, {'int': -100}); }); - if (isManaged) { - baasTest('List can be reassigned', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from([true, 5.3])); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.oneAny.type, RealmValueType.list); - expectMatches(object2.oneAny, [true, 5.3]); - - // Reassign value in second realm. - realm2.write(() => object2.oneAny = RealmValue.from(['foo'])); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check and reassign new value in first realm. - expectMatches(object1.oneAny, ['foo']); - realm1.write(() => object1.oneAny = RealmValue.from(999)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check and reassign new value in second realm. - expectMatches(object2.oneAny, 999); - realm2.write(() => object2.oneAny = RealmValue.from({'int': -100})); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new value in first realm. - expectMatches(object2.oneAny, {'int': -100}); - }); - } - Map getDictAllTypes({ObjectId? differentiator}) { return { 'primitive_null': null, @@ -857,66 +553,6 @@ void main() { expectMatches(storedDict, {'int': -10, 'string': 'abc'}); }); - // This test only needs to run once, but it's placed - // here to be collocated with the above test. - if (isManaged) { - baasTest('Map works with all types', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final originalMap = getDictAllTypes(differentiator: differentiator); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(originalMap)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - - final foundValue = object2.oneAny; - expect(foundValue.value, isA>()); - expect(foundValue.type, RealmValueType.map); - - final foundMap = foundValue.asMap(); - expect(foundMap.length, foundMap.length); - - final primitiveKeys = originalMap.keys.where((k) => k.startsWith('primitive_')); - for (var key in primitiveKeys) { - expect(foundMap[key]!.value, originalMap[key]); - } - - final storedObj = foundMap['object']!; - expect(storedObj.value, isA()); - expect(storedObj.as().isManaged, isManaged); - expect(storedObj.as().i, 123); - - final storedList = foundMap['list']!; - expectMatches(storedList, [5, 'abc']); - - final storedDict = foundMap['map']!; - expectMatches(storedDict, {'int': -10, 'string': 'abc'}); - - // Update and add items in second realm. - realm2.write(() { - storedObj.as().i = 456; - storedList.asList()[0] = RealmValue.from('updated'); - storedList.asList().add(RealmValue.from('new-value')); - storedDict.asMap()['string'] = RealmValue.from('updated'); - storedDict.asMap()['new-value'] = RealmValue.from('new-value'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check updated items in first realm. - final map = object1.oneAny.asMap(); - expect(map['object']?.as().i, 456); - expectMatches(map['list']!, ['updated', 'abc', 'new-value']); - expectMatches(map['map']!, {'int': -10, 'string': 'updated', 'new-value': 'new-value'}); - }); - } - test('Map when $managedString can be reassigned', () { final realm = getMixedRealm(); final obj = ObjectWithRealmValue(ObjectId(), oneAny: RealmValue.from({'bool': true, 'double': 5.3})); @@ -937,44 +573,6 @@ void main() { expectMatches(obj.oneAny, [1.23456789]); }); - if (isManaged) { - baasTest('Map can be reassigned', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from({'bool': true, 'double': 5.3})); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.oneAny.type, RealmValueType.map); - expectMatches(object2.oneAny, {'bool': true, 'double': 5.3}); - - // Reassign value in second realm. - realm2.write(() => object2.oneAny = RealmValue.from({'newKey': 'new value'})); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check and reassign new value in first realm. - expectMatches(object1.oneAny, {'newKey': 'new value'}); - realm1.write(() => object1.oneAny = RealmValue.from(999)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check and reassign new value in second realm. - expectMatches(object2.oneAny, 999); - realm2.write(() => object2.oneAny = RealmValue.from([1.23456789])); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new value in first realm. - expectMatches(object1.oneAny, [1.23456789]); - }); - } - test('Map inside list when $managedString can be reassigned', () { final realm = getMixedRealm(); final obj = ObjectWithRealmValue(ObjectId(), @@ -1010,66 +608,6 @@ void main() { ]); }); - if (isManaged) { - baasTest('Map inside list can be reassigned', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), - differentiator: differentiator, - oneAny: RealmValue.from([ - true, - {'foo': 'bar'}, - 5.3 - ])); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expect(object2.oneAny.type, RealmValueType.list); - expectMatches(object2.oneAny, [ - true, - {'foo': 'bar'}, - 5.3 - ]); - - final syncedList = object2.oneAny.asList(); - expect(syncedList[1].type, RealmValueType.map); - - // Reassign map in second realm. - realm2.write(() => syncedList[1] = RealmValue.from({'new': 5})); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check and reassign new value in first realm. - expectMatches(object1.oneAny, [ - true, - {'new': 5}, - 5.3 - ]); - final list = object1.oneAny.asList(); - realm1.write(() => list[1] = RealmValue.from([1.23456789])); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check and reassign new value in second realm. - expectMatches(object2.oneAny, [ - true, - [1.23456789], - 5.3 - ]); - realm2.write(() => syncedList[1] = RealmValue.from(999)); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check new value in first realm. - expectMatches(object1.oneAny, [true, 999, 5.3]); - }); - } - // TODO: Self-assignment - this doesn't work due to https://github.com/realm/realm-core/issues/7422 test('Map inside list when $managedString can self-assign', () { final realm = getMixedRealm(); @@ -1357,141 +895,6 @@ void main() { expect(rv.asMap()['1_map']!.asMap().isEmpty, true); }); - - if (isManaged) { - baasTest('RealmValue can store complex struct', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(originalList)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expectMatches(object2.oneAny, originalList); - - // Remove list item in second realm. - realm2.write(() => object2.oneAny.asList().removeAt(0)); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check list in first realm. - expectMatches(object1.oneAny, [ - { - '1_int': 5, - '1_map': { - '2_decimal': Decimal128.fromDouble(0.1), - '2_list': [ - 'bla bla', - { - '3_dict': {'4_string': 'abc'} - } - ] - } - } - ]); - - // Make updates in first realm. - realm1.write(() { - final list = object1.oneAny.asList(); - list[0].asMap()['1_double'] = RealmValue.double(5.5); - list.add(RealmValue.bool(true)); - }); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check updated list in second realm. - expectMatches(object2.oneAny, [ - { - '1_int': 5, - '1_map': { - '2_decimal': Decimal128.fromDouble(0.1), - '2_list': [ - 'bla bla', - { - '3_dict': {'4_string': 'abc'} - } - ] - }, - '1_double': 5.5 - }, - true - ]); - }); - - // Skipped until this is fixed: https://github.com/realm/realm-core/issues/7573 - baasTest('RealmValue list can remove nested collections', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final listWithMap = [ - { - '1_map': {'2_string': 'map value'}, - '1_list': ['list value'] - } - ]; - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(listWithMap)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expectMatches(object2.oneAny, listWithMap); - - // Remove nested map and list in second realm. - realm2.write(() { - // TODO: Committing these removals will cause termination: - // libc++abi: terminating due to uncaught exception of type realm::StaleAccessor: This collection is no more - object2.oneAny.asList()[0].asMap().remove('1_map'); - object2.oneAny.asList()[0].asMap().remove('1_list'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check object in first realm. - expect(object1.oneAny.asList()[0].asMap().isEmpty, true); - }, skip: true); - - // Skipped until this is fixed: https://github.com/realm/realm-core/issues/7573 - baasTest('RealmValue map can remove nested collections', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final mapWithMap = { - '1_map': { - '2_map': {'3_string': 'map value'}, - '2_list': ['list value'] - } - }; - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(mapWithMap)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check object values in second realm. - final object2 = realm2.all().single; - expectMatches(object2.oneAny, mapWithMap); - - // Remove nested map and list in second realm. - realm2.write(() { - // TODO: Committing these removals will cause termination: - // libc++abi: terminating due to uncaught exception of type realm::StaleAccessor: This collection is no more - object2.oneAny.asMap()['1_map']!.asMap().remove('2_map'); - object2.oneAny.asMap()['1_map']!.asMap().remove('2_list'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Check object in first realm. - expect(object1.oneAny.asMap()['1_map']!.asMap().isEmpty, true); - }, skip: true); - } }); } @@ -1716,247 +1119,6 @@ void main() { expect(identical(obj.oneAny.asMap(), map), false); }); - baasTest('List has conflicting writes resolved', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final originalList = ['original 0', 'original 1', 'original 2']; - final rvList = RealmValue.from(originalList); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: rvList, manyAny: [rvList], dictOfAny: {'key': rvList}); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check synced object in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object2.oneAny.value, isA>()); - expectMatches(object2.oneAny, originalList); - - expect(object2.manyAny[0].value, isA>()); - expectMatches(object2.manyAny[0], originalList); - - expect(object2.dictOfAny['key']!.value, isA>()); - expectMatches(object2.dictOfAny['key']!, originalList); - - // Pause sessions and do conflicting writes. - realm1.syncSession.pause(); - realm2.syncSession.pause(); - await validateSessionStates("State after pause", realm1.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - await validateSessionStates("State after pause", realm2.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - - // Realm1 changes: update type at index0, update at index 1, remove at index 2. - realm1.write(() { - object1.oneAny.asList()[0] = RealmValue.from(['updated str->lst (index 0) - realm1']); - object1.oneAny.asList()[1] = RealmValue.from('updated str->str (index 1) - realm1'); - object1.oneAny.asList().removeAt(2); - - object1.manyAny[0].asList()[0] = RealmValue.from(['updated str->lst (index 0) - realm1']); - object1.manyAny[0].asList()[1] = RealmValue.from('updated str->str (index 1) - realm1'); - object1.manyAny[0].asList().removeAt(2); - - object1.dictOfAny['key']!.asList()[0] = RealmValue.from(['updated str->lst (index 0) - realm1']); - object1.dictOfAny['key']!.asList()[1] = RealmValue.from('updated str->str (index 1) - realm1'); - object1.dictOfAny['key']!.asList().removeAt(2); - }); - - // Realm2 changes: update type at index0, update at index 1, update at index 2, add at end (index 3). - realm2.write(() { - object2.oneAny.asList()[0] = RealmValue.from({'key': 'updated str->map (index 0) - realm2'}); - object2.oneAny.asList()[1] = RealmValue.from('updated str->str (index 1) - realm2'); - object2.oneAny.asList()[2] = RealmValue.from('updated str->str (index 2) - realm2'); - object2.oneAny.asList().add(RealmValue.from('added str (index 3) - realm2')); - - object2.manyAny[0].asList()[0] = RealmValue.from({'key': 'updated str->map (index 0) - realm2'}); - object2.manyAny[0].asList()[1] = RealmValue.from('updated str->str (index 1) - realm2'); - object2.manyAny[0].asList()[2] = RealmValue.from('updated str->str (index 2) - realm2'); - object2.manyAny[0].asList().add(RealmValue.from('added str (index 3) - realm2')); - - object2.dictOfAny['key']!.asList()[0] = RealmValue.from({'key': 'updated str->map (index 0) - realm2'}); - object2.dictOfAny['key']!.asList()[1] = RealmValue.from('updated str->str (index 1) - realm2'); - object2.dictOfAny['key']!.asList()[2] = RealmValue.from('updated str->str (index 2) - realm2'); - object2.dictOfAny['key']!.asList().add(RealmValue.from('added str (index 3) - realm2')); - }); - - // Resume sessions and check resolution. - realm1.syncSession.resume(); - realm2.syncSession.resume(); - await validateSessionStates("State after resume", realm1.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - await validateSessionStates("State after resume", realm2.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Update of type at index 0 in realm2 should have won. - expect(object1.oneAny.asList()[0].value, object2.oneAny.asList()[0].value); - expect(object1.oneAny.asList()[0].value, isA>()); - expectMatches(object1.oneAny.asList()[0], {'key': 'updated str->map (index 0) - realm2'}); - - expect(object1.manyAny[0].asList()[0].value, object2.manyAny[0].asList()[0].value); - expect(object1.manyAny[0].asList()[0].value, isA>()); - expectMatches(object1.manyAny[0].asList()[0], {'key': 'updated str->map (index 0) - realm2'}); - - expect(object1.dictOfAny['key']!.asList()[0].value, object2.dictOfAny['key']!.asList()[0].value); - expect(object1.dictOfAny['key']!.asList()[0].value, isA>()); - expectMatches(object1.dictOfAny['key']!.asList()[0], {'key': 'updated str->map (index 0) - realm2'}); - - // Update at index 1 in realm2 should have won. - expect(object1.oneAny.asList()[1].value, object2.oneAny.asList()[1].value); - expect(object1.oneAny.asList()[1].value, 'updated str->str (index 1) - realm2'); - - expect(object1.manyAny[0].asList()[1].value, object2.manyAny[0].asList()[1].value); - expect(object1.manyAny[0].asList()[1].value, 'updated str->str (index 1) - realm2'); - - expect(object1.dictOfAny['key']!.asList()[1].value, object2.dictOfAny['key']!.asList()[1].value); - expect(object1.dictOfAny['key']!.asList()[1].value, 'updated str->str (index 1) - realm2'); - - // Removal at index 2 in realm1 should have won over update in realm2. - expect(object1.oneAny.asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - expect(object2.oneAny.asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - - expect(object1.manyAny[0].asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - expect(object2.manyAny[0].asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - - expect(object1.dictOfAny['key']!.asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - expect(object2.dictOfAny['key']!.asList().contains(RealmValue.from('updated str->str (index 2) - realm2')), false); - - // Adding at index 3 in realm2 should have resolved to adding at index 2. - expect(object1.oneAny.asList()[2].value, object2.oneAny.asList()[2].value); - expect(object1.oneAny.asList()[2].value, 'added str (index 3) - realm2'); - - expect(object1.manyAny[0].asList()[2].value, object2.manyAny[0].asList()[2].value); - expect(object1.manyAny[0].asList()[2].value, 'added str (index 3) - realm2'); - - expect(object1.dictOfAny['key']!.asList()[2].value, object2.dictOfAny['key']!.asList()[2].value); - expect(object1.dictOfAny['key']!.asList()[2].value, 'added str (index 3) - realm2'); - }); - - baasTest('Map has conflicting writes resolved', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final originalMap = {'key0': 'original 0', 'key1': 'original 1', 'key2': 'original 2'}; - final rvMap = RealmValue.from(originalMap); - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: rvMap, manyAny: [rvMap], dictOfAny: {'key': rvMap}); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Check synced object in second realm. - final object2 = realm2.all().single; - expect(object2.id, object1.id); - expect(object2.oneAny.value, isA>()); - expectMatches(object2.oneAny, originalMap); - - expect(object2.manyAny[0].value, isA>()); - expectMatches(object2.manyAny[0], originalMap); - - expect(object2.dictOfAny['key']!.value, isA>()); - expectMatches(object2.dictOfAny['key']!, originalMap); - - // Pause sessions and do conflicting writes. - realm1.syncSession.pause(); - realm2.syncSession.pause(); - await validateSessionStates("State after pause", realm1.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - await validateSessionStates("State after pause", realm2.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - - // Realm1 changes: update type at key0, update at key1, remove at key2. - realm1.write(() { - object1.oneAny.asMap()['key0'] = RealmValue.from(['updated str->lst (key0) - realm1']); - object1.oneAny.asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm1'); - object1.oneAny.asMap().remove('key2'); - - object1.manyAny[0].asMap()['key0'] = RealmValue.from(['updated str->lst (key0) - realm1']); - object1.manyAny[0].asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm1'); - object1.manyAny[0].asMap().remove('key2'); - - object1.dictOfAny['key']!.asMap()['key0'] = RealmValue.from(['updated str->lst (key0) - realm1']); - object1.dictOfAny['key']!.asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm1'); - object1.dictOfAny['key']!.asMap().remove('key2'); - }); - - // Realm2 changes: update type at key0, update at key1, update at key2, add key3. - realm2.write(() { - object2.oneAny.asMap()['key0'] = RealmValue.from({'key': 'updated str->map (key0) - realm2'}); - object2.oneAny.asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm2'); - object2.oneAny.asMap()['key2'] = RealmValue.from('updated str->str (key2) - realm2'); - object2.oneAny.asMap()['key3'] = RealmValue.from('added str (key3) - realm2'); - - object2.manyAny[0].asMap()['key0'] = RealmValue.from({'key': 'updated str->map (key0) - realm2'}); - object2.manyAny[0].asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm2'); - object2.manyAny[0].asMap()['key2'] = RealmValue.from('updated str->str (key2) - realm2'); - object2.manyAny[0].asMap()['key3'] = RealmValue.from('added str (key3) - realm2'); - - object2.dictOfAny['key']!.asMap()['key0'] = RealmValue.from({'key': 'updated str->map (key0) - realm2'}); - object2.dictOfAny['key']!.asMap()['key1'] = RealmValue.from('updated str->str (key1) - realm2'); - object2.dictOfAny['key']!.asMap()['key2'] = RealmValue.from('updated str->str (key2) - realm2'); - object2.dictOfAny['key']!.asMap()['key3'] = RealmValue.from('added str (key3) - realm2'); - }); - - // Resume sessions and check resolution. - realm1.syncSession.resume(); - realm2.syncSession.resume(); - await validateSessionStates("State after resume", realm1.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - await validateSessionStates("State after resume", realm2.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - - // Update of type at key0 in realm2 should have won. - expect(object1.oneAny.asMap()['key0']!.value, object2.oneAny.asMap()['key0']!.value); - expect(object1.oneAny.asMap()['key0']!.value, isA>()); - expectMatches(object1.oneAny.asMap()['key0']!, {'key': 'updated str->map (key0) - realm2'}); - - expect(object1.manyAny[0].asMap()['key0']!.value, object2.manyAny[0].asMap()['key0']!.value); - expect(object1.manyAny[0].asMap()['key0']!.value, isA>()); - expectMatches(object1.manyAny[0].asMap()['key0']!, {'key': 'updated str->map (key0) - realm2'}); - - expect(object1.dictOfAny['key']!.asMap()['key0']!.value, object2.dictOfAny['key']!.asMap()['key0']!.value); - expect(object1.dictOfAny['key']!.asMap()['key0']!.value, isA>()); - expectMatches(object1.dictOfAny['key']!.asMap()['key0']!, {'key': 'updated str->map (key0) - realm2'}); - - // Update at key1 in realm2 should have won. - expect(object1.oneAny.asMap()['key1']!.value, object2.oneAny.asMap()['key1']!.value); - expect(object1.oneAny.asMap()['key1']!.value, 'updated str->str (key1) - realm2'); - - expect(object1.manyAny[0].asMap()['key1']!.value, object2.manyAny[0].asMap()['key1']!.value); - expect(object1.manyAny[0].asMap()['key1']!.value, 'updated str->str (key1) - realm2'); - - expect(object1.dictOfAny['key']!.asMap()['key1']!.value, object2.dictOfAny['key']!.asMap()['key1']!.value); - expect(object1.dictOfAny['key']!.asMap()['key1']!.value, 'updated str->str (key1) - realm2'); - - // Update at key2 in realm2 (last writer) should have won over "removal" in realm1 - // due to OT acting on two updates (the removal being a `KeyErased` update). - expect(object1.oneAny.asMap()['key2']!.value, object2.oneAny.asMap()['key2']!.value); - expect(object1.oneAny.asMap()['key2']!.value, 'updated str->str (key2) - realm2'); - - expect(object1.manyAny[0].asMap()['key2']!.value, object2.manyAny[0].asMap()['key2']!.value); - expect(object1.manyAny[0].asMap()['key2']!.value, 'updated str->str (key2) - realm2'); - - expect(object1.dictOfAny['key']!.asMap()['key2']!.value, object2.dictOfAny['key']!.asMap()['key2']!.value); - expect(object1.dictOfAny['key']!.asMap()['key2']!.value, 'updated str->str (key2) - realm2'); - - // Adding key3 in realm2 should have resolved to the same thing. - expect(object1.oneAny.asMap()['key3']!.value, object2.oneAny.asMap()['key3']!.value); - expect(object1.oneAny.asMap()['key3']!.value, 'added str (key3) - realm2'); - - expect(object1.manyAny[0].asMap()['key3']!.value, object2.manyAny[0].asMap()['key3']!.value); - expect(object1.manyAny[0].asMap()['key3']!.value, 'added str (key3) - realm2'); - - expect(object1.dictOfAny['key']!.asMap()['key3']!.value, object2.dictOfAny['key']!.asMap()['key3']!.value); - expect(object1.dictOfAny['key']!.asMap()['key3']!.value, 'added str (key3) - realm2'); - }); - test('Notifications', () async { final realm = getMixedRealm(); final obj = ObjectWithRealmValue(ObjectId(), @@ -2105,164 +1267,6 @@ void main() { expect(mapChanges, hasLength(3)); }); - baasTest('Notifications', (appConfig) async { - final differentiator = ObjectId(); - final (realm1, realm2) = await logInAndGetSyncedRealms(appConfig, differentiator); - - // Add object in first realm. - final list = [ - 5, - { - 'string': 'bar', - 'list': [10] - } - ]; - final object1 = ObjectWithRealmValue(ObjectId(), differentiator: differentiator, oneAny: RealmValue.from(list)); - realm1.write(() => realm1.add(object1)); - - await waitForSynchronization(uploadRealm: realm1, downloadRealm: realm2); - - // Add listeners in first realm. - final List> parentChanges = []; - final subscription = object1.changes.listen((event) { - parentChanges.add(event); - }); - - final List> listChanges = []; - final listSubscription = object1.oneAny.asList().changes.listen((event) { - listChanges.add(event); - }); - - final List> mapChanges = []; - final mapSubscription = object1.oneAny.asList()[1].asMap().changes.listen((event) { - mapChanges.add(event); - }); - - await Future.delayed(Duration(milliseconds: 20)); - - parentChanges.clear(); - listChanges.clear(); - mapChanges.clear(); - - // Get object in second realm. - final object2 = realm2.query(r'_id == $0', [object1.id]).single; - - // Add item to list in second realm. - realm2.write(() { - object2.oneAny.asList().add(RealmValue.bool(true)); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - await Future.delayed(Duration(milliseconds: 20)); - - // Expect listeners to be fired in first realm. - expect(parentChanges, hasLength(1)); - expect(parentChanges[0].properties, ['oneAny']); - - expect(listChanges, hasLength(1)); - expect(listChanges[0].inserted, [2]); - expect(listChanges[0].deleted, isEmpty); - expect(listChanges[0].modified, isEmpty); - expect(listChanges[0].isCleared, false); - expect(listChanges[0].isCollectionDeleted, false); - - expect(mapChanges, hasLength(0)); - - // Update and add entry in nested dictionary in second realm. - realm2.write(() { - object2.oneAny.asList()[1].asMap()['list'] = RealmValue.from([10]); - object2.oneAny.asList()[1].asMap()['new-value'] = RealmValue.from({'foo': 'bar'}); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - await Future.delayed(Duration(milliseconds: 20)); - - // Expect listeners to be fired in first realm. - expect(parentChanges, hasLength(2)); - expect(parentChanges[1].properties, ['oneAny']); - - expect(listChanges, hasLength(2)); - expect(listChanges[1].inserted, isEmpty); - expect(listChanges[1].deleted, isEmpty); - expect(listChanges[1].modified, [1]); - expect(listChanges[1].isCleared, false); - expect(listChanges[1].isCollectionDeleted, false); - - expect(mapChanges, hasLength(1)); - expect(mapChanges[0].modified, ['list']); - expect(mapChanges[0].inserted, ['new-value']); - expect(mapChanges[0].deleted, isEmpty); - expect(mapChanges[0].isCleared, false); - expect(mapChanges[0].isCollectionDeleted, false); - - // Remove entry in nested dictionary in second realm. - realm2.write(() { - object2.oneAny.asList()[1].asMap().remove('string'); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - await Future.delayed(Duration(milliseconds: 20)); - - // Expect listeners to be fired in first realm. - expect(parentChanges, hasLength(3)); - expect(parentChanges[2].properties, ['oneAny']); - - expect(listChanges, hasLength(3)); - expect(listChanges[2].inserted, isEmpty); - expect(listChanges[2].deleted, isEmpty); - expect(listChanges[2].modified, [1]); - expect(listChanges[2].isCleared, false); - expect(listChanges[2].isCollectionDeleted, false); - - expect(mapChanges, hasLength(2)); - expect(mapChanges[1].modified, isEmpty); - expect(mapChanges[1].inserted, isEmpty); - expect(mapChanges[1].deleted, ['string']); - expect(mapChanges[1].isCleared, false); - expect(mapChanges[1].isCollectionDeleted, false); - expect(mapChanges[1].isCollectionDeleted, false); - - // Remove dictionary from list in second realm. - realm2.write(() { - object2.oneAny.asList().removeAt(1); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - await Future.delayed(Duration(milliseconds: 20)); - - // Expect listeners to be fired in first realm. - expect(parentChanges, hasLength(4)); - expect(parentChanges[3].properties, ['oneAny']); - - expect(listChanges, hasLength(4)); - expect(listChanges[3].inserted, isEmpty); - expect(listChanges[3].deleted, [1]); - expect(listChanges[3].modified, isEmpty); - expect(listChanges[3].isCleared, false); - expect(listChanges[3].isCollectionDeleted, false); - - expect(mapChanges, hasLength(3)); - expect(mapChanges[2].isCollectionDeleted, true); - - // Cancel subscriptions. - subscription.cancel(); - listSubscription.cancel(); - mapSubscription.cancel(); - - // Overwrite list with primitive in second realm. - realm2.write(() { - object2.oneAny = RealmValue.bool(false); - }); - - await waitForSynchronization(uploadRealm: realm2, downloadRealm: realm1); - await Future.delayed(Duration(milliseconds: 20)); - - // Subscriptions have been canceled - shouldn't get more notifications. - expect(parentChanges, hasLength(4)); - expect(listChanges, hasLength(4)); - expect(mapChanges, hasLength(3)); - }); - test('Queries', () { final realm = getMixedRealm(); diff --git a/packages/realm_dart/test/session_test.dart b/packages/realm_dart/test/session_test.dart deleted file mode 100644 index f0076879f..000000000 --- a/packages/realm_dart/test/session_test.dart +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'package:test/test.dart' hide test, throws; -import 'package:realm_dart/realm.dart'; -import 'test.dart'; - -Future validateSessionStates(String validationName, Session session, - {SessionState? expectedSessionState, ConnectionState? expectedConnectionState}) async { - if (expectedSessionState != null) { - await waitForCondition(() => session.state.name == expectedSessionState.name, - message: 'Expected ${session.state} to equal $expectedSessionState. Validation: $validationName', timeout: const Duration(seconds: 15)); - } - - if (expectedConnectionState != null) { - await waitForCondition(() => session.connectionState.name == expectedConnectionState.name, - message: 'Expected ${session.connectionState} to equal $expectedConnectionState. Validation: $validationName', timeout: const Duration(seconds: 15)); - } -} - -void main() { - setupTests(); - - test('Realm.syncSession throws on wrong configuration', () { - final config = Configuration.local([Task.schema]); - final realm = getRealm(config); - expect(() => realm.syncSession, throws()); - }); - - baasTest('Realm.syncSession returns on FLX configuration', (configuration) async { - final realm = await getIntegrationRealm(); - - expect(realm.syncSession, isNotNull); - expect(realm.syncSession.realmPath, realm.config.path); - expect(realm.syncSession, realm.syncSession); - }); - - baasTest('SyncSession.user returns a valid user', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final config = Configuration.flexibleSync(user, getSyncSchema()); - final realm = getRealm(config); - - expect(realm.syncSession.user, user); - expect(realm.syncSession.user.id, user.id); - expect(realm.syncSession.user.app.id, configuration.appId); - expect(realm.syncSession.user.app.currentUser, user); - }); - - baasTest('SyncSession when isolate is torn down does not crash', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final config = Configuration.flexibleSync(user, getSyncSchema()); - - // Don't use getRealm because we want the Realm to survive - final realm = Realm(config); - - expect(realm.syncSession, isNotNull); - }); - - baasTest('SyncSession.pause/resume', (configuration) async { - final realm = await getIntegrationRealm(); - - await validateSessionStates("Initial state", realm.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - - realm.syncSession.pause(); - - await validateSessionStates("State after pause", realm.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - - realm.syncSession.resume(); - - await validateSessionStates("State after resume", realm.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - }); - - baasTest('SyncSession.pause called multiple times is a no-op', (configuration) async { - final realm = await getIntegrationRealm(); - - await validateSessionStates("Initial state", realm.syncSession, expectedSessionState: SessionState.active); - - realm.syncSession.pause(); - - await validateSessionStates("State after pause", realm.syncSession, expectedSessionState: SessionState.inactive); - - // This should not do anything - realm.syncSession.pause(); - - await validateSessionStates("State after second pause", realm.syncSession, expectedSessionState: SessionState.inactive); - }); - - baasTest('SyncSession.resume called multiple times is a no-op', (configuration) async { - final realm = await getIntegrationRealm(); - - await validateSessionStates("Initial state", realm.syncSession, expectedSessionState: SessionState.active); - - realm.syncSession.resume(); - realm.syncSession.resume(); - - await validateSessionStates("State after resume called multiple times", realm.syncSession, expectedSessionState: SessionState.active); - }); - - baasTest('SyncSession.waitForUpload with no changes', (configuration) async { - final realm = await getIntegrationRealm(); - - await realm.syncSession.waitForUpload(); - - // Call it multiple times to make sure it doesn't throw - await realm.syncSession.waitForUpload(); - }); - - baasTest('SyncSession.waitForDownload with no changes', (configuration) async { - final realm = await getIntegrationRealm(); - - await realm.syncSession.waitForDownload(); - - // Call it multiple times to make sure it doesn't throw - await realm.syncSession.waitForDownload(); - }); - - baasTest('SyncSession.waitForDownload/waitForUpload canceled', (configuration) async { - final realm = await getIntegrationRealm(); - final cancellationDownloadToken = CancellationToken(); - final waitForDownloadFuture = realm.syncSession.waitForDownload(cancellationDownloadToken); - cancellationDownloadToken.cancel(); - expect(() async => await waitForDownloadFuture, throwsA(isA())); - - final cancellationUploadToken = CancellationToken(); - final waitForUploadFuture = realm.syncSession.waitForUpload(cancellationUploadToken); - cancellationUploadToken.cancel(); - expect(() async => await waitForUploadFuture, throwsA(isA())); - }); - - baasTest('SyncSession.waitForUpload with changes', (configuration) async { - final differentiator = ObjectId(); - - final realmA = await getIntegrationRealm(differentiator: differentiator); - final realmB = await getIntegrationRealm(differentiator: differentiator); - - realmA.write(() { - realmA.add(NullableTypes(ObjectId(), differentiator, stringProp: 'abc')); - }); - - await realmA.syncSession.waitForUpload(); - await realmB.syncSession.waitForDownload(); - - expect(realmA.all().map((e) => e.stringProp), realmB.all().map((e) => e.stringProp)); - - realmB.write(() { - realmB.add(NullableTypes(ObjectId(), differentiator, stringProp: 'def')); - }); - - await realmB.syncSession.waitForUpload(); - await realmA.syncSession.waitForDownload(); - - expect(realmA.all().map((e) => e.stringProp), realmB.all().map((e) => e.stringProp)); - }); - - StreamProgressData subscribeToProgress(Realm realm, ProgressDirection direction, ProgressMode mode) { - final data = StreamProgressData(); - final stream = realm.syncSession.getProgressStream(direction, mode); - - data.subscription = stream.listen((event) { - if (mode == ProgressMode.forCurrentlyOutstandingWork) { - expect(event.progressEstimate, greaterThanOrEqualTo(data.progressEstimate)); - } - - data.progressEstimate = event.progressEstimate; - data.callbacksInvoked++; - }); - - data.subscription.onDone(() { - data.doneInvoked = true; - }); - - return data; - } - - Future validateData(StreamProgressData data, {bool expectDone = false}) async { - // Wait a little since the last event is sent asynchronously - await Future.delayed(const Duration(milliseconds: 100)); - - expect(data.callbacksInvoked, greaterThan(0)); - expect(data.progressEstimate, greaterThan(0)); - if (expectDone) { - expect(data.progressEstimate, 1.0); - } else { - expect(data.progressEstimate, lessThanOrEqualTo(1.0)); - } - expect(data.doneInvoked, expectDone); - } - - baasTest('SyncSession.getProgressStream forCurrentlyOutstandingWork', (configuration) async { - final differentiator = ObjectId(); - final uploadRealm = await getIntegrationRealm(differentiator: differentiator); - - for (var i = 0; i < 10; i++) { - uploadRealm.write(() { - uploadRealm.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - } - - final uploadData = subscribeToProgress(uploadRealm, ProgressDirection.upload, ProgressMode.forCurrentlyOutstandingWork); - await uploadRealm.syncSession.waitForUpload(); - await validateData(uploadData, expectDone: true); - - // Subscribe immediately after the upload to ensure we get the entire upload message as progress notifications - final downloadRealm = await getIntegrationRealm(differentiator: differentiator, waitForSync: false); - final downloadData = subscribeToProgress(downloadRealm, ProgressDirection.download, ProgressMode.forCurrentlyOutstandingWork); - - await downloadRealm.subscriptions.waitForSynchronization(); - - await downloadRealm.syncSession.waitForDownload(); - - await validateData(downloadData, expectDone: true); - - // We should not see more updates in either direction - final uploadCallbacks = uploadData.callbacksInvoked; - final downloadCallbacks = downloadData.callbacksInvoked; - - uploadRealm.write(() { - uploadRealm.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - - await uploadRealm.syncSession.waitForUpload(); - await downloadRealm.syncSession.waitForDownload(); - - expect(uploadRealm.all().length, downloadRealm.all().length); - expect(uploadData.callbacksInvoked, uploadCallbacks); - expect(downloadData.callbacksInvoked, downloadCallbacks); - - await uploadData.subscription.cancel(); - await downloadData.subscription.cancel(); - }); - - baasTest('SyncSession.getProgressStream after reconnecting', (configuration) async { - final differentiator = ObjectId(); - final uploadRealm = await getIntegrationRealm(differentiator: differentiator); - - // Make sure we've caught up, then close the Realm. We'll reopen it later and verify that progress notifications - // are delivered. This is different from "SyncSession.getProgressStream forCurrentlyOutstandingWork" where we're - // testing notifications after change of query. - final user = await getIntegrationUser(appConfig: configuration); - final config = getIntegrationConfig(user); - var downloadRealm = getRealm(config); - downloadRealm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(downloadRealm.query(r'differentiator = $0', [differentiator])); - }); - - await downloadRealm.subscriptions.waitForSynchronization(); - downloadRealm.close(); - - for (var i = 0; i < 10; i++) { - uploadRealm.write(() { - uploadRealm.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - } - - final uploadData = subscribeToProgress(uploadRealm, ProgressDirection.upload, ProgressMode.forCurrentlyOutstandingWork); - await uploadRealm.syncSession.waitForUpload(); - await validateData(uploadData, expectDone: true); - - // Reopen the download realm and subscribe for notifications - those should still be delivered as normal. - downloadRealm = getRealm(getIntegrationConfig(user)); - final downloadData = subscribeToProgress(downloadRealm, ProgressDirection.download, ProgressMode.reportIndefinitely); - - await downloadRealm.syncSession.waitForDownload(); - - await validateData(downloadData, expectDone: false); - - // We should not see more updates in upload direction, but should see a callback invoked for download - final uploadCallbacks = uploadData.callbacksInvoked; - final downloadCallbacks = downloadData.callbacksInvoked; - - uploadRealm.write(() { - uploadRealm.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - - await uploadRealm.syncSession.waitForUpload(); - await downloadRealm.syncSession.waitForDownload(); - - expect(uploadRealm.all().length, downloadRealm.all().length); - expect(uploadData.callbacksInvoked, uploadCallbacks); - expect(downloadData.callbacksInvoked, greaterThan(downloadCallbacks)); - - await uploadData.subscription.cancel(); - await downloadData.subscription.cancel(); - }); - - baasTest('SyncSession.getProgressStream reportIndefinitely', (configuration) async { - final differentiator = ObjectId(); - final realmA = await getIntegrationRealm(differentiator: differentiator); - final realmB = await getIntegrationRealm(differentiator: differentiator); - - for (var i = 0; i < 10; i++) { - realmA.write(() { - realmA.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - } - - final uploadData = subscribeToProgress(realmA, ProgressDirection.upload, ProgressMode.reportIndefinitely); - final downloadData = subscribeToProgress(realmB, ProgressDirection.download, ProgressMode.reportIndefinitely); - - await realmA.syncSession.waitForUpload(); - await validateData(uploadData); - expect(uploadData.progressEstimate, 1.0); - - await realmB.syncSession.waitForDownload(); - await validateData(downloadData); - expect(downloadData.progressEstimate, 1.0); - - // Snapshot the current state, then add a new object. We should receive more notifications - final uploadSnapshot = StreamProgressData.snapshot(uploadData); - final downloadSnapshot = StreamProgressData.snapshot(downloadData); - - realmA.write(() { - realmA.add(NullableTypes(ObjectId(), differentiator, stringProp: generateRandomString(50))); - }); - - await realmA.syncSession.waitForUpload(); - await realmB.syncSession.waitForDownload(); - - await validateData(uploadData); - expect(uploadData.progressEstimate, 1.0); - await validateData(downloadData); - expect(downloadData.progressEstimate, 1.0); - - expect(uploadData.callbacksInvoked, greaterThan(uploadSnapshot.callbacksInvoked)); - expect(downloadData.callbacksInvoked, greaterThan(downloadSnapshot.callbacksInvoked)); - - await uploadData.subscription.cancel(); - await downloadData.subscription.cancel(); - }); - - baasTest('SyncSession.getConnectionStateStream', (configuration) async { - final realm = await getIntegrationRealm(); - - await validateSessionStates("Initial state", realm.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - - final states = []; - final stream = realm.syncSession.connectionStateChanges; - final subscription = stream.listen((event) { - states.add(event); - }); - - // Verify we get a notification when we pause the session - realm.syncSession.pause(); - - await validateSessionStates("State after pause", realm.syncSession, - expectedSessionState: SessionState.inactive, expectedConnectionState: ConnectionState.disconnected); - await waitForCondition(() => states.length == 1, timeout: const Duration(seconds: 15), message: 'expected 1 notification, got ${states.length}'); - - expect(states[0].previous.name, ConnectionState.connected.name); - expect(states[0].current.name, ConnectionState.disconnected.name); - - // When resuming, we should get two notifications - first we go to connecting, then connected - realm.syncSession.resume(); - - await validateSessionStates("State after resume", realm.syncSession, - expectedSessionState: SessionState.active, expectedConnectionState: ConnectionState.connected); - await waitForCondition(() => states.length == 3, timeout: const Duration(seconds: 15), message: 'expected 3 notifications, got ${states.length}'); - - expect(states[1].previous.name, ConnectionState.disconnected.name); - expect(states[1].current.name, ConnectionState.connecting.name); - - expect(states[2].previous.name, ConnectionState.connecting.name); - expect(states[2].current.name, ConnectionState.connected.name); - - await subscription.cancel(); - }); - - baasTest('SyncSession when Realm is closed gets closed as well', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final config = Configuration.flexibleSync(user, getSyncSchema()); - final realm = getRealm(config); - - final session = realm.syncSession; - expect(() => session.state, returnsNormally); - - realm.close(); - - expect(() => session.state, throws()); - }); -} - -class StreamProgressData { - double progressEstimate; - int callbacksInvoked; - bool doneInvoked; - late StreamSubscription subscription; - - StreamProgressData({this.progressEstimate = -1, this.callbacksInvoked = 0, this.doneInvoked = false}); - - StreamProgressData.snapshot(StreamProgressData other) - : this(callbacksInvoked: other.callbacksInvoked, doneInvoked: other.doneInvoked, progressEstimate: other.progressEstimate); -} diff --git a/packages/realm_dart/test/subscription_test.dart b/packages/realm_dart/test/subscription_test.dart deleted file mode 100644 index a24c05ade..000000000 --- a/packages/realm_dart/test/subscription_test.dart +++ /dev/null @@ -1,769 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:math'; -import 'dart:typed_data'; - -import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/handles/realm_core.dart'; -import 'package:realm_dart/src/subscription.dart'; - -import 'test.dart'; -import 'utils/platform_util.dart'; - -void main() { - setupTests(); - - test('Get subscriptions throws on wrong configuration', () { - final config = Configuration.local([Task.schema]); - final realm = getRealm(config); - expect(() => realm.subscriptions, throws()); - }); - - baasTest('SubscriptionSet.state/waitForSynchronization', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - await subscriptions.waitForSynchronization(); - expect(subscriptions.state, SubscriptionSetState.complete); - }); - - baasTest('SubscriptionSet.state/waitForSynchronization canceled', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final cancellationToken = CancellationToken(); - final waitFuture = subscriptions.waitForSynchronization(cancellationToken); - cancellationToken.cancel(); - expect(() async => await waitFuture, throwsA(isA())); - }); - - baasTest('SubscriptionSet.version', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - expect(subscriptions.version, 0); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - }); - - expect(subscriptions.length, 1); - expect(subscriptions.version, 1); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.clear(); - }); - - expect(subscriptions.length, 0); - expect(subscriptions.version, 2); - }); - - baasTest('MutableSubscriptionSet.add', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final query = realm.all(); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - expect(subscriptions, isNotEmpty); - expect(subscriptions.find(query), isNotNull); - }); - - baasTest('MutableSubscriptionSet.add named', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - const name = 'some name'; - late Subscription s; - subscriptions.update((mutableSubscriptions) { - s = mutableSubscriptions.add(realm.all(), name: name); - }); - expect(subscriptions, isNotEmpty); - expect(subscriptions.findByName(name), s); - }); - - baasTest('SubscriptionSet.find', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final query = realm.all(); - - expect(subscriptions.find(query), isNull); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - expect(subscriptions.find(query), isNotNull); - }); - - baasTest('SubscriptionSet.find return match, even if named', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final query = realm.all(); - - expect(subscriptions.find(query), isNull); - - late Subscription s; - subscriptions.update((mutableSubscriptions) { - s = mutableSubscriptions.add(query, name: 'foobar'); - }); - expect(subscriptions.find(query), s); - }); - - baasTest('SubscriptionSet.findByName', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - const name = 'some name'; - expect(subscriptions.findByName(name), isNull); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: name); - }); - expect(subscriptions.findByName(name), isNotNull); - }); - - baasTest('MutableSubscriptionSet.remove', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final query = realm.all(); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - expect(subscriptions, isNotEmpty); - - final s = subscriptions[0]; - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.remove(s); - }); - expect(subscriptions, isEmpty); - }); - - baasTest('MutableSubscriptionSet.removeByQuery', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final query = realm.all(); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - expect(subscriptions, isNotEmpty); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByQuery(query); - }); - expect(subscriptions, isEmpty); - }); - - baasTest('MutableSubscriptionSet.removeByName', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - const name = 'some name'; - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: name); - }); - expect(subscriptions, isNotEmpty); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByName(name); - }); - expect(subscriptions, isEmpty); - }); - - baasTest('MutableSubscriptionSet.removeAll', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()])); - mutableSubscriptions.add(realm.all()); - }); - expect(subscriptions.length, 2); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.clear(); - }); - expect(subscriptions, isEmpty); - }); - - baasTest('SubscriptionSet.elementAt', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()])); - mutableSubscriptions.add(realm.all()); - }); - expect(subscriptions.length, 2); - - int index = 0; - for (final s in subscriptions) { - expect(s, s); - expect(subscriptions[index], isNotNull); - expect(subscriptions[index], subscriptions[index]); - expect(s, subscriptions[index]); - ++index; - } - - expect(() => subscriptions[-1], throws()); - expect(() => subscriptions[1000], throws()); - }); - - baasTest('MutableSubscriptionSet.elementAt', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - subscriptions.update((mutableSubscriptions) { - final s = mutableSubscriptions.add(realm.all()); - expect(mutableSubscriptions[0], isNotNull); - expect(s, isNotNull); - expect(mutableSubscriptions.state, SubscriptionSetState.pending); // not _uncommitted! - expect(mutableSubscriptions[0], s); - }); - }); - - baasTest('MutableSubscriptionSet.add double-add throws', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - // Adding same unnamed query twice without requesting an update will just de-duplicate - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - mutableSubscriptions.add(realm.all()); - }); - expect(subscriptions.length, 1); - - // Okay to add same query under different names, not de-duplicated - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: 'foo'); - mutableSubscriptions.add(realm.all(), name: 'bar'); - }); - expect(subscriptions.length, 3); - - // Cannot add different queries under same name, unless the second - // can update the first. - expect(() { - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: 'same'); - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()]), name: 'same'); - }); - }, throws('Duplicate subscription')); - }); - - baasTest('MutableSubscriptionSet.add with update flag', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - mutableSubscriptions.add(realm.all(), update: true); - }); - - expect(subscriptions.length, 1); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: 'same'); - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()]), name: 'same', update: true); - }); - - expect(subscriptions.length, 2); - }); - - baasTest('MutableSubscriptionSet.add multiple queries for same class', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - final random = Random.secure(); - - Uint8List randomBytes(int n) { - final Uint8List randomList = Uint8List(n); - for (int i = 0; i < randomList.length; i++) { - randomList[i] = random.nextInt(255); - } - return randomList; - } - - ObjectId newOid() => ObjectId.fromBytes(randomBytes(12)); - - final objectIds = {}; - const max = 1000; - subscriptions.update((mutableSubscriptions) { - objectIds.addAll([ - for (int i = 0; i < max; ++i) mutableSubscriptions.add(realm.query(r'_id == $0', [newOid()])).id - ]); - }); - expect(objectIds.length, max); // no collisions - expect(subscriptions.length, max); - - for (final sub in subscriptions) { - expect(sub.id, isIn(objectIds)); - } - }); - - baasTest('MutableSubscriptionSet.add same name, different classes', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - expect( - () => subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: 'same'); - mutableSubscriptions.add(realm.all(), name: 'same'); - }), - throws()); - }); - - baasTest('MutableSubscriptionSet.add same name, different classes, with update flag', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - late Subscription subscription; - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all(), name: 'same'); - subscription = mutableSubscriptions.add(realm.all(), name: 'same', update: true); - }); - - expect(subscriptions.length, 1); - expect(subscriptions[0], subscription); // last added wins - }); - - baasTest('MutableSubscriptionSet.add same query, different classes', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - mutableSubscriptions.add(realm.all()); - }); - - expect(subscriptions.length, 2); - for (final s in subscriptions) { - expect(s.queryString, contains('TRUEPREDICATE')); - } - }); - - baasTest('MutableSubscriptionSet.add illegal query', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - // Illegal query for subscription: - final query = realm.query('tasks.@count > 10 SORT(id ASC)'); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - - expect(() async => await subscriptions.waitForSynchronization(), throws("invalid RQL")); - }); - - baasTest('MutableSubscriptionSet.remove same query, different classes', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - late Subscription s; - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - s = mutableSubscriptions.add(realm.all()); - }); - - expect(subscriptions.length, 2); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByQuery(realm.all()); - }); - - expect(subscriptions, [s]); - }); - - baasTest('MutableSubscriptionSet.removeByType', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - late Subscription s; - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()])); - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()])); - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()])); - s = mutableSubscriptions.add(realm.all()); - }); - - expect(subscriptions.length, 4); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByType(); - }); - - expect(subscriptions, [s]); - }); - - baasTest('Get subscriptions', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - expect(subscriptions, isEmpty); - - final query = realm.all(); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query); - }); - - expect(subscriptions.length, 1); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByQuery(query); - }); - - expect(subscriptions, isEmpty); - - const name = 'a random name'; - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(query, name: name); - }); - - expect(subscriptions.findByName(name), isNotNull); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByName(name); - }); - - expect(subscriptions, isEmpty); - expect(realm.subscriptions.findByName(name), isNull); - - await subscriptions.waitForSynchronization(); - }); - - baasTest('Subscription properties roundtrip', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptions = realm.subscriptions; - - final before = DateTime.now().toUtc(); - - late ObjectId oid; - subscriptions.update((mutableSubscriptions) { - oid = mutableSubscriptions.add(realm.all(), name: 'foobar').id; - }); - - await subscriptions.waitForSynchronization(); - - final after = DateTime.now().toUtc(); - var s = subscriptions[0]; - - expect(s.id, oid); - expect(s.name, 'foobar'); - expect(s.objectClassName, 'Task'); - expect(s.queryString, contains('TRUEPREDICATE')); - expect(s.createdAt.isAfter(before), isTrue); - expect(s.createdAt.isBefore(after), isTrue); - expect(s.createdAt, s.updatedAt); - - subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'_id == $0', [ObjectId()]), name: 'foobar', update: true); - }); - - s = subscriptions[0]; // Needed in order to refresh properties! - expect(s.createdAt.isBefore(s.updatedAt), isTrue); - }); - - baasTest('flexible sync roundtrip', (appConfigurationX) async { - final appX = App(appConfigurationX); - - realmCore.clearCachedApps(); - final temporaryPath = await platformUtil.createTempPath(); - final appConfigurationY = AppConfiguration( - appConfigurationX.appId, - baseUrl: appConfigurationX.baseUrl, - baseFilePath: temporaryPath, - ); - final appY = App(appConfigurationY); - - final credentials = Credentials.anonymous(); - final userX = await appX.logIn(credentials); - final userY = await appY.logIn(credentials); - - final realmX = getRealm(Configuration.flexibleSync(userX, getSyncSchema())); - final objectId = ObjectId(); - - realmX.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realmX.query(r'_id == $0', [objectId])); - }); - await realmX.subscriptions.waitForSynchronization(); - realmX.write(() => realmX.add(Task(objectId))); - await realmX.syncSession.waitForUpload(); - - final realmY = getRealm(Configuration.flexibleSync(userY, getSyncSchema())); - realmY.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realmY.query(r'_id == $0', [objectId])); - }); - await realmY.subscriptions.waitForSynchronization(); - await realmY.syncSession.waitForDownload(); - final task = realmY.find(objectId); - expect(task, isNotNull); - }); - - baasTest('Writing before subscribe', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final config = Configuration.flexibleSync(user, getSyncSchema()); - - final realm = getRealm(config); - expect(() => realm.write(() => realm.add(Task(ObjectId()))), throws("no flexible sync subscription has been created")); - }); - - baasTest('Filter realm data using query subscription', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.all()); - }); - await realm.subscriptions.waitForSynchronization(); - - realm.write(() { - realm.addAll([ - Event(ObjectId(), name: "NPMG Event", isCompleted: true, durationInMinutes: 30), - Event(ObjectId(), name: "NPMG Meeting", isCompleted: false, durationInMinutes: 10), - Event(ObjectId(), name: "Some other event", isCompleted: true, durationInMinutes: 60), - ]); - }); - - await realm.syncSession.waitForUpload(); - - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.removeByQuery(realm.all()); - mutableSubscriptions.add(realm.query(r'name BEGINSWITH $0 AND isCompleted == $1 AND durationInMinutes > $2', ["NPMG", true, 20]), name: "filter"); - }); - - await realm.subscriptions.waitForSynchronization(); - await realm.syncSession.waitForDownload(); - - var filtered = realm.query(realm.subscriptions.findByName("filter")!.queryString); - var all = realm.all(); - expect(filtered, isNotEmpty); - expect(filtered.length, all.length); - }); - - baasTest('Subscriptions when realm is closed gets closed as well', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - - final subscriptions = realm.subscriptions; - expect(() => subscriptions.state, returnsNormally); - - realm.close(); - expect(() => subscriptions.state, throws()); - }); - - baasTest('SyncSessionErrorCode.compensatingWrite', (configuration) async { - late SyncError compensatingWriteError; - final productNamePrefix = generateRandomString(4); - final user = await getIntegrationUser(appConfig: configuration); - final config = Configuration.flexibleSync(user, getSyncSchema(), syncErrorHandler: (syncError) { - compensatingWriteError = syncError; - }); - final realm = getRealm(config); - final query = realm.query(r'name BEGINSWITH $0', [productNamePrefix]); - realm.subscriptions.update((mutableSubscriptions) => mutableSubscriptions.add(query)); - await realm.subscriptions.waitForSynchronization(); - - final productId = ObjectId(); - realm.write(() => realm.add(Product(productId, "doesn't match subscription"))); - await realm.syncSession.waitForUpload(); - - expect(compensatingWriteError, isA()); - final sessionError = compensatingWriteError as CompensatingWriteError; - expect(sessionError.message, startsWith('Client attempted a write that is not allowed')); - expect(sessionError.compensatingWrites, isNotNull); - final writeReason = sessionError.compensatingWrites!.first; - expect(writeReason, isNotNull); - expect(writeReason.objectType, "Product"); - expect(writeReason.reason, 'write to ObjectID("$productId") in table "${writeReason.objectType}" not allowed; object is outside of the current query view'); - expect(writeReason.primaryKey.value, productId); - }); - - baasTest('Flexible sync subscribe/unsubscribe API', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final prefix = generateRandomString(4); - final byTestRun = "name BEGINSWITH '$prefix'"; - final query = realm.query(byTestRun); - await query.subscribe(); - - // Write new data and upload - realm.write(() { - realm.addAll([ - Event(ObjectId(), name: "$prefix NPM Event", isCompleted: true, durationInMinutes: 30), - Event(ObjectId(), name: "$prefix NPM Meeting", isCompleted: false, durationInMinutes: 10), - Event(ObjectId(), name: "$prefix Some other event", isCompleted: true, durationInMinutes: 15), - ]); - }); - expect(query.length, 3); - await realm.syncSession.waitForUpload(); - - // Remove all the data from realm file after synchronization completes - realm.subscriptions.update((mutableSubscriptions) => mutableSubscriptions.clear()); - await realm.subscriptions.waitForSynchronization(); - expect(query.length, 0); - - // Subscribing will download only the objects with names containing 'NPM' - final subscribedByName = await realm.query('$byTestRun AND name CONTAINS \$0', ["NPM"]).subscribe(); - expect(subscribedByName.length, 2); - - // Adding subscription by duration on top of downloaded objects by name - // will remove the objects, which don't match duration < 20, from the local realm - final subscribedByNameAndDuration = await subscribedByName.query(r'durationInMinutes < $0', [20]).subscribe(); - expect(subscribedByNameAndDuration.length, 1); - expect(subscribedByNameAndDuration[0].durationInMinutes, 10); - expect(subscribedByNameAndDuration[0].name, contains("NPM")); - - // Query local realm by duration - final filteredByDuration = realm.query("$byTestRun AND durationInMinutes < \$0", [20]); - expect(filteredByDuration.length, 1); // duration 10 only, because there is subscription by name containing 'NPM' and duration < 20 - - // Subscribing only by duration will download all objects with duration < 20 independent on the name - final subscribedByDuration = await filteredByDuration.subscribe(); - expect(subscribedByDuration.length, 2); // duration 10 and 15, because all objects with durations < 20 are downloaded - }); - - test("Using flexible sync subscribe API for local realm throws", () async { - final config = Configuration.local([Event.schema]); - final realm = getRealm(config); - await expectLater( - () => realm.all().subscribe(), throws("subscriptions is only valid on Realms opened with a FlexibleSyncConfiguration")); - expect(() => realm.all().unsubscribe(), throws("unsubscribe is only allowed on Realms opened with a FlexibleSyncConfiguration")); - }); - - baasTest('Flexible sync subscribe API - duplicated subscription', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptionName1 = "sub1"; - final subscriptionName2 = "sub2"; - final query1 = realm.all(); - final query2 = realm.query("name = \$0", ["some name"]); - - await query1.subscribe(name: subscriptionName1); - expect(realm.subscriptions.version, 1); - expect(realm.subscriptions.length, 1); - - //Replace subscription with query2 using the same name and update flag - await query2.subscribe(name: subscriptionName1, update: true); - expect(realm.subscriptions.length, 1); - expect(realm.subscriptions.findByName(subscriptionName1), isNotNull); - - //Subscribe for the same query2 with different name - await query2.subscribe(name: subscriptionName2); - expect(realm.subscriptions.length, 2); - expect(realm.subscriptions.findByName(subscriptionName1), isNotNull); - expect(realm.subscriptions.findByName(subscriptionName2), isNotNull); - - //Add query subscription with the same name and update=false throws - await expectLater(() => query1.subscribe(name: subscriptionName2), throws("Duplicate subscription with name: $subscriptionName2")); - }); - - baasTest('Flexible sync subscribe/unsubscribe and removeAllUnnamed', (config) async { - final realm = await getIntegrationRealm(appConfig: config); - final subscriptionName1 = "sub1"; - final subscriptionName2 = "sub2"; - final query = realm.all(); - final queryFiltered = realm.query("name='x'"); - - final unnamedResults = await query.subscribe(); // +1 unnamed subscription - await query.subscribe(); // +0 subscription already exists - await realm.all().subscribe(); // +0 subscription already exists - await queryFiltered.subscribe(); // +1 unnamed subscription - final namedResults1 = await query.subscribe(name: subscriptionName1); // +1 named subscription - final namedResults2 = await query.subscribe(name: subscriptionName2); // +1 named subscription - expect(realm.subscriptions.length, 4); - - expect(query.unsubscribe(), isFalse); // -0 (query is not a subscription) - expect(realm.subscriptions.length, 4); - - expect(unnamedResults.unsubscribe(), isTrue); // -1 unnamed subscription on query - expect(realm.subscriptions.length, 3); - expect(realm.subscriptions.find(queryFiltered), isNotNull); - expect(realm.subscriptions.findByName(subscriptionName1), isNotNull); - expect(realm.subscriptions.findByName(subscriptionName2), isNotNull); - - realm.subscriptions.update((mutableSubscriptions) => mutableSubscriptions.clear(unnamedOnly: true)); // -1 unnamed subscription on queryFiltered - - expect(realm.subscriptions.length, 2); - expect(realm.subscriptions.findByName(subscriptionName1), isNotNull); - expect(realm.subscriptions.findByName(subscriptionName2), isNotNull); - - expect(namedResults1.unsubscribe(), isTrue); // -1 named subscription sub1 - expect(realm.subscriptions.length, 1); - expect(realm.subscriptions.findByName(subscriptionName2), isNotNull); - - expect(namedResults2.unsubscribe(), isTrue); // -1 named subscription - expect(realm.subscriptions.length, 0); - }); - - baasTest('Flexible sync subscribe/unsubscribe API wait for download', (configuration) async { - int count = 2; - RealmResults query = await _getQueryToSubscribeForDownload(configuration, count); - final results = await query.subscribe(waitForSyncMode: WaitForSyncMode.never); - expect(results.length, 0); // didn't wait for downloading because of WaitForSyncMode.never - - final second = await query.subscribe(waitForSyncMode: WaitForSyncMode.always); - expect(second.length, count); // product_1 and product_21 - }); - - baasTest('Flexible sync subscribe/unsubscribe cancellation token', (configuration) async { - RealmResults query = await _getQueryToSubscribeForDownload(configuration, 3); - - // Wait Always if timeout expired - final timeoutCancellationToken = TimeoutCancellationToken(Duration(microseconds: 0)); - await expectLater( - () async => await query.subscribe(waitForSyncMode: WaitForSyncMode.always, cancellationToken: timeoutCancellationToken), - throwsA(isA()), - ); - - // Wait Always but cancel berfore - final cancellationToken = CancellationToken(); - cancellationToken.cancel(); - await expectLater( - query.subscribe(waitForSyncMode: WaitForSyncMode.always, cancellationToken: cancellationToken), - throwsA(isA()), - ); - - // Wait Never but cancel before - final cancellationToken1 = CancellationToken(); - cancellationToken1.cancel(); - await expectLater( - query.subscribe(waitForSyncMode: WaitForSyncMode.never, cancellationToken: cancellationToken1), - throwsA(isA()), - ); - - // Wait Always but cancel after - final cancellationToken2 = CancellationToken(); - final subFuture = query.subscribe(waitForSyncMode: WaitForSyncMode.always, cancellationToken: cancellationToken2); - cancellationToken2.cancel(); - - expect( - () async => await subFuture, - throwsA(isA()), - ); - }); -} - -Future> _getQueryToSubscribeForDownload(AppConfiguration configuration, int takeCount) async { - final prefix = generateRandomString(4); - final byTestRun = "name BEGINSWITH '$prefix'"; - App app = App(configuration); - final userA = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final configA = Configuration.flexibleSync(userA, getSyncSchema()); - final realmA = getRealm(configA); - await realmA.query(byTestRun).subscribe(); - List names = []; - realmA.write(() { - for (var i = 0; i < 20; i++) { - final name = "${prefix}_${i + 1}"; - names.add(name); - realmA.add(Product(ObjectId(), name)); - } - }); - await realmA.syncSession.waitForUpload(); - realmA.close(); - - final userB = await app.logIn(Credentials.anonymous(reuseCredentials: false)); - final configB = Configuration.flexibleSync(userB, getSyncSchema()); - final realmB = getRealm(configB); - final query = realmB.query('$byTestRun AND name IN \$0', [names.take(takeCount)]); - - return query; -} diff --git a/packages/realm_dart/test/sync_migration_test.dart b/packages/realm_dart/test/sync_migration_test.dart deleted file mode 100644 index f8d6ed488..000000000 --- a/packages/realm_dart/test/sync_migration_test.dart +++ /dev/null @@ -1,266 +0,0 @@ -// Copyright 2024 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:typed_data'; - -import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/configuration.dart'; -import 'package:test/test.dart' hide test, throws; - -import 'test.dart'; - -part 'sync_migration_test.realm.dart'; - -// This has to match the server-side schema declared in baas_client::_nullablesSchemaV0 -@RealmModel() -@MapTo("Nullables") -class _NullablesV0 { - @PrimaryKey() - @MapTo('_id') - late ObjectId id; - - late ObjectId differentiator; - - late bool? boolValue; - late int? intValue; - late double? doubleValue; - late Decimal128? decimalValue; - late DateTime? dateValue; - late String? stringValue; - late ObjectId? objectIdValue; - late Uuid? uuidValue; - late Uint8List? binaryValue; -} - -// This has to match the server-side schema declared in baas_client::_nullablesSchemaV1 -@RealmModel() -@MapTo("Nullables") -class _NullablesV1 { - @PrimaryKey() - @MapTo('_id') - late ObjectId id; - - late ObjectId differentiator; - - late bool boolValue; - late int intValue; - late double doubleValue; - late Decimal128 decimalValue; - late DateTime dateValue; - late String stringValue; - late ObjectId objectIdValue; - late Uuid uuidValue; - late Uint8List binaryValue; - - late String willBeRemoved; -} - -Future openRealm(AppConfiguration appConfig, SchemaObject schema, ObjectId differentiator, {required int schemaVersion}) async { - final user = await getIntegrationUser(appConfig: appConfig); - final config = Configuration.flexibleSync(user, [schema], schemaVersion: schemaVersion)..sessionStopPolicy = SessionStopPolicy.immediately; - - final realm = await Realm.open(config); - - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.dynamic.all(schema.name).query('differentiator == \$0', [differentiator])); - }); - - await realm.subscriptions.waitForSynchronization(); - - return realm; -} - -void main() { - setupTests(); - - baasTest('Can migrate property optionality', (appConfig) async { - final differentiator = ObjectId(); - final oid = ObjectId(); - final uuid = Uuid.v4(); - final date = DateTime(1999, 12, 21, 4, 53, 17).toUtc(); - final binary = Uint8List.fromList([1, 2, 3]); - - final realmv0 = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 0); - final objv0 = realmv0.write(() { - return realmv0.add(NullablesV0(ObjectId(), differentiator, - boolValue: true, - dateValue: date, - decimalValue: Decimal128.fromDouble(123.456), - doubleValue: -123.987, - intValue: 42, - objectIdValue: oid, - stringValue: 'abc', - uuidValue: uuid, - binaryValue: binary)); - }); - - await realmv0.syncSession.waitForUpload(); - - final realmv1 = await openRealm(appConfig, NullablesV1.schema, differentiator, schemaVersion: 1); - - final objv1 = realmv1.all().single; - - expect(objv1.boolValue, true); - expect(objv1.dateValue, date); - expect(objv1.decimalValue, Decimal128.fromDouble(123.456)); - expect(objv1.doubleValue, -123.987); - expect(objv1.intValue, 42); - expect(objv1.objectIdValue, oid); - expect(objv1.stringValue, 'abc'); - expect(objv1.uuidValue, uuid); - expect(objv1.binaryValue, binary); - expect(objv1.willBeRemoved, ''); - - final realmv2 = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 2); - final objv2 = realmv2.all().single; - - expect(objv2.boolValue, true); - expect(objv2.dateValue, date); - expect(objv2.decimalValue, Decimal128.fromDouble(123.456)); - expect(objv2.doubleValue, -123.987); - expect(objv2.intValue, 42); - expect(objv2.objectIdValue, oid); - expect(objv2.stringValue, 'abc'); - expect(objv2.uuidValue, uuid); - expect(objv2.binaryValue, binary); - - realmv0.write(() { - objv0.boolValue = null; - objv0.dateValue = null; - objv0.decimalValue = null; - objv0.doubleValue = null; - objv0.intValue = null; - objv0.objectIdValue = null; - objv0.stringValue = null; - objv0.uuidValue = null; - objv0.binaryValue = null; - }); - - await realmv0.syncSession.waitForUpload(); - await realmv1.syncSession.waitForDownload(); - await realmv2.syncSession.waitForDownload(); - - expect(objv1.boolValue, false); - expect(objv1.dateValue, DateTime.utc(1)); - expect(objv1.decimalValue, Decimal128.fromDouble(0)); - expect(objv1.doubleValue, 0); - expect(objv1.intValue, 0); - expect(objv1.objectIdValue, ObjectId.fromBytes(List.generate(12, (index) => 0))); - expect(objv1.stringValue, ''); - expect(objv1.uuidValue, Uuid.nil); - expect(objv1.binaryValue, Uint8List(0)); - - expect(objv2.boolValue, isNull); - expect(objv2.dateValue, isNull); - expect(objv2.decimalValue, isNull); - expect(objv2.doubleValue, isNull); - expect(objv2.intValue, isNull); - expect(objv2.objectIdValue, isNull); - expect(objv2.stringValue, isNull); - expect(objv2.uuidValue, isNull); - expect(objv2.binaryValue, isNull); - }, appName: AppName.staticSchema, skip: true); - - baasTest('Can remove field', (appConfig) async { - final differentiator = ObjectId(); - final realmv1 = await openRealm(appConfig, NullablesV1.schema, differentiator, schemaVersion: 1); - final objv1 = realmv1.write(() { - return realmv1.add(NullablesV1( - ObjectId(), differentiator, true, 5, 1, Decimal128.infinity, DateTime.now(), 'foo', ObjectId(), Uuid.v4(), Uint8List(0), 'this should go away!')); - }); - - expect(objv1.willBeRemoved, 'this should go away!'); - await realmv1.syncSession.waitForUpload(); - - final realmv2 = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 2); - - final id2 = ObjectId(); - realmv2.write(() { - realmv2.add(NullablesV0(id2, differentiator)); - }); - - await realmv2.syncSession.waitForUpload(); - await realmv1.syncSession.waitForDownload(); - - final objv2 = realmv1.find(id2)!; - expect(objv2.willBeRemoved, ''); - }, appName: AppName.staticSchema); - - baasTest('Fails with a future schema version', (appConfig) { - expectLater( - () => openRealm(appConfig, NullablesV1.schema, ObjectId(), schemaVersion: 3), - throwsA(isA().having( - (e) => e.message, - 'message', - // Locally this seems to throw: 'Failed to open realm: Error details missing'. - // While on CI it throws: - // contains('Failed to open realm: Client provided invalid schema version: client presented schema version "3" is greater than latest schema version "2"') - contains('Failed to open realm')))); - }, appName: AppName.staticSchema); - - baasTest('Realm can be migrated through consequtive versions (0->1->2)', (appConfig) async { - final differentiator = ObjectId(); - var realm = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 0); - final id = ObjectId(); - realm.write(() { - realm.add(NullablesV0(id, differentiator)); - }); - - realm.close(); - - realm = await openRealm(appConfig, NullablesV1.schema, differentiator, schemaVersion: 1); - final objv1 = realm.all().first; - expect(objv1.id, id); - expect(objv1.differentiator, differentiator); - expect(objv1.boolValue, false); - expect(objv1.dateValue, DateTime.utc(1)); - expect(objv1.decimalValue, Decimal128.fromDouble(0)); - expect(objv1.doubleValue, 0); - expect(objv1.intValue, 0); - expect(objv1.objectIdValue, ObjectId.fromBytes(List.generate(12, (index) => 0))); - expect(objv1.stringValue, ''); - expect(objv1.uuidValue, Uuid.nil); - expect(objv1.binaryValue, Uint8List(0)); - - realm.close(); - - realm = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 2); - final objv2 = realm.all().first; - expect(objv2.id, id); - expect(objv2.differentiator, differentiator); - expect(objv2.boolValue, isNull); - expect(objv2.dateValue, isNull); - expect(objv2.decimalValue, isNull); - expect(objv2.doubleValue, isNull); - expect(objv2.intValue, isNull); - expect(objv2.objectIdValue, isNull); - expect(objv2.stringValue, isNull); - expect(objv2.uuidValue, isNull); - expect(objv2.binaryValue, isNull); - }, appName: AppName.staticSchema, skip:true); - - baasTest('Realm can be migrated skipping versions (0->2)', (appConfig) async { - final differentiator = ObjectId(); - var realm = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 0); - final id = ObjectId(); - realm.write(() { - realm.add(NullablesV0(id, differentiator)); - }); - - realm.close(); - - realm = await openRealm(appConfig, NullablesV0.schema, differentiator, schemaVersion: 2); - final objv2 = realm.all().first; - expect(objv2.id, id); - expect(objv2.differentiator, differentiator); - expect(objv2.boolValue, isNull); - expect(objv2.dateValue, isNull); - expect(objv2.decimalValue, isNull); - expect(objv2.doubleValue, isNull); - expect(objv2.intValue, isNull); - expect(objv2.objectIdValue, isNull); - expect(objv2.stringValue, isNull); - expect(objv2.uuidValue, isNull); - expect(objv2.binaryValue, isNull); - }, appName: AppName.staticSchema, skip: true); -} diff --git a/packages/realm_dart/test/sync_migration_test.realm.dart b/packages/realm_dart/test/sync_migration_test.realm.dart deleted file mode 100644 index 40e397929..000000000 --- a/packages/realm_dart/test/sync_migration_test.realm.dart +++ /dev/null @@ -1,384 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'sync_migration_test.dart'; - -// ************************************************************************** -// RealmObjectGenerator -// ************************************************************************** - -// ignore_for_file: type=lint -class NullablesV0 extends _NullablesV0 - with RealmEntity, RealmObjectBase, RealmObject { - NullablesV0( - ObjectId id, - ObjectId differentiator, { - bool? boolValue, - int? intValue, - double? doubleValue, - Decimal128? decimalValue, - DateTime? dateValue, - String? stringValue, - ObjectId? objectIdValue, - Uuid? uuidValue, - Uint8List? binaryValue, - }) { - RealmObjectBase.set(this, '_id', id); - RealmObjectBase.set(this, 'differentiator', differentiator); - RealmObjectBase.set(this, 'boolValue', boolValue); - RealmObjectBase.set(this, 'intValue', intValue); - RealmObjectBase.set(this, 'doubleValue', doubleValue); - RealmObjectBase.set(this, 'decimalValue', decimalValue); - RealmObjectBase.set(this, 'dateValue', dateValue); - RealmObjectBase.set(this, 'stringValue', stringValue); - RealmObjectBase.set(this, 'objectIdValue', objectIdValue); - RealmObjectBase.set(this, 'uuidValue', uuidValue); - RealmObjectBase.set(this, 'binaryValue', binaryValue); - } - - NullablesV0._(); - - @override - ObjectId get id => RealmObjectBase.get(this, '_id') as ObjectId; - @override - set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); - - @override - ObjectId get differentiator => - RealmObjectBase.get(this, 'differentiator') as ObjectId; - @override - set differentiator(ObjectId value) => - RealmObjectBase.set(this, 'differentiator', value); - - @override - bool? get boolValue => RealmObjectBase.get(this, 'boolValue') as bool?; - @override - set boolValue(bool? value) => RealmObjectBase.set(this, 'boolValue', value); - - @override - int? get intValue => RealmObjectBase.get(this, 'intValue') as int?; - @override - set intValue(int? value) => RealmObjectBase.set(this, 'intValue', value); - - @override - double? get doubleValue => - RealmObjectBase.get(this, 'doubleValue') as double?; - @override - set doubleValue(double? value) => - RealmObjectBase.set(this, 'doubleValue', value); - - @override - Decimal128? get decimalValue => - RealmObjectBase.get(this, 'decimalValue') as Decimal128?; - @override - set decimalValue(Decimal128? value) => - RealmObjectBase.set(this, 'decimalValue', value); - - @override - DateTime? get dateValue => - RealmObjectBase.get(this, 'dateValue') as DateTime?; - @override - set dateValue(DateTime? value) => - RealmObjectBase.set(this, 'dateValue', value); - - @override - String? get stringValue => - RealmObjectBase.get(this, 'stringValue') as String?; - @override - set stringValue(String? value) => - RealmObjectBase.set(this, 'stringValue', value); - - @override - ObjectId? get objectIdValue => - RealmObjectBase.get(this, 'objectIdValue') as ObjectId?; - @override - set objectIdValue(ObjectId? value) => - RealmObjectBase.set(this, 'objectIdValue', value); - - @override - Uuid? get uuidValue => RealmObjectBase.get(this, 'uuidValue') as Uuid?; - @override - set uuidValue(Uuid? value) => RealmObjectBase.set(this, 'uuidValue', value); - - @override - Uint8List? get binaryValue => - RealmObjectBase.get(this, 'binaryValue') as Uint8List?; - @override - set binaryValue(Uint8List? value) => - RealmObjectBase.set(this, 'binaryValue', value); - - @override - Stream> get changes => - RealmObjectBase.getChanges(this); - - @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); - - @override - NullablesV0 freeze() => RealmObjectBase.freezeObject(this); - - EJsonValue toEJson() { - return { - '_id': id.toEJson(), - 'differentiator': differentiator.toEJson(), - 'boolValue': boolValue.toEJson(), - 'intValue': intValue.toEJson(), - 'doubleValue': doubleValue.toEJson(), - 'decimalValue': decimalValue.toEJson(), - 'dateValue': dateValue.toEJson(), - 'stringValue': stringValue.toEJson(), - 'objectIdValue': objectIdValue.toEJson(), - 'uuidValue': uuidValue.toEJson(), - 'binaryValue': binaryValue.toEJson(), - }; - } - - static EJsonValue _toEJson(NullablesV0 value) => value.toEJson(); - static NullablesV0 _fromEJson(EJsonValue ejson) { - if (ejson is! Map) return raiseInvalidEJson(ejson); - return switch (ejson) { - { - '_id': EJsonValue id, - 'differentiator': EJsonValue differentiator, - } => - NullablesV0( - fromEJson(id), - fromEJson(differentiator), - boolValue: fromEJson(ejson['boolValue']), - intValue: fromEJson(ejson['intValue']), - doubleValue: fromEJson(ejson['doubleValue']), - decimalValue: fromEJson(ejson['decimalValue']), - dateValue: fromEJson(ejson['dateValue']), - stringValue: fromEJson(ejson['stringValue']), - objectIdValue: fromEJson(ejson['objectIdValue']), - uuidValue: fromEJson(ejson['uuidValue']), - binaryValue: fromEJson(ejson['binaryValue']), - ), - _ => raiseInvalidEJson(ejson), - }; - } - - static final schema = () { - RealmObjectBase.registerFactory(NullablesV0._); - register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, NullablesV0, 'Nullables', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('differentiator', RealmPropertyType.objectid), - SchemaProperty('boolValue', RealmPropertyType.bool, optional: true), - SchemaProperty('intValue', RealmPropertyType.int, optional: true), - SchemaProperty('doubleValue', RealmPropertyType.double, optional: true), - SchemaProperty('decimalValue', RealmPropertyType.decimal128, - optional: true), - SchemaProperty('dateValue', RealmPropertyType.timestamp, optional: true), - SchemaProperty('stringValue', RealmPropertyType.string, optional: true), - SchemaProperty('objectIdValue', RealmPropertyType.objectid, - optional: true), - SchemaProperty('uuidValue', RealmPropertyType.uuid, optional: true), - SchemaProperty('binaryValue', RealmPropertyType.binary, optional: true), - ]); - }(); - - @override - SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; -} - -class NullablesV1 extends _NullablesV1 - with RealmEntity, RealmObjectBase, RealmObject { - NullablesV1( - ObjectId id, - ObjectId differentiator, - bool boolValue, - int intValue, - double doubleValue, - Decimal128 decimalValue, - DateTime dateValue, - String stringValue, - ObjectId objectIdValue, - Uuid uuidValue, - Uint8List binaryValue, - String willBeRemoved, - ) { - RealmObjectBase.set(this, '_id', id); - RealmObjectBase.set(this, 'differentiator', differentiator); - RealmObjectBase.set(this, 'boolValue', boolValue); - RealmObjectBase.set(this, 'intValue', intValue); - RealmObjectBase.set(this, 'doubleValue', doubleValue); - RealmObjectBase.set(this, 'decimalValue', decimalValue); - RealmObjectBase.set(this, 'dateValue', dateValue); - RealmObjectBase.set(this, 'stringValue', stringValue); - RealmObjectBase.set(this, 'objectIdValue', objectIdValue); - RealmObjectBase.set(this, 'uuidValue', uuidValue); - RealmObjectBase.set(this, 'binaryValue', binaryValue); - RealmObjectBase.set(this, 'willBeRemoved', willBeRemoved); - } - - NullablesV1._(); - - @override - ObjectId get id => RealmObjectBase.get(this, '_id') as ObjectId; - @override - set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); - - @override - ObjectId get differentiator => - RealmObjectBase.get(this, 'differentiator') as ObjectId; - @override - set differentiator(ObjectId value) => - RealmObjectBase.set(this, 'differentiator', value); - - @override - bool get boolValue => RealmObjectBase.get(this, 'boolValue') as bool; - @override - set boolValue(bool value) => RealmObjectBase.set(this, 'boolValue', value); - - @override - int get intValue => RealmObjectBase.get(this, 'intValue') as int; - @override - set intValue(int value) => RealmObjectBase.set(this, 'intValue', value); - - @override - double get doubleValue => - RealmObjectBase.get(this, 'doubleValue') as double; - @override - set doubleValue(double value) => - RealmObjectBase.set(this, 'doubleValue', value); - - @override - Decimal128 get decimalValue => - RealmObjectBase.get(this, 'decimalValue') as Decimal128; - @override - set decimalValue(Decimal128 value) => - RealmObjectBase.set(this, 'decimalValue', value); - - @override - DateTime get dateValue => - RealmObjectBase.get(this, 'dateValue') as DateTime; - @override - set dateValue(DateTime value) => - RealmObjectBase.set(this, 'dateValue', value); - - @override - String get stringValue => - RealmObjectBase.get(this, 'stringValue') as String; - @override - set stringValue(String value) => - RealmObjectBase.set(this, 'stringValue', value); - - @override - ObjectId get objectIdValue => - RealmObjectBase.get(this, 'objectIdValue') as ObjectId; - @override - set objectIdValue(ObjectId value) => - RealmObjectBase.set(this, 'objectIdValue', value); - - @override - Uuid get uuidValue => RealmObjectBase.get(this, 'uuidValue') as Uuid; - @override - set uuidValue(Uuid value) => RealmObjectBase.set(this, 'uuidValue', value); - - @override - Uint8List get binaryValue => - RealmObjectBase.get(this, 'binaryValue') as Uint8List; - @override - set binaryValue(Uint8List value) => - RealmObjectBase.set(this, 'binaryValue', value); - - @override - String get willBeRemoved => - RealmObjectBase.get(this, 'willBeRemoved') as String; - @override - set willBeRemoved(String value) => - RealmObjectBase.set(this, 'willBeRemoved', value); - - @override - Stream> get changes => - RealmObjectBase.getChanges(this); - - @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); - - @override - NullablesV1 freeze() => RealmObjectBase.freezeObject(this); - - EJsonValue toEJson() { - return { - '_id': id.toEJson(), - 'differentiator': differentiator.toEJson(), - 'boolValue': boolValue.toEJson(), - 'intValue': intValue.toEJson(), - 'doubleValue': doubleValue.toEJson(), - 'decimalValue': decimalValue.toEJson(), - 'dateValue': dateValue.toEJson(), - 'stringValue': stringValue.toEJson(), - 'objectIdValue': objectIdValue.toEJson(), - 'uuidValue': uuidValue.toEJson(), - 'binaryValue': binaryValue.toEJson(), - 'willBeRemoved': willBeRemoved.toEJson(), - }; - } - - static EJsonValue _toEJson(NullablesV1 value) => value.toEJson(); - static NullablesV1 _fromEJson(EJsonValue ejson) { - if (ejson is! Map) return raiseInvalidEJson(ejson); - return switch (ejson) { - { - '_id': EJsonValue id, - 'differentiator': EJsonValue differentiator, - 'boolValue': EJsonValue boolValue, - 'intValue': EJsonValue intValue, - 'doubleValue': EJsonValue doubleValue, - 'decimalValue': EJsonValue decimalValue, - 'dateValue': EJsonValue dateValue, - 'stringValue': EJsonValue stringValue, - 'objectIdValue': EJsonValue objectIdValue, - 'uuidValue': EJsonValue uuidValue, - 'binaryValue': EJsonValue binaryValue, - 'willBeRemoved': EJsonValue willBeRemoved, - } => - NullablesV1( - fromEJson(id), - fromEJson(differentiator), - fromEJson(boolValue), - fromEJson(intValue), - fromEJson(doubleValue), - fromEJson(decimalValue), - fromEJson(dateValue), - fromEJson(stringValue), - fromEJson(objectIdValue), - fromEJson(uuidValue), - fromEJson(binaryValue), - fromEJson(willBeRemoved), - ), - _ => raiseInvalidEJson(ejson), - }; - } - - static final schema = () { - RealmObjectBase.registerFactory(NullablesV1._); - register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, NullablesV1, 'Nullables', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('differentiator', RealmPropertyType.objectid), - SchemaProperty('boolValue', RealmPropertyType.bool), - SchemaProperty('intValue', RealmPropertyType.int), - SchemaProperty('doubleValue', RealmPropertyType.double), - SchemaProperty('decimalValue', RealmPropertyType.decimal128), - SchemaProperty('dateValue', RealmPropertyType.timestamp), - SchemaProperty('stringValue', RealmPropertyType.string), - SchemaProperty('objectIdValue', RealmPropertyType.objectid), - SchemaProperty('uuidValue', RealmPropertyType.uuid), - SchemaProperty('binaryValue', RealmPropertyType.binary), - SchemaProperty('willBeRemoved', RealmPropertyType.string), - ]); - }(); - - @override - SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; -} diff --git a/packages/realm_dart/test/test.dart b/packages/realm_dart/test/test.dart index 624eac951..a6153fb4f 100644 --- a/packages/realm_dart/test/test.dart +++ b/packages/realm_dart/test/test.dart @@ -6,23 +6,18 @@ import 'dart:collection'; import 'dart:math'; import 'dart:typed_data'; -import 'package:meta/meta.dart'; import 'package:path/path.dart' as _path; import 'package:realm_dart/realm.dart'; -import 'package:realm_dart/src/configuration.dart'; import 'package:realm_dart/src/handles/realm_core.dart'; import 'package:realm_dart/src/logging.dart'; import 'package:realm_dart/src/realm_object.dart'; import 'package:test/test.dart'; import 'package:universal_platform/universal_platform.dart'; -import 'baas_helper.dart'; import 'utils/platform_util.dart'; export 'package:test/test.dart'; -export 'baas_helper.dart' show AppName; - part 'test.realm.dart'; typedef Platform = UniversalPlatform; @@ -358,16 +353,6 @@ class _ObjectWithDecimal { Decimal128? nullableDecimal; } -@RealmModel(ObjectType.asymmetricObject) -class _Asymmetric { - @PrimaryKey() - @MapTo('_id') - late ObjectId id; - - _Symmetric? symmetric; - late List<_Embedded> embeddedObjects; -} - @RealmModel(ObjectType.embeddedObject) class _Embedded { late int value; @@ -421,12 +406,8 @@ void xtest(String? name, dynamic Function() testFunction, {dynamic skip, Map(); paths.add(path); - realmCore.clearCachedApps(); - while (_openRealms.isNotEmpty) { final realm = _openRealms.removeFirst(); paths.add(realm.config.path); @@ -486,20 +465,13 @@ String generateRandomEmail({int length = 5}) { } Realm getRealm(Configuration config) { - if (config is FlexibleSyncConfiguration) { - config.sessionStopPolicy = SessionStopPolicy.immediately; - } - final realm = Realm(config); _openRealms.add(realm); return realm; } -Future getRealmAsync(Configuration config, {CancellationToken? cancellationToken, ProgressCallback? onProgressCallback}) async { - if (config is FlexibleSyncConfiguration) { - config.sessionStopPolicy = SessionStopPolicy.immediately; - } - final realm = await Realm.open(config, cancellationToken: cancellationToken, onProgressCallback: onProgressCallback); +Future getRealmAsync(Configuration config, {CancellationToken? cancellationToken}) async { + final realm = await Realm.open(config, cancellationToken: cancellationToken); _openRealms.add(realm); return realm; } @@ -573,90 +545,6 @@ Future tryDeleteRealm(String path) async { // throw Exception('Failed to delete realm at path $path. Did you forget to close it?'); } -@isTest -Future baasTest( - String name, - FutureOr Function(AppConfiguration appConfig) testFunction, { - AppName appName = AppName.flexible, - dynamic skip, -}) async { - BaasHelper.throwIfSetupFailed(); - - skip = shouldSkip(skip); - - test(name, () async { - baasHelper!.printSplunkLogLink(appName, baasHelper?.baseUrl); - final config = await baasHelper!.getAppConfig(appName: appName); - await testFunction(config); - }, skip: skip, tags: 'baas'); -} - -dynamic shouldSkip(dynamic skip) { - if (skip == null) { - skip = BaasHelper.shouldRunBaasTests ? false : "BAAS URL not present"; - } else if (skip is bool) { - if (!BaasHelper.shouldRunBaasTests) { - skip = "BAAS URL not present"; - } - } - return skip; -} - -String getAutoverifiedEmail() => 'realm_tests_do_autoverify_${generateRandomEmail()}'; - -/// Registers, logs in, and returns the new user. -Future getIntegrationUser({App? app, AppConfiguration? appConfig}) async { - app ??= App(appConfig ?? await baasHelper!.getAppConfig()); - final email = getAutoverifiedEmail(); - final password = 'password'; - await app.emailPasswordAuthProvider.registerUser(email, password); - - return await loginWithRetry(app, Credentials.emailPassword(email, password)); -} - -Future getAnonymousUser(App app) { - return app.logIn(Credentials.anonymous(reuseCredentials: false)); -} - -FlexibleSyncConfiguration getIntegrationConfig(User user) { - return Configuration.flexibleSync(user, getSyncSchema())..sessionStopPolicy = SessionStopPolicy.immediately; -} - -/// Returns a synced realm after logging in a user. -/// -/// A subscription for querying all [NullableTypes] objects containing -/// the `differentiator` will be added if a `differentiator` is provided. -Future getIntegrationRealm({App? app, ObjectId? differentiator, AppConfiguration? appConfig, bool waitForSync = true}) async { - app ??= App(appConfig ?? await baasHelper!.getAppConfig()); - final user = await getIntegrationUser(app: app, appConfig: appConfig); - - final config = getIntegrationConfig(user); - final realm = getRealm(config); - if (differentiator != null) { - realm.subscriptions.update((mutableSubscriptions) { - mutableSubscriptions.add(realm.query(r'differentiator = $0', [differentiator])); - }); - - if (waitForSync) { - await realm.subscriptions.waitForSynchronization(); - } - } - - return realm; -} - -Future loginWithRetry(App app, Credentials credentials, {int retryCount = 3}) async { - try { - return await app.logIn(credentials); - } catch (e) { - if (retryCount > 1) { - await Future.delayed(const Duration(milliseconds: 150)); - return await loginWithRetry(app, credentials, retryCount: retryCount - 1); - } - rethrow; - } -} - Future waitForCondition( FutureOr Function() condition, { Duration timeout = const Duration(seconds: 1), @@ -710,8 +598,6 @@ extension DateTimeTest on DateTime { } } -void clearCachedApps() => realmCore.clearCachedApps(); - extension StreamEx on Stream> { Stream switchLatest() async* { StreamSubscription? inner; @@ -726,46 +612,4 @@ extension StreamEx on Stream> { } } -/// Schema list for default app service -/// used for all the flexible sync tests. -/// The full list of schemas is required when creating -/// a flexibleSync configuration to the default app service -/// to avoid causing breaking changes in development mode. -List getSyncSchema() { - return [ - Task.schema, - Schedule.schema, - Product.schema, - Event.schema, - AllTypesEmbedded.schema, - ObjectWithEmbedded.schema, - RecursiveEmbedded1.schema, - RecursiveEmbedded2.schema, - RecursiveEmbedded3.schema, - NullableTypes.schema, - Asymmetric.schema, - Embedded.schema, - Symmetric.schema, - ObjectWithRealmValue.schema, - ObjectWithInt.schema, - ]; -} - -Future runWithRetries(FutureOr Function() tester, {int retryDelay = 100, int attempts = 100}) async { - var success = await tester(); - var timeout = retryDelay * attempts; - - while (!success && attempts > 0) { - await Future.delayed(Duration(milliseconds: retryDelay)); - success = await tester(); - attempts--; - } - - if (!success) { - throw TimeoutException('Failed to meet condition after $timeout ms.'); - } - - return success; -} - var copyFile = platformUtil.copy; // default, but allow integration_test to override diff --git a/packages/realm_dart/test/test.realm.dart b/packages/realm_dart/test/test.realm.dart index 4c71abe5c..c0cc28904 100644 --- a/packages/realm_dart/test/test.realm.dart +++ b/packages/realm_dart/test/test.realm.dart @@ -22,12 +22,10 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { set make(String value) => RealmObjectBase.set(this, 'make', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Car freeze() => RealmObjectBase.freezeObject(this); @@ -79,12 +77,10 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { set name(String value) => RealmObjectBase.set(this, 'name', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Person freeze() => RealmObjectBase.freezeObject(this); @@ -147,16 +143,13 @@ class Dog extends _Dog with RealmEntity, RealmObjectBase, RealmObject { @override Person? get owner => RealmObjectBase.get(this, 'owner') as Person?; @override - set owner(covariant Person? value) => - RealmObjectBase.set(this, 'owner', value); + set owner(covariant Person? value) => RealmObjectBase.set(this, 'owner', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Dog freeze() => RealmObjectBase.freezeObject(this); @@ -191,8 +184,7 @@ class Dog extends _Dog with RealmEntity, RealmObjectBase, RealmObject { return const SchemaObject(ObjectType.realmObject, Dog, 'Dog', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('age', RealmPropertyType.int, optional: true), - SchemaProperty('owner', RealmPropertyType.object, - optional: true, linkTarget: 'Person'), + SchemaProperty('owner', RealmPropertyType.object, optional: true, linkTarget: 'Person'), ]); }(); @@ -207,8 +199,7 @@ class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { Iterable scores = const [], }) { RealmObjectBase.set(this, 'name', name); - RealmObjectBase.set>( - this, 'players', RealmList(players)); + RealmObjectBase.set>(this, 'players', RealmList(players)); RealmObjectBase.set>(this, 'scores', RealmList(scores)); } @@ -220,26 +211,20 @@ class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { set name(String value) => RealmObjectBase.set(this, 'name', value); @override - RealmList get players => - RealmObjectBase.get(this, 'players') as RealmList; + RealmList get players => RealmObjectBase.get(this, 'players') as RealmList; @override - set players(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set players(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get scores => - RealmObjectBase.get(this, 'scores') as RealmList; + RealmList get scores => RealmObjectBase.get(this, 'scores') as RealmList; @override - set scores(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set scores(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Team freeze() => RealmObjectBase.freezeObject(this); @@ -273,10 +258,8 @@ class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Team, 'Team', [ SchemaProperty('name', RealmPropertyType.string), - SchemaProperty('players', RealmPropertyType.object, - linkTarget: 'Person', collectionType: RealmCollectionType.list), - SchemaProperty('scores', RealmPropertyType.int, - collectionType: RealmCollectionType.list), + SchemaProperty('players', RealmPropertyType.object, linkTarget: 'Person', collectionType: RealmCollectionType.list), + SchemaProperty('scores', RealmPropertyType.int, collectionType: RealmCollectionType.list), ]); }(); @@ -312,22 +295,18 @@ class Student extends _Student with RealmEntity, RealmObjectBase, RealmObject { @override int? get yearOfBirth => RealmObjectBase.get(this, 'yearOfBirth') as int?; @override - set yearOfBirth(int? value) => - RealmObjectBase.set(this, 'yearOfBirth', value); + set yearOfBirth(int? value) => RealmObjectBase.set(this, 'yearOfBirth', value); @override School? get school => RealmObjectBase.get(this, 'school') as School?; @override - set school(covariant School? value) => - RealmObjectBase.set(this, 'school', value); + set school(covariant School? value) => RealmObjectBase.set(this, 'school', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Student freeze() => RealmObjectBase.freezeObject(this); @@ -365,8 +344,7 @@ class Student extends _Student with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('number', RealmPropertyType.int, primaryKey: true), SchemaProperty('name', RealmPropertyType.string, optional: true), SchemaProperty('yearOfBirth', RealmPropertyType.int, optional: true), - SchemaProperty('school', RealmPropertyType.object, - optional: true, linkTarget: 'School'), + SchemaProperty('school', RealmPropertyType.object, optional: true, linkTarget: 'School'), ]); }(); @@ -384,11 +362,9 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { }) { RealmObjectBase.set(this, 'name', name); RealmObjectBase.set(this, 'city', city); - RealmObjectBase.set>( - this, 'students', RealmList(students)); + RealmObjectBase.set>(this, 'students', RealmList(students)); RealmObjectBase.set(this, 'branchOfSchool', branchOfSchool); - RealmObjectBase.set>( - this, 'branches', RealmList(branches)); + RealmObjectBase.set>(this, 'branches', RealmList(branches)); } School._(); @@ -404,33 +380,25 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { set city(String? value) => RealmObjectBase.set(this, 'city', value); @override - RealmList get students => - RealmObjectBase.get(this, 'students') as RealmList; + RealmList get students => RealmObjectBase.get(this, 'students') as RealmList; @override - set students(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set students(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - School? get branchOfSchool => - RealmObjectBase.get(this, 'branchOfSchool') as School?; + School? get branchOfSchool => RealmObjectBase.get(this, 'branchOfSchool') as School?; @override - set branchOfSchool(covariant School? value) => - RealmObjectBase.set(this, 'branchOfSchool', value); + set branchOfSchool(covariant School? value) => RealmObjectBase.set(this, 'branchOfSchool', value); @override - RealmList get branches => - RealmObjectBase.get(this, 'branches') as RealmList; + RealmList get branches => RealmObjectBase.get(this, 'branches') as RealmList; @override - set branches(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set branches(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override School freeze() => RealmObjectBase.freezeObject(this); @@ -469,12 +437,9 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { return const SchemaObject(ObjectType.realmObject, School, 'School', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('city', RealmPropertyType.string, optional: true), - SchemaProperty('students', RealmPropertyType.object, - linkTarget: 'Student', collectionType: RealmCollectionType.list), - SchemaProperty('branchOfSchool', RealmPropertyType.object, - optional: true, linkTarget: 'School'), - SchemaProperty('branches', RealmPropertyType.object, - linkTarget: 'School', collectionType: RealmCollectionType.list), + SchemaProperty('students', RealmPropertyType.object, linkTarget: 'Student', collectionType: RealmCollectionType.list), + SchemaProperty('branchOfSchool', RealmPropertyType.object, optional: true, linkTarget: 'School'), + SchemaProperty('branches', RealmPropertyType.object, linkTarget: 'School', collectionType: RealmCollectionType.list), ]); }(); @@ -482,42 +447,32 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class RemappedClass extends $RemappedClass - with RealmEntity, RealmObjectBase, RealmObject { +class RemappedClass extends $RemappedClass with RealmEntity, RealmObjectBase, RealmObject { RemappedClass( String remappedProperty, { Iterable listProperty = const [], }) { RealmObjectBase.set(this, 'primitive_property', remappedProperty); - RealmObjectBase.set>( - this, 'list-with-dashes', RealmList(listProperty)); + RealmObjectBase.set>(this, 'list-with-dashes', RealmList(listProperty)); } RemappedClass._(); @override - String get remappedProperty => - RealmObjectBase.get(this, 'primitive_property') as String; + String get remappedProperty => RealmObjectBase.get(this, 'primitive_property') as String; @override - set remappedProperty(String value) => - RealmObjectBase.set(this, 'primitive_property', value); + set remappedProperty(String value) => RealmObjectBase.set(this, 'primitive_property', value); @override - RealmList get listProperty => - RealmObjectBase.get(this, 'list-with-dashes') - as RealmList; + RealmList get listProperty => RealmObjectBase.get(this, 'list-with-dashes') as RealmList; @override - set listProperty(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set listProperty(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override RemappedClass freeze() => RealmObjectBase.freezeObject(this); @@ -547,14 +502,10 @@ class RemappedClass extends $RemappedClass static final schema = () { RealmObjectBase.registerFactory(RemappedClass._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, RemappedClass, 'myRemappedClass', [ - SchemaProperty('remappedProperty', RealmPropertyType.string, - mapTo: 'primitive_property'), + return const SchemaObject(ObjectType.realmObject, RemappedClass, 'myRemappedClass', [ + SchemaProperty('remappedProperty', RealmPropertyType.string, mapTo: 'primitive_property'), SchemaProperty('listProperty', RealmPropertyType.object, - mapTo: 'list-with-dashes', - linkTarget: 'myRemappedClass', - collectionType: RealmCollectionType.list), + mapTo: 'list-with-dashes', linkTarget: 'myRemappedClass', collectionType: RealmCollectionType.list), ]); }(); @@ -577,12 +528,10 @@ class Task extends _Task with RealmEntity, RealmObjectBase, RealmObject { set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Task freeze() => RealmObjectBase.freezeObject(this); @@ -611,8 +560,7 @@ class Task extends _Task with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.registerFactory(Task._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Task, 'Task', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), ]); }(); @@ -637,19 +585,15 @@ class Product extends _Product with RealmEntity, RealmObjectBase, RealmObject { set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - String get name => - RealmObjectBase.get(this, 'stringQueryField') as String; + String get name => RealmObjectBase.get(this, 'stringQueryField') as String; @override - set name(String value) => - RealmObjectBase.set(this, 'stringQueryField', value); + set name(String value) => RealmObjectBase.set(this, 'stringQueryField', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Product freeze() => RealmObjectBase.freezeObject(this); @@ -681,10 +625,8 @@ class Product extends _Product with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.registerFactory(Product._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Product, 'Product', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('name', RealmPropertyType.string, - mapTo: 'stringQueryField'), + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), + SchemaProperty('name', RealmPropertyType.string, mapTo: 'stringQueryField'), ]); }(); @@ -692,8 +634,7 @@ class Product extends _Product with RealmEntity, RealmObjectBase, RealmObject { SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class Schedule extends _Schedule - with RealmEntity, RealmObjectBase, RealmObject { +class Schedule extends _Schedule with RealmEntity, RealmObjectBase, RealmObject { Schedule( ObjectId id, { Iterable tasks = const [], @@ -710,19 +651,15 @@ class Schedule extends _Schedule set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - RealmList get tasks => - RealmObjectBase.get(this, 'tasks') as RealmList; + RealmList get tasks => RealmObjectBase.get(this, 'tasks') as RealmList; @override - set tasks(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set tasks(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Schedule freeze() => RealmObjectBase.freezeObject(this); @@ -753,10 +690,8 @@ class Schedule extends _Schedule RealmObjectBase.registerFactory(Schedule._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Schedule, 'Schedule', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('tasks', RealmPropertyType.object, - linkTarget: 'Task', collectionType: RealmCollectionType.list), + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), + SchemaProperty('tasks', RealmPropertyType.object, linkTarget: 'Task', collectionType: RealmCollectionType.list), ]); }(); @@ -776,26 +711,20 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { Foo._(); @override - Uint8List get requiredBinaryProp => - RealmObjectBase.get(this, 'requiredBinaryProp') as Uint8List; + Uint8List get requiredBinaryProp => RealmObjectBase.get(this, 'requiredBinaryProp') as Uint8List; @override - set requiredBinaryProp(Uint8List value) => - RealmObjectBase.set(this, 'requiredBinaryProp', value); + set requiredBinaryProp(Uint8List value) => RealmObjectBase.set(this, 'requiredBinaryProp', value); @override - Uint8List? get nullableBinaryProp => - RealmObjectBase.get(this, 'nullableBinaryProp') as Uint8List?; + Uint8List? get nullableBinaryProp => RealmObjectBase.get(this, 'nullableBinaryProp') as Uint8List?; @override - set nullableBinaryProp(Uint8List? value) => - RealmObjectBase.set(this, 'nullableBinaryProp', value); + set nullableBinaryProp(Uint8List? value) => RealmObjectBase.set(this, 'nullableBinaryProp', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Foo freeze() => RealmObjectBase.freezeObject(this); @@ -827,8 +756,7 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Foo, 'Foo', [ SchemaProperty('requiredBinaryProp', RealmPropertyType.binary), - SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, - optional: true), + SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, optional: true), ]); }(); @@ -836,8 +764,7 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class AllTypes extends _AllTypes - with RealmEntity, RealmObjectBase, RealmObject { +class AllTypes extends _AllTypes with RealmEntity, RealmObjectBase, RealmObject { AllTypes( String stringProp, bool boolProp, @@ -883,11 +810,9 @@ class AllTypes extends _AllTypes AllTypes._(); @override - String get stringProp => - RealmObjectBase.get(this, 'stringProp') as String; + String get stringProp => RealmObjectBase.get(this, 'stringProp') as String; @override - set stringProp(String value) => - RealmObjectBase.set(this, 'stringProp', value); + set stringProp(String value) => RealmObjectBase.set(this, 'stringProp', value); @override bool get boolProp => RealmObjectBase.get(this, 'boolProp') as bool; @@ -895,24 +820,19 @@ class AllTypes extends _AllTypes set boolProp(bool value) => RealmObjectBase.set(this, 'boolProp', value); @override - DateTime get dateProp => - RealmObjectBase.get(this, 'dateProp') as DateTime; + DateTime get dateProp => RealmObjectBase.get(this, 'dateProp') as DateTime; @override set dateProp(DateTime value) => RealmObjectBase.set(this, 'dateProp', value); @override - double get doubleProp => - RealmObjectBase.get(this, 'doubleProp') as double; + double get doubleProp => RealmObjectBase.get(this, 'doubleProp') as double; @override - set doubleProp(double value) => - RealmObjectBase.set(this, 'doubleProp', value); + set doubleProp(double value) => RealmObjectBase.set(this, 'doubleProp', value); @override - ObjectId get objectIdProp => - RealmObjectBase.get(this, 'objectIdProp') as ObjectId; + ObjectId get objectIdProp => RealmObjectBase.get(this, 'objectIdProp') as ObjectId; @override - set objectIdProp(ObjectId value) => - RealmObjectBase.set(this, 'objectIdProp', value); + set objectIdProp(ObjectId value) => RealmObjectBase.set(this, 'objectIdProp', value); @override Uuid get uuidProp => RealmObjectBase.get(this, 'uuidProp') as Uuid; @@ -925,97 +845,70 @@ class AllTypes extends _AllTypes set intProp(int value) => RealmObjectBase.set(this, 'intProp', value); @override - Decimal128 get decimalProp => - RealmObjectBase.get(this, 'decimalProp') as Decimal128; + Decimal128 get decimalProp => RealmObjectBase.get(this, 'decimalProp') as Decimal128; @override - set decimalProp(Decimal128 value) => - RealmObjectBase.set(this, 'decimalProp', value); + set decimalProp(Decimal128 value) => RealmObjectBase.set(this, 'decimalProp', value); @override - Uint8List get binaryProp => - RealmObjectBase.get(this, 'binaryProp') as Uint8List; + Uint8List get binaryProp => RealmObjectBase.get(this, 'binaryProp') as Uint8List; @override - set binaryProp(Uint8List value) => - RealmObjectBase.set(this, 'binaryProp', value); + set binaryProp(Uint8List value) => RealmObjectBase.set(this, 'binaryProp', value); @override - String? get nullableStringProp => - RealmObjectBase.get(this, 'nullableStringProp') as String?; + String? get nullableStringProp => RealmObjectBase.get(this, 'nullableStringProp') as String?; @override - set nullableStringProp(String? value) => - RealmObjectBase.set(this, 'nullableStringProp', value); + set nullableStringProp(String? value) => RealmObjectBase.set(this, 'nullableStringProp', value); @override - bool? get nullableBoolProp => - RealmObjectBase.get(this, 'nullableBoolProp') as bool?; + bool? get nullableBoolProp => RealmObjectBase.get(this, 'nullableBoolProp') as bool?; @override - set nullableBoolProp(bool? value) => - RealmObjectBase.set(this, 'nullableBoolProp', value); + set nullableBoolProp(bool? value) => RealmObjectBase.set(this, 'nullableBoolProp', value); @override - DateTime? get nullableDateProp => - RealmObjectBase.get(this, 'nullableDateProp') as DateTime?; + DateTime? get nullableDateProp => RealmObjectBase.get(this, 'nullableDateProp') as DateTime?; @override - set nullableDateProp(DateTime? value) => - RealmObjectBase.set(this, 'nullableDateProp', value); + set nullableDateProp(DateTime? value) => RealmObjectBase.set(this, 'nullableDateProp', value); @override - double? get nullableDoubleProp => - RealmObjectBase.get(this, 'nullableDoubleProp') as double?; + double? get nullableDoubleProp => RealmObjectBase.get(this, 'nullableDoubleProp') as double?; @override - set nullableDoubleProp(double? value) => - RealmObjectBase.set(this, 'nullableDoubleProp', value); + set nullableDoubleProp(double? value) => RealmObjectBase.set(this, 'nullableDoubleProp', value); @override - ObjectId? get nullableObjectIdProp => - RealmObjectBase.get(this, 'nullableObjectIdProp') as ObjectId?; + ObjectId? get nullableObjectIdProp => RealmObjectBase.get(this, 'nullableObjectIdProp') as ObjectId?; @override - set nullableObjectIdProp(ObjectId? value) => - RealmObjectBase.set(this, 'nullableObjectIdProp', value); + set nullableObjectIdProp(ObjectId? value) => RealmObjectBase.set(this, 'nullableObjectIdProp', value); @override - Uuid? get nullableUuidProp => - RealmObjectBase.get(this, 'nullableUuidProp') as Uuid?; + Uuid? get nullableUuidProp => RealmObjectBase.get(this, 'nullableUuidProp') as Uuid?; @override - set nullableUuidProp(Uuid? value) => - RealmObjectBase.set(this, 'nullableUuidProp', value); + set nullableUuidProp(Uuid? value) => RealmObjectBase.set(this, 'nullableUuidProp', value); @override - int? get nullableIntProp => - RealmObjectBase.get(this, 'nullableIntProp') as int?; + int? get nullableIntProp => RealmObjectBase.get(this, 'nullableIntProp') as int?; @override - set nullableIntProp(int? value) => - RealmObjectBase.set(this, 'nullableIntProp', value); + set nullableIntProp(int? value) => RealmObjectBase.set(this, 'nullableIntProp', value); @override - Decimal128? get nullableDecimalProp => - RealmObjectBase.get(this, 'nullableDecimalProp') - as Decimal128?; + Decimal128? get nullableDecimalProp => RealmObjectBase.get(this, 'nullableDecimalProp') as Decimal128?; @override - set nullableDecimalProp(Decimal128? value) => - RealmObjectBase.set(this, 'nullableDecimalProp', value); + set nullableDecimalProp(Decimal128? value) => RealmObjectBase.set(this, 'nullableDecimalProp', value); @override - Uint8List? get nullableBinaryProp => - RealmObjectBase.get(this, 'nullableBinaryProp') as Uint8List?; + Uint8List? get nullableBinaryProp => RealmObjectBase.get(this, 'nullableBinaryProp') as Uint8List?; @override - set nullableBinaryProp(Uint8List? value) => - RealmObjectBase.set(this, 'nullableBinaryProp', value); + set nullableBinaryProp(Uint8List? value) => RealmObjectBase.set(this, 'nullableBinaryProp', value); @override - RealmValue get realmValueProp => - RealmObjectBase.get(this, 'realmValueProp') as RealmValue; + RealmValue get realmValueProp => RealmObjectBase.get(this, 'realmValueProp') as RealmValue; @override - set realmValueProp(RealmValue value) => - RealmObjectBase.set(this, 'realmValueProp', value); + set realmValueProp(RealmValue value) => RealmObjectBase.set(this, 'realmValueProp', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override AllTypes freeze() => RealmObjectBase.freezeObject(this); @@ -1097,23 +990,15 @@ class AllTypes extends _AllTypes SchemaProperty('intProp', RealmPropertyType.int), SchemaProperty('decimalProp', RealmPropertyType.decimal128), SchemaProperty('binaryProp', RealmPropertyType.binary), - SchemaProperty('nullableStringProp', RealmPropertyType.string, - optional: true), - SchemaProperty('nullableBoolProp', RealmPropertyType.bool, - optional: true), - SchemaProperty('nullableDateProp', RealmPropertyType.timestamp, - optional: true), - SchemaProperty('nullableDoubleProp', RealmPropertyType.double, - optional: true), - SchemaProperty('nullableObjectIdProp', RealmPropertyType.objectid, - optional: true), - SchemaProperty('nullableUuidProp', RealmPropertyType.uuid, - optional: true), + SchemaProperty('nullableStringProp', RealmPropertyType.string, optional: true), + SchemaProperty('nullableBoolProp', RealmPropertyType.bool, optional: true), + SchemaProperty('nullableDateProp', RealmPropertyType.timestamp, optional: true), + SchemaProperty('nullableDoubleProp', RealmPropertyType.double, optional: true), + SchemaProperty('nullableObjectIdProp', RealmPropertyType.objectid, optional: true), + SchemaProperty('nullableUuidProp', RealmPropertyType.uuid, optional: true), SchemaProperty('nullableIntProp', RealmPropertyType.int, optional: true), - SchemaProperty('nullableDecimalProp', RealmPropertyType.decimal128, - optional: true), - SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, - optional: true), + SchemaProperty('nullableDecimalProp', RealmPropertyType.decimal128, optional: true), + SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, optional: true), SchemaProperty('realmValueProp', RealmPropertyType.mixed, optional: true), ]); }(); @@ -1122,8 +1007,7 @@ class AllTypes extends _AllTypes SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class LinksClass extends _LinksClass - with RealmEntity, RealmObjectBase, RealmObject { +class LinksClass extends _LinksClass with RealmEntity, RealmObjectBase, RealmObject { LinksClass( Uuid id, { LinksClass? link, @@ -1133,12 +1017,9 @@ class LinksClass extends _LinksClass }) { RealmObjectBase.set(this, 'id', id); RealmObjectBase.set(this, 'link', link); - RealmObjectBase.set>( - this, 'list', RealmList(list)); - RealmObjectBase.set>( - this, 'linksSet', RealmSet(linksSet)); - RealmObjectBase.set>( - this, 'map', RealmMap(map)); + RealmObjectBase.set>(this, 'list', RealmList(list)); + RealmObjectBase.set>(this, 'linksSet', RealmSet(linksSet)); + RealmObjectBase.set>(this, 'map', RealmMap(map)); } LinksClass._(); @@ -1149,40 +1030,30 @@ class LinksClass extends _LinksClass set id(Uuid value) => RealmObjectBase.set(this, 'id', value); @override - LinksClass? get link => - RealmObjectBase.get(this, 'link') as LinksClass?; + LinksClass? get link => RealmObjectBase.get(this, 'link') as LinksClass?; @override - set link(covariant LinksClass? value) => - RealmObjectBase.set(this, 'link', value); + set link(covariant LinksClass? value) => RealmObjectBase.set(this, 'link', value); @override - RealmList get list => - RealmObjectBase.get(this, 'list') as RealmList; + RealmList get list => RealmObjectBase.get(this, 'list') as RealmList; @override - set list(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set list(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmSet get linksSet => - RealmObjectBase.get(this, 'linksSet') as RealmSet; + RealmSet get linksSet => RealmObjectBase.get(this, 'linksSet') as RealmSet; @override - set linksSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set linksSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmMap get map => - RealmObjectBase.get(this, 'map') as RealmMap; + RealmMap get map => RealmObjectBase.get(this, 'map') as RealmMap; @override - set map(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set map(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override LinksClass freeze() => RealmObjectBase.freezeObject(this); @@ -1218,19 +1089,12 @@ class LinksClass extends _LinksClass static final schema = () { RealmObjectBase.registerFactory(LinksClass._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, LinksClass, 'LinksClass', [ + return const SchemaObject(ObjectType.realmObject, LinksClass, 'LinksClass', [ SchemaProperty('id', RealmPropertyType.uuid, primaryKey: true), - SchemaProperty('link', RealmPropertyType.object, - optional: true, linkTarget: 'LinksClass'), - SchemaProperty('list', RealmPropertyType.object, - linkTarget: 'LinksClass', collectionType: RealmCollectionType.list), - SchemaProperty('linksSet', RealmPropertyType.object, - linkTarget: 'LinksClass', collectionType: RealmCollectionType.set), - SchemaProperty('map', RealmPropertyType.object, - optional: true, - linkTarget: 'LinksClass', - collectionType: RealmCollectionType.map), + SchemaProperty('link', RealmPropertyType.object, optional: true, linkTarget: 'LinksClass'), + SchemaProperty('list', RealmPropertyType.object, linkTarget: 'LinksClass', collectionType: RealmCollectionType.list), + SchemaProperty('linksSet', RealmPropertyType.object, linkTarget: 'LinksClass', collectionType: RealmCollectionType.set), + SchemaProperty('map', RealmPropertyType.object, optional: true, linkTarget: 'LinksClass', collectionType: RealmCollectionType.map), ]); }(); @@ -1238,8 +1102,7 @@ class LinksClass extends _LinksClass SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class AllCollections extends _AllCollections - with RealmEntity, RealmObjectBase, RealmObject { +class AllCollections extends _AllCollections with RealmEntity, RealmObjectBase, RealmObject { AllCollections({ Iterable stringList = const [], Iterable boolList = const [], @@ -1290,465 +1153,303 @@ class AllCollections extends _AllCollections Map nullableIntMap = const {}, Map nullableDecimalMap = const {}, }) { - RealmObjectBase.set>( - this, 'stringList', RealmList(stringList)); - RealmObjectBase.set>( - this, 'boolList', RealmList(boolList)); - RealmObjectBase.set>( - this, 'dateList', RealmList(dateList)); - RealmObjectBase.set>( - this, 'doubleList', RealmList(doubleList)); - RealmObjectBase.set>( - this, 'objectIdList', RealmList(objectIdList)); - RealmObjectBase.set>( - this, 'uuidList', RealmList(uuidList)); - RealmObjectBase.set>( - this, 'intList', RealmList(intList)); - RealmObjectBase.set>( - this, 'decimalList', RealmList(decimalList)); - RealmObjectBase.set>( - this, 'nullableStringList', RealmList(nullableStringList)); - RealmObjectBase.set>( - this, 'nullableBoolList', RealmList(nullableBoolList)); - RealmObjectBase.set>( - this, 'nullableDateList', RealmList(nullableDateList)); - RealmObjectBase.set>( - this, 'nullableDoubleList', RealmList(nullableDoubleList)); - RealmObjectBase.set>(this, 'nullableObjectIdList', - RealmList(nullableObjectIdList)); - RealmObjectBase.set>( - this, 'nullableUuidList', RealmList(nullableUuidList)); - RealmObjectBase.set>( - this, 'nullableIntList', RealmList(nullableIntList)); - RealmObjectBase.set>(this, 'nullableDecimalList', - RealmList(nullableDecimalList)); - RealmObjectBase.set>( - this, 'stringSet', RealmSet(stringSet)); - RealmObjectBase.set>( - this, 'boolSet', RealmSet(boolSet)); - RealmObjectBase.set>( - this, 'dateSet', RealmSet(dateSet)); - RealmObjectBase.set>( - this, 'doubleSet', RealmSet(doubleSet)); - RealmObjectBase.set>( - this, 'objectIdSet', RealmSet(objectIdSet)); - RealmObjectBase.set>( - this, 'uuidSet', RealmSet(uuidSet)); + RealmObjectBase.set>(this, 'stringList', RealmList(stringList)); + RealmObjectBase.set>(this, 'boolList', RealmList(boolList)); + RealmObjectBase.set>(this, 'dateList', RealmList(dateList)); + RealmObjectBase.set>(this, 'doubleList', RealmList(doubleList)); + RealmObjectBase.set>(this, 'objectIdList', RealmList(objectIdList)); + RealmObjectBase.set>(this, 'uuidList', RealmList(uuidList)); + RealmObjectBase.set>(this, 'intList', RealmList(intList)); + RealmObjectBase.set>(this, 'decimalList', RealmList(decimalList)); + RealmObjectBase.set>(this, 'nullableStringList', RealmList(nullableStringList)); + RealmObjectBase.set>(this, 'nullableBoolList', RealmList(nullableBoolList)); + RealmObjectBase.set>(this, 'nullableDateList', RealmList(nullableDateList)); + RealmObjectBase.set>(this, 'nullableDoubleList', RealmList(nullableDoubleList)); + RealmObjectBase.set>(this, 'nullableObjectIdList', RealmList(nullableObjectIdList)); + RealmObjectBase.set>(this, 'nullableUuidList', RealmList(nullableUuidList)); + RealmObjectBase.set>(this, 'nullableIntList', RealmList(nullableIntList)); + RealmObjectBase.set>(this, 'nullableDecimalList', RealmList(nullableDecimalList)); + RealmObjectBase.set>(this, 'stringSet', RealmSet(stringSet)); + RealmObjectBase.set>(this, 'boolSet', RealmSet(boolSet)); + RealmObjectBase.set>(this, 'dateSet', RealmSet(dateSet)); + RealmObjectBase.set>(this, 'doubleSet', RealmSet(doubleSet)); + RealmObjectBase.set>(this, 'objectIdSet', RealmSet(objectIdSet)); + RealmObjectBase.set>(this, 'uuidSet', RealmSet(uuidSet)); RealmObjectBase.set>(this, 'intSet', RealmSet(intSet)); - RealmObjectBase.set>( - this, 'decimalSet', RealmSet(decimalSet)); - RealmObjectBase.set>( - this, 'nullableStringSet', RealmSet(nullableStringSet)); - RealmObjectBase.set>( - this, 'nullableBoolSet', RealmSet(nullableBoolSet)); - RealmObjectBase.set>( - this, 'nullableDateSet', RealmSet(nullableDateSet)); - RealmObjectBase.set>( - this, 'nullableDoubleSet', RealmSet(nullableDoubleSet)); - RealmObjectBase.set>( - this, 'nullableObjectIdSet', RealmSet(nullableObjectIdSet)); - RealmObjectBase.set>( - this, 'nullableUuidSet', RealmSet(nullableUuidSet)); - RealmObjectBase.set>( - this, 'nullableIntSet', RealmSet(nullableIntSet)); - RealmObjectBase.set>( - this, 'nullableDecimalSet', RealmSet(nullableDecimalSet)); - RealmObjectBase.set>( - this, 'stringMap', RealmMap(stringMap)); - RealmObjectBase.set>( - this, 'boolMap', RealmMap(boolMap)); - RealmObjectBase.set>( - this, 'dateMap', RealmMap(dateMap)); - RealmObjectBase.set>( - this, 'doubleMap', RealmMap(doubleMap)); - RealmObjectBase.set>( - this, 'objectIdMap', RealmMap(objectIdMap)); - RealmObjectBase.set>( - this, 'uuidMap', RealmMap(uuidMap)); + RealmObjectBase.set>(this, 'decimalSet', RealmSet(decimalSet)); + RealmObjectBase.set>(this, 'nullableStringSet', RealmSet(nullableStringSet)); + RealmObjectBase.set>(this, 'nullableBoolSet', RealmSet(nullableBoolSet)); + RealmObjectBase.set>(this, 'nullableDateSet', RealmSet(nullableDateSet)); + RealmObjectBase.set>(this, 'nullableDoubleSet', RealmSet(nullableDoubleSet)); + RealmObjectBase.set>(this, 'nullableObjectIdSet', RealmSet(nullableObjectIdSet)); + RealmObjectBase.set>(this, 'nullableUuidSet', RealmSet(nullableUuidSet)); + RealmObjectBase.set>(this, 'nullableIntSet', RealmSet(nullableIntSet)); + RealmObjectBase.set>(this, 'nullableDecimalSet', RealmSet(nullableDecimalSet)); + RealmObjectBase.set>(this, 'stringMap', RealmMap(stringMap)); + RealmObjectBase.set>(this, 'boolMap', RealmMap(boolMap)); + RealmObjectBase.set>(this, 'dateMap', RealmMap(dateMap)); + RealmObjectBase.set>(this, 'doubleMap', RealmMap(doubleMap)); + RealmObjectBase.set>(this, 'objectIdMap', RealmMap(objectIdMap)); + RealmObjectBase.set>(this, 'uuidMap', RealmMap(uuidMap)); RealmObjectBase.set>(this, 'intMap', RealmMap(intMap)); - RealmObjectBase.set>( - this, 'decimalMap', RealmMap(decimalMap)); - RealmObjectBase.set>( - this, 'nullableStringMap', RealmMap(nullableStringMap)); - RealmObjectBase.set>( - this, 'nullableBoolMap', RealmMap(nullableBoolMap)); - RealmObjectBase.set>( - this, 'nullableDateMap', RealmMap(nullableDateMap)); - RealmObjectBase.set>( - this, 'nullableDoubleMap', RealmMap(nullableDoubleMap)); - RealmObjectBase.set>( - this, 'nullableObjectIdMap', RealmMap(nullableObjectIdMap)); - RealmObjectBase.set>( - this, 'nullableUuidMap', RealmMap(nullableUuidMap)); - RealmObjectBase.set>( - this, 'nullableIntMap', RealmMap(nullableIntMap)); - RealmObjectBase.set>( - this, 'nullableDecimalMap', RealmMap(nullableDecimalMap)); + RealmObjectBase.set>(this, 'decimalMap', RealmMap(decimalMap)); + RealmObjectBase.set>(this, 'nullableStringMap', RealmMap(nullableStringMap)); + RealmObjectBase.set>(this, 'nullableBoolMap', RealmMap(nullableBoolMap)); + RealmObjectBase.set>(this, 'nullableDateMap', RealmMap(nullableDateMap)); + RealmObjectBase.set>(this, 'nullableDoubleMap', RealmMap(nullableDoubleMap)); + RealmObjectBase.set>(this, 'nullableObjectIdMap', RealmMap(nullableObjectIdMap)); + RealmObjectBase.set>(this, 'nullableUuidMap', RealmMap(nullableUuidMap)); + RealmObjectBase.set>(this, 'nullableIntMap', RealmMap(nullableIntMap)); + RealmObjectBase.set>(this, 'nullableDecimalMap', RealmMap(nullableDecimalMap)); } AllCollections._(); @override - RealmList get stringList => - RealmObjectBase.get(this, 'stringList') as RealmList; + RealmList get stringList => RealmObjectBase.get(this, 'stringList') as RealmList; @override - set stringList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set stringList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get boolList => - RealmObjectBase.get(this, 'boolList') as RealmList; + RealmList get boolList => RealmObjectBase.get(this, 'boolList') as RealmList; @override - set boolList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set boolList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get dateList => - RealmObjectBase.get(this, 'dateList') as RealmList; + RealmList get dateList => RealmObjectBase.get(this, 'dateList') as RealmList; @override - set dateList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set dateList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get doubleList => - RealmObjectBase.get(this, 'doubleList') as RealmList; + RealmList get doubleList => RealmObjectBase.get(this, 'doubleList') as RealmList; @override - set doubleList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set doubleList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get objectIdList => - RealmObjectBase.get(this, 'objectIdList') - as RealmList; + RealmList get objectIdList => RealmObjectBase.get(this, 'objectIdList') as RealmList; @override - set objectIdList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set objectIdList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get uuidList => - RealmObjectBase.get(this, 'uuidList') as RealmList; + RealmList get uuidList => RealmObjectBase.get(this, 'uuidList') as RealmList; @override - set uuidList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set uuidList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get intList => - RealmObjectBase.get(this, 'intList') as RealmList; + RealmList get intList => RealmObjectBase.get(this, 'intList') as RealmList; @override - set intList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set intList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get decimalList => - RealmObjectBase.get(this, 'decimalList') - as RealmList; + RealmList get decimalList => RealmObjectBase.get(this, 'decimalList') as RealmList; @override - set decimalList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set decimalList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableStringList => - RealmObjectBase.get(this, 'nullableStringList') - as RealmList; + RealmList get nullableStringList => RealmObjectBase.get(this, 'nullableStringList') as RealmList; @override - set nullableStringList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableStringList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableBoolList => - RealmObjectBase.get(this, 'nullableBoolList') as RealmList; + RealmList get nullableBoolList => RealmObjectBase.get(this, 'nullableBoolList') as RealmList; @override - set nullableBoolList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableBoolList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableDateList => - RealmObjectBase.get(this, 'nullableDateList') - as RealmList; + RealmList get nullableDateList => RealmObjectBase.get(this, 'nullableDateList') as RealmList; @override - set nullableDateList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableDateList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableDoubleList => - RealmObjectBase.get(this, 'nullableDoubleList') - as RealmList; + RealmList get nullableDoubleList => RealmObjectBase.get(this, 'nullableDoubleList') as RealmList; @override - set nullableDoubleList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableDoubleList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableObjectIdList => - RealmObjectBase.get(this, 'nullableObjectIdList') - as RealmList; + RealmList get nullableObjectIdList => RealmObjectBase.get(this, 'nullableObjectIdList') as RealmList; @override - set nullableObjectIdList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableObjectIdList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableUuidList => - RealmObjectBase.get(this, 'nullableUuidList') as RealmList; + RealmList get nullableUuidList => RealmObjectBase.get(this, 'nullableUuidList') as RealmList; @override - set nullableUuidList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableUuidList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableIntList => - RealmObjectBase.get(this, 'nullableIntList') as RealmList; + RealmList get nullableIntList => RealmObjectBase.get(this, 'nullableIntList') as RealmList; @override - set nullableIntList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableIntList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get nullableDecimalList => - RealmObjectBase.get(this, 'nullableDecimalList') - as RealmList; + RealmList get nullableDecimalList => RealmObjectBase.get(this, 'nullableDecimalList') as RealmList; @override - set nullableDecimalList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set nullableDecimalList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmSet get stringSet => - RealmObjectBase.get(this, 'stringSet') as RealmSet; + RealmSet get stringSet => RealmObjectBase.get(this, 'stringSet') as RealmSet; @override - set stringSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set stringSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get boolSet => - RealmObjectBase.get(this, 'boolSet') as RealmSet; + RealmSet get boolSet => RealmObjectBase.get(this, 'boolSet') as RealmSet; @override - set boolSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set boolSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get dateSet => - RealmObjectBase.get(this, 'dateSet') as RealmSet; + RealmSet get dateSet => RealmObjectBase.get(this, 'dateSet') as RealmSet; @override - set dateSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set dateSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get doubleSet => - RealmObjectBase.get(this, 'doubleSet') as RealmSet; + RealmSet get doubleSet => RealmObjectBase.get(this, 'doubleSet') as RealmSet; @override - set doubleSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set doubleSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get objectIdSet => - RealmObjectBase.get(this, 'objectIdSet') as RealmSet; + RealmSet get objectIdSet => RealmObjectBase.get(this, 'objectIdSet') as RealmSet; @override - set objectIdSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set objectIdSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get uuidSet => - RealmObjectBase.get(this, 'uuidSet') as RealmSet; + RealmSet get uuidSet => RealmObjectBase.get(this, 'uuidSet') as RealmSet; @override - set uuidSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set uuidSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get intSet => - RealmObjectBase.get(this, 'intSet') as RealmSet; + RealmSet get intSet => RealmObjectBase.get(this, 'intSet') as RealmSet; @override set intSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get decimalSet => - RealmObjectBase.get(this, 'decimalSet') - as RealmSet; + RealmSet get decimalSet => RealmObjectBase.get(this, 'decimalSet') as RealmSet; @override - set decimalSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set decimalSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableStringSet => - RealmObjectBase.get(this, 'nullableStringSet') - as RealmSet; + RealmSet get nullableStringSet => RealmObjectBase.get(this, 'nullableStringSet') as RealmSet; @override - set nullableStringSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableStringSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableBoolSet => - RealmObjectBase.get(this, 'nullableBoolSet') as RealmSet; + RealmSet get nullableBoolSet => RealmObjectBase.get(this, 'nullableBoolSet') as RealmSet; @override - set nullableBoolSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableBoolSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableDateSet => - RealmObjectBase.get(this, 'nullableDateSet') - as RealmSet; + RealmSet get nullableDateSet => RealmObjectBase.get(this, 'nullableDateSet') as RealmSet; @override - set nullableDateSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableDateSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableDoubleSet => - RealmObjectBase.get(this, 'nullableDoubleSet') - as RealmSet; + RealmSet get nullableDoubleSet => RealmObjectBase.get(this, 'nullableDoubleSet') as RealmSet; @override - set nullableDoubleSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableDoubleSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableObjectIdSet => - RealmObjectBase.get(this, 'nullableObjectIdSet') - as RealmSet; + RealmSet get nullableObjectIdSet => RealmObjectBase.get(this, 'nullableObjectIdSet') as RealmSet; @override - set nullableObjectIdSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableObjectIdSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableUuidSet => - RealmObjectBase.get(this, 'nullableUuidSet') as RealmSet; + RealmSet get nullableUuidSet => RealmObjectBase.get(this, 'nullableUuidSet') as RealmSet; @override - set nullableUuidSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableUuidSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableIntSet => - RealmObjectBase.get(this, 'nullableIntSet') as RealmSet; + RealmSet get nullableIntSet => RealmObjectBase.get(this, 'nullableIntSet') as RealmSet; @override - set nullableIntSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableIntSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmSet get nullableDecimalSet => - RealmObjectBase.get(this, 'nullableDecimalSet') - as RealmSet; + RealmSet get nullableDecimalSet => RealmObjectBase.get(this, 'nullableDecimalSet') as RealmSet; @override - set nullableDecimalSet(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set nullableDecimalSet(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - RealmMap get stringMap => - RealmObjectBase.get(this, 'stringMap') as RealmMap; + RealmMap get stringMap => RealmObjectBase.get(this, 'stringMap') as RealmMap; @override - set stringMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set stringMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get boolMap => - RealmObjectBase.get(this, 'boolMap') as RealmMap; + RealmMap get boolMap => RealmObjectBase.get(this, 'boolMap') as RealmMap; @override - set boolMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set boolMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get dateMap => - RealmObjectBase.get(this, 'dateMap') as RealmMap; + RealmMap get dateMap => RealmObjectBase.get(this, 'dateMap') as RealmMap; @override - set dateMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set dateMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get doubleMap => - RealmObjectBase.get(this, 'doubleMap') as RealmMap; + RealmMap get doubleMap => RealmObjectBase.get(this, 'doubleMap') as RealmMap; @override - set doubleMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set doubleMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get objectIdMap => - RealmObjectBase.get(this, 'objectIdMap') as RealmMap; + RealmMap get objectIdMap => RealmObjectBase.get(this, 'objectIdMap') as RealmMap; @override - set objectIdMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set objectIdMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get uuidMap => - RealmObjectBase.get(this, 'uuidMap') as RealmMap; + RealmMap get uuidMap => RealmObjectBase.get(this, 'uuidMap') as RealmMap; @override - set uuidMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set uuidMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get intMap => - RealmObjectBase.get(this, 'intMap') as RealmMap; + RealmMap get intMap => RealmObjectBase.get(this, 'intMap') as RealmMap; @override set intMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get decimalMap => - RealmObjectBase.get(this, 'decimalMap') - as RealmMap; + RealmMap get decimalMap => RealmObjectBase.get(this, 'decimalMap') as RealmMap; @override - set decimalMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set decimalMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableStringMap => - RealmObjectBase.get(this, 'nullableStringMap') - as RealmMap; + RealmMap get nullableStringMap => RealmObjectBase.get(this, 'nullableStringMap') as RealmMap; @override - set nullableStringMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableStringMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableBoolMap => - RealmObjectBase.get(this, 'nullableBoolMap') as RealmMap; + RealmMap get nullableBoolMap => RealmObjectBase.get(this, 'nullableBoolMap') as RealmMap; @override - set nullableBoolMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableBoolMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableDateMap => - RealmObjectBase.get(this, 'nullableDateMap') - as RealmMap; + RealmMap get nullableDateMap => RealmObjectBase.get(this, 'nullableDateMap') as RealmMap; @override - set nullableDateMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableDateMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableDoubleMap => - RealmObjectBase.get(this, 'nullableDoubleMap') - as RealmMap; + RealmMap get nullableDoubleMap => RealmObjectBase.get(this, 'nullableDoubleMap') as RealmMap; @override - set nullableDoubleMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableDoubleMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableObjectIdMap => - RealmObjectBase.get(this, 'nullableObjectIdMap') - as RealmMap; + RealmMap get nullableObjectIdMap => RealmObjectBase.get(this, 'nullableObjectIdMap') as RealmMap; @override - set nullableObjectIdMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableObjectIdMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableUuidMap => - RealmObjectBase.get(this, 'nullableUuidMap') as RealmMap; + RealmMap get nullableUuidMap => RealmObjectBase.get(this, 'nullableUuidMap') as RealmMap; @override - set nullableUuidMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableUuidMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableIntMap => - RealmObjectBase.get(this, 'nullableIntMap') as RealmMap; + RealmMap get nullableIntMap => RealmObjectBase.get(this, 'nullableIntMap') as RealmMap; @override - set nullableIntMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableIntMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmMap get nullableDecimalMap => - RealmObjectBase.get(this, 'nullableDecimalMap') - as RealmMap; + RealmMap get nullableDecimalMap => RealmObjectBase.get(this, 'nullableDecimalMap') as RealmMap; @override - set nullableDecimalMap(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set nullableDecimalMap(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override AllCollections freeze() => RealmObjectBase.freezeObject(this); @@ -1864,104 +1565,55 @@ class AllCollections extends _AllCollections static final schema = () { RealmObjectBase.registerFactory(AllCollections._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, AllCollections, 'AllCollections', [ - SchemaProperty('stringList', RealmPropertyType.string, - collectionType: RealmCollectionType.list), - SchemaProperty('boolList', RealmPropertyType.bool, - collectionType: RealmCollectionType.list), - SchemaProperty('dateList', RealmPropertyType.timestamp, - collectionType: RealmCollectionType.list), - SchemaProperty('doubleList', RealmPropertyType.double, - collectionType: RealmCollectionType.list), - SchemaProperty('objectIdList', RealmPropertyType.objectid, - collectionType: RealmCollectionType.list), - SchemaProperty('uuidList', RealmPropertyType.uuid, - collectionType: RealmCollectionType.list), - SchemaProperty('intList', RealmPropertyType.int, - collectionType: RealmCollectionType.list), - SchemaProperty('decimalList', RealmPropertyType.decimal128, - collectionType: RealmCollectionType.list), - SchemaProperty('nullableStringList', RealmPropertyType.string, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableBoolList', RealmPropertyType.bool, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableDateList', RealmPropertyType.timestamp, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableDoubleList', RealmPropertyType.double, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableObjectIdList', RealmPropertyType.objectid, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableUuidList', RealmPropertyType.uuid, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableIntList', RealmPropertyType.int, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('nullableDecimalList', RealmPropertyType.decimal128, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('stringSet', RealmPropertyType.string, - collectionType: RealmCollectionType.set), - SchemaProperty('boolSet', RealmPropertyType.bool, - collectionType: RealmCollectionType.set), - SchemaProperty('dateSet', RealmPropertyType.timestamp, - collectionType: RealmCollectionType.set), - SchemaProperty('doubleSet', RealmPropertyType.double, - collectionType: RealmCollectionType.set), - SchemaProperty('objectIdSet', RealmPropertyType.objectid, - collectionType: RealmCollectionType.set), - SchemaProperty('uuidSet', RealmPropertyType.uuid, - collectionType: RealmCollectionType.set), - SchemaProperty('intSet', RealmPropertyType.int, - collectionType: RealmCollectionType.set), - SchemaProperty('decimalSet', RealmPropertyType.decimal128, - collectionType: RealmCollectionType.set), - SchemaProperty('nullableStringSet', RealmPropertyType.string, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableBoolSet', RealmPropertyType.bool, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableDateSet', RealmPropertyType.timestamp, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableDoubleSet', RealmPropertyType.double, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableObjectIdSet', RealmPropertyType.objectid, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableUuidSet', RealmPropertyType.uuid, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableIntSet', RealmPropertyType.int, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('nullableDecimalSet', RealmPropertyType.decimal128, - optional: true, collectionType: RealmCollectionType.set), - SchemaProperty('stringMap', RealmPropertyType.string, - collectionType: RealmCollectionType.map), - SchemaProperty('boolMap', RealmPropertyType.bool, - collectionType: RealmCollectionType.map), - SchemaProperty('dateMap', RealmPropertyType.timestamp, - collectionType: RealmCollectionType.map), - SchemaProperty('doubleMap', RealmPropertyType.double, - collectionType: RealmCollectionType.map), - SchemaProperty('objectIdMap', RealmPropertyType.objectid, - collectionType: RealmCollectionType.map), - SchemaProperty('uuidMap', RealmPropertyType.uuid, - collectionType: RealmCollectionType.map), - SchemaProperty('intMap', RealmPropertyType.int, - collectionType: RealmCollectionType.map), - SchemaProperty('decimalMap', RealmPropertyType.decimal128, - collectionType: RealmCollectionType.map), - SchemaProperty('nullableStringMap', RealmPropertyType.string, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableBoolMap', RealmPropertyType.bool, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableDateMap', RealmPropertyType.timestamp, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableDoubleMap', RealmPropertyType.double, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableObjectIdMap', RealmPropertyType.objectid, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableUuidMap', RealmPropertyType.uuid, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableIntMap', RealmPropertyType.int, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('nullableDecimalMap', RealmPropertyType.decimal128, - optional: true, collectionType: RealmCollectionType.map), + return const SchemaObject(ObjectType.realmObject, AllCollections, 'AllCollections', [ + SchemaProperty('stringList', RealmPropertyType.string, collectionType: RealmCollectionType.list), + SchemaProperty('boolList', RealmPropertyType.bool, collectionType: RealmCollectionType.list), + SchemaProperty('dateList', RealmPropertyType.timestamp, collectionType: RealmCollectionType.list), + SchemaProperty('doubleList', RealmPropertyType.double, collectionType: RealmCollectionType.list), + SchemaProperty('objectIdList', RealmPropertyType.objectid, collectionType: RealmCollectionType.list), + SchemaProperty('uuidList', RealmPropertyType.uuid, collectionType: RealmCollectionType.list), + SchemaProperty('intList', RealmPropertyType.int, collectionType: RealmCollectionType.list), + SchemaProperty('decimalList', RealmPropertyType.decimal128, collectionType: RealmCollectionType.list), + SchemaProperty('nullableStringList', RealmPropertyType.string, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableBoolList', RealmPropertyType.bool, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableDateList', RealmPropertyType.timestamp, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableDoubleList', RealmPropertyType.double, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableObjectIdList', RealmPropertyType.objectid, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableUuidList', RealmPropertyType.uuid, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableIntList', RealmPropertyType.int, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('nullableDecimalList', RealmPropertyType.decimal128, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('stringSet', RealmPropertyType.string, collectionType: RealmCollectionType.set), + SchemaProperty('boolSet', RealmPropertyType.bool, collectionType: RealmCollectionType.set), + SchemaProperty('dateSet', RealmPropertyType.timestamp, collectionType: RealmCollectionType.set), + SchemaProperty('doubleSet', RealmPropertyType.double, collectionType: RealmCollectionType.set), + SchemaProperty('objectIdSet', RealmPropertyType.objectid, collectionType: RealmCollectionType.set), + SchemaProperty('uuidSet', RealmPropertyType.uuid, collectionType: RealmCollectionType.set), + SchemaProperty('intSet', RealmPropertyType.int, collectionType: RealmCollectionType.set), + SchemaProperty('decimalSet', RealmPropertyType.decimal128, collectionType: RealmCollectionType.set), + SchemaProperty('nullableStringSet', RealmPropertyType.string, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableBoolSet', RealmPropertyType.bool, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableDateSet', RealmPropertyType.timestamp, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableDoubleSet', RealmPropertyType.double, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableObjectIdSet', RealmPropertyType.objectid, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableUuidSet', RealmPropertyType.uuid, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableIntSet', RealmPropertyType.int, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('nullableDecimalSet', RealmPropertyType.decimal128, optional: true, collectionType: RealmCollectionType.set), + SchemaProperty('stringMap', RealmPropertyType.string, collectionType: RealmCollectionType.map), + SchemaProperty('boolMap', RealmPropertyType.bool, collectionType: RealmCollectionType.map), + SchemaProperty('dateMap', RealmPropertyType.timestamp, collectionType: RealmCollectionType.map), + SchemaProperty('doubleMap', RealmPropertyType.double, collectionType: RealmCollectionType.map), + SchemaProperty('objectIdMap', RealmPropertyType.objectid, collectionType: RealmCollectionType.map), + SchemaProperty('uuidMap', RealmPropertyType.uuid, collectionType: RealmCollectionType.map), + SchemaProperty('intMap', RealmPropertyType.int, collectionType: RealmCollectionType.map), + SchemaProperty('decimalMap', RealmPropertyType.decimal128, collectionType: RealmCollectionType.map), + SchemaProperty('nullableStringMap', RealmPropertyType.string, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableBoolMap', RealmPropertyType.bool, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableDateMap', RealmPropertyType.timestamp, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableDoubleMap', RealmPropertyType.double, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableObjectIdMap', RealmPropertyType.objectid, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableUuidMap', RealmPropertyType.uuid, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableIntMap', RealmPropertyType.int, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('nullableDecimalMap', RealmPropertyType.decimal128, optional: true, collectionType: RealmCollectionType.map), ]); }(); @@ -1969,8 +1621,7 @@ class AllCollections extends _AllCollections SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class NullableTypes extends _NullableTypes - with RealmEntity, RealmObjectBase, RealmObject { +class NullableTypes extends _NullableTypes with RealmEntity, RealmObjectBase, RealmObject { NullableTypes( ObjectId id, ObjectId differentiator, { @@ -2003,18 +1654,14 @@ class NullableTypes extends _NullableTypes set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - ObjectId get differentiator => - RealmObjectBase.get(this, 'differentiator') as ObjectId; + ObjectId get differentiator => RealmObjectBase.get(this, 'differentiator') as ObjectId; @override - set differentiator(ObjectId value) => - RealmObjectBase.set(this, 'differentiator', value); + set differentiator(ObjectId value) => RealmObjectBase.set(this, 'differentiator', value); @override - String? get stringProp => - RealmObjectBase.get(this, 'stringProp') as String?; + String? get stringProp => RealmObjectBase.get(this, 'stringProp') as String?; @override - set stringProp(String? value) => - RealmObjectBase.set(this, 'stringProp', value); + set stringProp(String? value) => RealmObjectBase.set(this, 'stringProp', value); @override bool? get boolProp => RealmObjectBase.get(this, 'boolProp') as bool?; @@ -2022,24 +1669,19 @@ class NullableTypes extends _NullableTypes set boolProp(bool? value) => RealmObjectBase.set(this, 'boolProp', value); @override - DateTime? get dateProp => - RealmObjectBase.get(this, 'dateProp') as DateTime?; + DateTime? get dateProp => RealmObjectBase.get(this, 'dateProp') as DateTime?; @override set dateProp(DateTime? value) => RealmObjectBase.set(this, 'dateProp', value); @override - double? get doubleProp => - RealmObjectBase.get(this, 'doubleProp') as double?; + double? get doubleProp => RealmObjectBase.get(this, 'doubleProp') as double?; @override - set doubleProp(double? value) => - RealmObjectBase.set(this, 'doubleProp', value); + set doubleProp(double? value) => RealmObjectBase.set(this, 'doubleProp', value); @override - ObjectId? get objectIdProp => - RealmObjectBase.get(this, 'objectIdProp') as ObjectId?; + ObjectId? get objectIdProp => RealmObjectBase.get(this, 'objectIdProp') as ObjectId?; @override - set objectIdProp(ObjectId? value) => - RealmObjectBase.set(this, 'objectIdProp', value); + set objectIdProp(ObjectId? value) => RealmObjectBase.set(this, 'objectIdProp', value); @override Uuid? get uuidProp => RealmObjectBase.get(this, 'uuidProp') as Uuid?; @@ -2052,20 +1694,15 @@ class NullableTypes extends _NullableTypes set intProp(int? value) => RealmObjectBase.set(this, 'intProp', value); @override - Decimal128? get decimalProp => - RealmObjectBase.get(this, 'decimalProp') as Decimal128?; + Decimal128? get decimalProp => RealmObjectBase.get(this, 'decimalProp') as Decimal128?; @override - set decimalProp(Decimal128? value) => - RealmObjectBase.set(this, 'decimalProp', value); + set decimalProp(Decimal128? value) => RealmObjectBase.set(this, 'decimalProp', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override NullableTypes freeze() => RealmObjectBase.freezeObject(this); @@ -2112,21 +1749,17 @@ class NullableTypes extends _NullableTypes static final schema = () { RealmObjectBase.registerFactory(NullableTypes._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, NullableTypes, 'NullableTypes', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), + return const SchemaObject(ObjectType.realmObject, NullableTypes, 'NullableTypes', [ + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), SchemaProperty('differentiator', RealmPropertyType.objectid), SchemaProperty('stringProp', RealmPropertyType.string, optional: true), SchemaProperty('boolProp', RealmPropertyType.bool, optional: true), SchemaProperty('dateProp', RealmPropertyType.timestamp, optional: true), SchemaProperty('doubleProp', RealmPropertyType.double, optional: true), - SchemaProperty('objectIdProp', RealmPropertyType.objectid, - optional: true), + SchemaProperty('objectIdProp', RealmPropertyType.objectid, optional: true), SchemaProperty('uuidProp', RealmPropertyType.uuid, optional: true), SchemaProperty('intProp', RealmPropertyType.int, optional: true), - SchemaProperty('decimalProp', RealmPropertyType.decimal128, - optional: true), + SchemaProperty('decimalProp', RealmPropertyType.decimal128, optional: true), ]); }(); @@ -2157,40 +1790,30 @@ class Event extends _Event with RealmEntity, RealmObjectBase, RealmObject { set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - String? get name => - RealmObjectBase.get(this, 'stringQueryField') as String?; + String? get name => RealmObjectBase.get(this, 'stringQueryField') as String?; @override - set name(String? value) => - RealmObjectBase.set(this, 'stringQueryField', value); + set name(String? value) => RealmObjectBase.set(this, 'stringQueryField', value); @override - bool? get isCompleted => - RealmObjectBase.get(this, 'boolQueryField') as bool?; + bool? get isCompleted => RealmObjectBase.get(this, 'boolQueryField') as bool?; @override - set isCompleted(bool? value) => - RealmObjectBase.set(this, 'boolQueryField', value); + set isCompleted(bool? value) => RealmObjectBase.set(this, 'boolQueryField', value); @override - int? get durationInMinutes => - RealmObjectBase.get(this, 'intQueryField') as int?; + int? get durationInMinutes => RealmObjectBase.get(this, 'intQueryField') as int?; @override - set durationInMinutes(int? value) => - RealmObjectBase.set(this, 'intQueryField', value); + set durationInMinutes(int? value) => RealmObjectBase.set(this, 'intQueryField', value); @override - String? get assignedTo => - RealmObjectBase.get(this, 'assignedTo') as String?; + String? get assignedTo => RealmObjectBase.get(this, 'assignedTo') as String?; @override - set assignedTo(String? value) => - RealmObjectBase.set(this, 'assignedTo', value); + set assignedTo(String? value) => RealmObjectBase.set(this, 'assignedTo', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Event freeze() => RealmObjectBase.freezeObject(this); @@ -2227,14 +1850,10 @@ class Event extends _Event with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.registerFactory(Event._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Event, 'Event', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('name', RealmPropertyType.string, - mapTo: 'stringQueryField', optional: true), - SchemaProperty('isCompleted', RealmPropertyType.bool, - mapTo: 'boolQueryField', optional: true), - SchemaProperty('durationInMinutes', RealmPropertyType.int, - mapTo: 'intQueryField', optional: true), + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), + SchemaProperty('name', RealmPropertyType.string, mapTo: 'stringQueryField', optional: true), + SchemaProperty('isCompleted', RealmPropertyType.bool, mapTo: 'boolQueryField', optional: true), + SchemaProperty('durationInMinutes', RealmPropertyType.int, mapTo: 'intQueryField', optional: true), SchemaProperty('assignedTo', RealmPropertyType.string, optional: true), ]); }(); @@ -2252,8 +1871,7 @@ class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { }) { RealmObjectBase.set(this, 'host', host); RealmObjectBase.set(this, 'year', year); - RealmObjectBase.set>( - this, 'guests', RealmList(guests)); + RealmObjectBase.set>(this, 'guests', RealmList(guests)); RealmObjectBase.set(this, 'previous', previous); } @@ -2270,25 +1888,20 @@ class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { set year(int value) => RealmObjectBase.set(this, 'year', value); @override - RealmList get guests => - RealmObjectBase.get(this, 'guests') as RealmList; + RealmList get guests => RealmObjectBase.get(this, 'guests') as RealmList; @override - set guests(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set guests(covariant RealmList value) => throw RealmUnsupportedSetError(); @override Party? get previous => RealmObjectBase.get(this, 'previous') as Party?; @override - set previous(covariant Party? value) => - RealmObjectBase.set(this, 'previous', value); + set previous(covariant Party? value) => RealmObjectBase.set(this, 'previous', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Party freeze() => RealmObjectBase.freezeObject(this); @@ -2323,13 +1936,10 @@ class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.registerFactory(Party._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Party, 'Party', [ - SchemaProperty('host', RealmPropertyType.object, - optional: true, linkTarget: 'Friend'), + SchemaProperty('host', RealmPropertyType.object, optional: true, linkTarget: 'Friend'), SchemaProperty('year', RealmPropertyType.int), - SchemaProperty('guests', RealmPropertyType.object, - linkTarget: 'Friend', collectionType: RealmCollectionType.list), - SchemaProperty('previous', RealmPropertyType.object, - optional: true, linkTarget: 'Party'), + SchemaProperty('guests', RealmPropertyType.object, linkTarget: 'Friend', collectionType: RealmCollectionType.list), + SchemaProperty('previous', RealmPropertyType.object, optional: true, linkTarget: 'Party'), ]); }(); @@ -2354,8 +1964,7 @@ class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.set(this, 'name', name); RealmObjectBase.set(this, 'age', age); RealmObjectBase.set(this, 'bestFriend', bestFriend); - RealmObjectBase.set>( - this, 'friends', RealmList(friends)); + RealmObjectBase.set>(this, 'friends', RealmList(friends)); } Friend._(); @@ -2371,26 +1980,20 @@ class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { set age(int value) => RealmObjectBase.set(this, 'age', value); @override - Friend? get bestFriend => - RealmObjectBase.get(this, 'bestFriend') as Friend?; + Friend? get bestFriend => RealmObjectBase.get(this, 'bestFriend') as Friend?; @override - set bestFriend(covariant Friend? value) => - RealmObjectBase.set(this, 'bestFriend', value); + set bestFriend(covariant Friend? value) => RealmObjectBase.set(this, 'bestFriend', value); @override - RealmList get friends => - RealmObjectBase.get(this, 'friends') as RealmList; + RealmList get friends => RealmObjectBase.get(this, 'friends') as RealmList; @override - set friends(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set friends(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Friend freeze() => RealmObjectBase.freezeObject(this); @@ -2427,10 +2030,8 @@ class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { return const SchemaObject(ObjectType.realmObject, Friend, 'Friend', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('age', RealmPropertyType.int), - SchemaProperty('bestFriend', RealmPropertyType.object, - optional: true, linkTarget: 'Friend'), - SchemaProperty('friends', RealmPropertyType.object, - linkTarget: 'Friend', collectionType: RealmCollectionType.list), + SchemaProperty('bestFriend', RealmPropertyType.object, optional: true, linkTarget: 'Friend'), + SchemaProperty('friends', RealmPropertyType.object, linkTarget: 'Friend', collectionType: RealmCollectionType.list), ]); }(); @@ -2450,26 +2051,20 @@ class When extends _When with RealmEntity, RealmObjectBase, RealmObject { When._(); @override - DateTime get dateTimeUtc => - RealmObjectBase.get(this, 'dateTimeUtc') as DateTime; + DateTime get dateTimeUtc => RealmObjectBase.get(this, 'dateTimeUtc') as DateTime; @override - set dateTimeUtc(DateTime value) => - RealmObjectBase.set(this, 'dateTimeUtc', value); + set dateTimeUtc(DateTime value) => RealmObjectBase.set(this, 'dateTimeUtc', value); @override - String get locationName => - RealmObjectBase.get(this, 'locationName') as String; + String get locationName => RealmObjectBase.get(this, 'locationName') as String; @override - set locationName(String value) => - RealmObjectBase.set(this, 'locationName', value); + set locationName(String value) => RealmObjectBase.set(this, 'locationName', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override When freeze() => RealmObjectBase.freezeObject(this); @@ -2518,8 +2113,7 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { }) { RealmObjectBase.set(this, 'name', name); RealmObjectBase.set(this, 'game', game); - RealmObjectBase.set>( - this, 'scoresByRound', RealmList(scoresByRound)); + RealmObjectBase.set>(this, 'scoresByRound', RealmList(scoresByRound)); } Player._(); @@ -2535,19 +2129,15 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { set game(covariant Game? value) => RealmObjectBase.set(this, 'game', value); @override - RealmList get scoresByRound => - RealmObjectBase.get(this, 'scoresByRound') as RealmList; + RealmList get scoresByRound => RealmObjectBase.get(this, 'scoresByRound') as RealmList; @override - set scoresByRound(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set scoresByRound(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Player freeze() => RealmObjectBase.freezeObject(this); @@ -2570,8 +2160,7 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { Player( fromEJson(name), game: fromEJson(ejson['game']), - scoresByRound: - fromEJson(ejson['scoresByRound'], defaultValue: const []), + scoresByRound: fromEJson(ejson['scoresByRound'], defaultValue: const []), ), _ => raiseInvalidEJson(ejson), }; @@ -2582,10 +2171,8 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Player, 'Player', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), - SchemaProperty('game', RealmPropertyType.object, - optional: true, linkTarget: 'Game'), - SchemaProperty('scoresByRound', RealmPropertyType.int, - optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('game', RealmPropertyType.object, optional: true, linkTarget: 'Game'), + SchemaProperty('scoresByRound', RealmPropertyType.int, optional: true, collectionType: RealmCollectionType.list), ]); }(); @@ -2597,26 +2184,21 @@ class Game extends _Game with RealmEntity, RealmObjectBase, RealmObject { Game({ Iterable winnerByRound = const [], }) { - RealmObjectBase.set>( - this, 'winnerByRound', RealmList(winnerByRound)); + RealmObjectBase.set>(this, 'winnerByRound', RealmList(winnerByRound)); } Game._(); @override - RealmList get winnerByRound => - RealmObjectBase.get(this, 'winnerByRound') as RealmList; + RealmList get winnerByRound => RealmObjectBase.get(this, 'winnerByRound') as RealmList; @override - set winnerByRound(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set winnerByRound(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Game freeze() => RealmObjectBase.freezeObject(this); @@ -2639,8 +2221,7 @@ class Game extends _Game with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.registerFactory(Game._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Game, 'Game', [ - SchemaProperty('winnerByRound', RealmPropertyType.object, - linkTarget: 'Player', collectionType: RealmCollectionType.list), + SchemaProperty('winnerByRound', RealmPropertyType.object, linkTarget: 'Player', collectionType: RealmCollectionType.list), ]); }(); @@ -2648,8 +2229,7 @@ class Game extends _Game with RealmEntity, RealmObjectBase, RealmObject { SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class AllTypesEmbedded extends _AllTypesEmbedded - with RealmEntity, RealmObjectBase, EmbeddedObject { +class AllTypesEmbedded extends _AllTypesEmbedded with RealmEntity, RealmObjectBase, EmbeddedObject { AllTypesEmbedded( String stringProp, bool boolProp, @@ -2692,29 +2272,22 @@ class AllTypesEmbedded extends _AllTypesEmbedded RealmObjectBase.set(this, 'nullableUuidProp', nullableUuidProp); RealmObjectBase.set(this, 'nullableIntProp', nullableIntProp); RealmObjectBase.set(this, 'nullableDecimalProp', nullableDecimalProp); - RealmObjectBase.set>( - this, 'strings', RealmList(strings)); + RealmObjectBase.set>(this, 'strings', RealmList(strings)); RealmObjectBase.set>(this, 'bools', RealmList(bools)); - RealmObjectBase.set>( - this, 'dates', RealmList(dates)); - RealmObjectBase.set>( - this, 'doubles', RealmList(doubles)); - RealmObjectBase.set>( - this, 'objectIds', RealmList(objectIds)); + RealmObjectBase.set>(this, 'dates', RealmList(dates)); + RealmObjectBase.set>(this, 'doubles', RealmList(doubles)); + RealmObjectBase.set>(this, 'objectIds', RealmList(objectIds)); RealmObjectBase.set>(this, 'uuids', RealmList(uuids)); RealmObjectBase.set>(this, 'ints', RealmList(ints)); - RealmObjectBase.set>( - this, 'decimals', RealmList(decimals)); + RealmObjectBase.set>(this, 'decimals', RealmList(decimals)); } AllTypesEmbedded._(); @override - String get stringProp => - RealmObjectBase.get(this, 'stringProp') as String; + String get stringProp => RealmObjectBase.get(this, 'stringProp') as String; @override - set stringProp(String value) => - RealmObjectBase.set(this, 'stringProp', value); + set stringProp(String value) => RealmObjectBase.set(this, 'stringProp', value); @override bool get boolProp => RealmObjectBase.get(this, 'boolProp') as bool; @@ -2722,24 +2295,19 @@ class AllTypesEmbedded extends _AllTypesEmbedded set boolProp(bool value) => RealmObjectBase.set(this, 'boolProp', value); @override - DateTime get dateProp => - RealmObjectBase.get(this, 'dateProp') as DateTime; + DateTime get dateProp => RealmObjectBase.get(this, 'dateProp') as DateTime; @override set dateProp(DateTime value) => RealmObjectBase.set(this, 'dateProp', value); @override - double get doubleProp => - RealmObjectBase.get(this, 'doubleProp') as double; + double get doubleProp => RealmObjectBase.get(this, 'doubleProp') as double; @override - set doubleProp(double value) => - RealmObjectBase.set(this, 'doubleProp', value); + set doubleProp(double value) => RealmObjectBase.set(this, 'doubleProp', value); @override - ObjectId get objectIdProp => - RealmObjectBase.get(this, 'objectIdProp') as ObjectId; + ObjectId get objectIdProp => RealmObjectBase.get(this, 'objectIdProp') as ObjectId; @override - set objectIdProp(ObjectId value) => - RealmObjectBase.set(this, 'objectIdProp', value); + set objectIdProp(ObjectId value) => RealmObjectBase.set(this, 'objectIdProp', value); @override Uuid get uuidProp => RealmObjectBase.get(this, 'uuidProp') as Uuid; @@ -2752,137 +2320,98 @@ class AllTypesEmbedded extends _AllTypesEmbedded set intProp(int value) => RealmObjectBase.set(this, 'intProp', value); @override - Decimal128 get decimalProp => - RealmObjectBase.get(this, 'decimalProp') as Decimal128; + Decimal128 get decimalProp => RealmObjectBase.get(this, 'decimalProp') as Decimal128; @override - set decimalProp(Decimal128 value) => - RealmObjectBase.set(this, 'decimalProp', value); + set decimalProp(Decimal128 value) => RealmObjectBase.set(this, 'decimalProp', value); @override - String? get nullableStringProp => - RealmObjectBase.get(this, 'nullableStringProp') as String?; + String? get nullableStringProp => RealmObjectBase.get(this, 'nullableStringProp') as String?; @override - set nullableStringProp(String? value) => - RealmObjectBase.set(this, 'nullableStringProp', value); + set nullableStringProp(String? value) => RealmObjectBase.set(this, 'nullableStringProp', value); @override - bool? get nullableBoolProp => - RealmObjectBase.get(this, 'nullableBoolProp') as bool?; + bool? get nullableBoolProp => RealmObjectBase.get(this, 'nullableBoolProp') as bool?; @override - set nullableBoolProp(bool? value) => - RealmObjectBase.set(this, 'nullableBoolProp', value); + set nullableBoolProp(bool? value) => RealmObjectBase.set(this, 'nullableBoolProp', value); @override - DateTime? get nullableDateProp => - RealmObjectBase.get(this, 'nullableDateProp') as DateTime?; + DateTime? get nullableDateProp => RealmObjectBase.get(this, 'nullableDateProp') as DateTime?; @override - set nullableDateProp(DateTime? value) => - RealmObjectBase.set(this, 'nullableDateProp', value); + set nullableDateProp(DateTime? value) => RealmObjectBase.set(this, 'nullableDateProp', value); @override - double? get nullableDoubleProp => - RealmObjectBase.get(this, 'nullableDoubleProp') as double?; + double? get nullableDoubleProp => RealmObjectBase.get(this, 'nullableDoubleProp') as double?; @override - set nullableDoubleProp(double? value) => - RealmObjectBase.set(this, 'nullableDoubleProp', value); + set nullableDoubleProp(double? value) => RealmObjectBase.set(this, 'nullableDoubleProp', value); @override - ObjectId? get nullableObjectIdProp => - RealmObjectBase.get(this, 'nullableObjectIdProp') as ObjectId?; + ObjectId? get nullableObjectIdProp => RealmObjectBase.get(this, 'nullableObjectIdProp') as ObjectId?; @override - set nullableObjectIdProp(ObjectId? value) => - RealmObjectBase.set(this, 'nullableObjectIdProp', value); + set nullableObjectIdProp(ObjectId? value) => RealmObjectBase.set(this, 'nullableObjectIdProp', value); @override - Uuid? get nullableUuidProp => - RealmObjectBase.get(this, 'nullableUuidProp') as Uuid?; + Uuid? get nullableUuidProp => RealmObjectBase.get(this, 'nullableUuidProp') as Uuid?; @override - set nullableUuidProp(Uuid? value) => - RealmObjectBase.set(this, 'nullableUuidProp', value); + set nullableUuidProp(Uuid? value) => RealmObjectBase.set(this, 'nullableUuidProp', value); @override - int? get nullableIntProp => - RealmObjectBase.get(this, 'nullableIntProp') as int?; + int? get nullableIntProp => RealmObjectBase.get(this, 'nullableIntProp') as int?; @override - set nullableIntProp(int? value) => - RealmObjectBase.set(this, 'nullableIntProp', value); + set nullableIntProp(int? value) => RealmObjectBase.set(this, 'nullableIntProp', value); @override - Decimal128? get nullableDecimalProp => - RealmObjectBase.get(this, 'nullableDecimalProp') - as Decimal128?; + Decimal128? get nullableDecimalProp => RealmObjectBase.get(this, 'nullableDecimalProp') as Decimal128?; @override - set nullableDecimalProp(Decimal128? value) => - RealmObjectBase.set(this, 'nullableDecimalProp', value); + set nullableDecimalProp(Decimal128? value) => RealmObjectBase.set(this, 'nullableDecimalProp', value); @override - RealmList get strings => - RealmObjectBase.get(this, 'strings') as RealmList; + RealmList get strings => RealmObjectBase.get(this, 'strings') as RealmList; @override - set strings(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set strings(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get bools => - RealmObjectBase.get(this, 'bools') as RealmList; + RealmList get bools => RealmObjectBase.get(this, 'bools') as RealmList; @override - set bools(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set bools(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get dates => - RealmObjectBase.get(this, 'dates') as RealmList; + RealmList get dates => RealmObjectBase.get(this, 'dates') as RealmList; @override - set dates(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set dates(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get doubles => - RealmObjectBase.get(this, 'doubles') as RealmList; + RealmList get doubles => RealmObjectBase.get(this, 'doubles') as RealmList; @override - set doubles(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set doubles(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get objectIds => - RealmObjectBase.get(this, 'objectIds') as RealmList; + RealmList get objectIds => RealmObjectBase.get(this, 'objectIds') as RealmList; @override - set objectIds(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set objectIds(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get uuids => - RealmObjectBase.get(this, 'uuids') as RealmList; + RealmList get uuids => RealmObjectBase.get(this, 'uuids') as RealmList; @override - set uuids(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set uuids(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get ints => - RealmObjectBase.get(this, 'ints') as RealmList; + RealmList get ints => RealmObjectBase.get(this, 'ints') as RealmList; @override set ints(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmList get decimals => - RealmObjectBase.get(this, 'decimals') - as RealmList; + RealmList get decimals => RealmObjectBase.get(this, 'decimals') as RealmList; @override - set decimals(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set decimals(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - AllTypesEmbedded freeze() => - RealmObjectBase.freezeObject(this); + AllTypesEmbedded freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -2960,8 +2489,7 @@ class AllTypesEmbedded extends _AllTypesEmbedded static final schema = () { RealmObjectBase.registerFactory(AllTypesEmbedded._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.embeddedObject, AllTypesEmbedded, 'AllTypesEmbedded', [ + return const SchemaObject(ObjectType.embeddedObject, AllTypesEmbedded, 'AllTypesEmbedded', [ SchemaProperty('stringProp', RealmPropertyType.string), SchemaProperty('boolProp', RealmPropertyType.bool), SchemaProperty('dateProp', RealmPropertyType.timestamp), @@ -2970,37 +2498,22 @@ class AllTypesEmbedded extends _AllTypesEmbedded SchemaProperty('uuidProp', RealmPropertyType.uuid), SchemaProperty('intProp', RealmPropertyType.int), SchemaProperty('decimalProp', RealmPropertyType.decimal128), - SchemaProperty('nullableStringProp', RealmPropertyType.string, - optional: true), - SchemaProperty('nullableBoolProp', RealmPropertyType.bool, - optional: true), - SchemaProperty('nullableDateProp', RealmPropertyType.timestamp, - optional: true), - SchemaProperty('nullableDoubleProp', RealmPropertyType.double, - optional: true), - SchemaProperty('nullableObjectIdProp', RealmPropertyType.objectid, - optional: true), - SchemaProperty('nullableUuidProp', RealmPropertyType.uuid, - optional: true), + SchemaProperty('nullableStringProp', RealmPropertyType.string, optional: true), + SchemaProperty('nullableBoolProp', RealmPropertyType.bool, optional: true), + SchemaProperty('nullableDateProp', RealmPropertyType.timestamp, optional: true), + SchemaProperty('nullableDoubleProp', RealmPropertyType.double, optional: true), + SchemaProperty('nullableObjectIdProp', RealmPropertyType.objectid, optional: true), + SchemaProperty('nullableUuidProp', RealmPropertyType.uuid, optional: true), SchemaProperty('nullableIntProp', RealmPropertyType.int, optional: true), - SchemaProperty('nullableDecimalProp', RealmPropertyType.decimal128, - optional: true), - SchemaProperty('strings', RealmPropertyType.string, - collectionType: RealmCollectionType.list), - SchemaProperty('bools', RealmPropertyType.bool, - collectionType: RealmCollectionType.list), - SchemaProperty('dates', RealmPropertyType.timestamp, - collectionType: RealmCollectionType.list), - SchemaProperty('doubles', RealmPropertyType.double, - collectionType: RealmCollectionType.list), - SchemaProperty('objectIds', RealmPropertyType.objectid, - collectionType: RealmCollectionType.list), - SchemaProperty('uuids', RealmPropertyType.uuid, - collectionType: RealmCollectionType.list), - SchemaProperty('ints', RealmPropertyType.int, - collectionType: RealmCollectionType.list), - SchemaProperty('decimals', RealmPropertyType.decimal128, - collectionType: RealmCollectionType.list), + SchemaProperty('nullableDecimalProp', RealmPropertyType.decimal128, optional: true), + SchemaProperty('strings', RealmPropertyType.string, collectionType: RealmCollectionType.list), + SchemaProperty('bools', RealmPropertyType.bool, collectionType: RealmCollectionType.list), + SchemaProperty('dates', RealmPropertyType.timestamp, collectionType: RealmCollectionType.list), + SchemaProperty('doubles', RealmPropertyType.double, collectionType: RealmCollectionType.list), + SchemaProperty('objectIds', RealmPropertyType.objectid, collectionType: RealmCollectionType.list), + SchemaProperty('uuids', RealmPropertyType.uuid, collectionType: RealmCollectionType.list), + SchemaProperty('ints', RealmPropertyType.int, collectionType: RealmCollectionType.list), + SchemaProperty('decimals', RealmPropertyType.decimal128, collectionType: RealmCollectionType.list), ]); }(); @@ -3008,8 +2521,7 @@ class AllTypesEmbedded extends _AllTypesEmbedded SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class ObjectWithEmbedded extends _ObjectWithEmbedded - with RealmEntity, RealmObjectBase, RealmObject { +class ObjectWithEmbedded extends _ObjectWithEmbedded with RealmEntity, RealmObjectBase, RealmObject { ObjectWithEmbedded( String id, { Uuid? differentiator, @@ -3021,11 +2533,9 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded RealmObjectBase.set(this, '_id', id); RealmObjectBase.set(this, 'differentiator', differentiator); RealmObjectBase.set(this, 'singleObject', singleObject); - RealmObjectBase.set>( - this, 'list', RealmList(list)); + RealmObjectBase.set>(this, 'list', RealmList(list)); RealmObjectBase.set(this, 'recursiveObject', recursiveObject); - RealmObjectBase.set>( - this, 'recursiveList', RealmList(recursiveList)); + RealmObjectBase.set>(this, 'recursiveList', RealmList(recursiveList)); } ObjectWithEmbedded._(); @@ -3036,56 +2546,38 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded set id(String value) => RealmObjectBase.set(this, '_id', value); @override - Uuid? get differentiator => - RealmObjectBase.get(this, 'differentiator') as Uuid?; + Uuid? get differentiator => RealmObjectBase.get(this, 'differentiator') as Uuid?; @override - set differentiator(Uuid? value) => - RealmObjectBase.set(this, 'differentiator', value); + set differentiator(Uuid? value) => RealmObjectBase.set(this, 'differentiator', value); @override - AllTypesEmbedded? get singleObject => - RealmObjectBase.get(this, 'singleObject') - as AllTypesEmbedded?; + AllTypesEmbedded? get singleObject => RealmObjectBase.get(this, 'singleObject') as AllTypesEmbedded?; @override - set singleObject(covariant AllTypesEmbedded? value) => - RealmObjectBase.set(this, 'singleObject', value); + set singleObject(covariant AllTypesEmbedded? value) => RealmObjectBase.set(this, 'singleObject', value); @override - RealmList get list => - RealmObjectBase.get(this, 'list') - as RealmList; + RealmList get list => RealmObjectBase.get(this, 'list') as RealmList; @override - set list(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set list(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RecursiveEmbedded1? get recursiveObject => - RealmObjectBase.get(this, 'recursiveObject') - as RecursiveEmbedded1?; + RecursiveEmbedded1? get recursiveObject => RealmObjectBase.get(this, 'recursiveObject') as RecursiveEmbedded1?; @override - set recursiveObject(covariant RecursiveEmbedded1? value) => - RealmObjectBase.set(this, 'recursiveObject', value); + set recursiveObject(covariant RecursiveEmbedded1? value) => RealmObjectBase.set(this, 'recursiveObject', value); @override - RealmList get recursiveList => - RealmObjectBase.get(this, 'recursiveList') - as RealmList; + RealmList get recursiveList => RealmObjectBase.get(this, 'recursiveList') as RealmList; @override - set recursiveList(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set recursiveList(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - ObjectWithEmbedded freeze() => - RealmObjectBase.freezeObject(this); + ObjectWithEmbedded freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3120,21 +2612,13 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded static final schema = () { RealmObjectBase.registerFactory(ObjectWithEmbedded._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, ObjectWithEmbedded, 'ObjectWithEmbedded', [ - SchemaProperty('id', RealmPropertyType.string, - mapTo: '_id', primaryKey: true), + return const SchemaObject(ObjectType.realmObject, ObjectWithEmbedded, 'ObjectWithEmbedded', [ + SchemaProperty('id', RealmPropertyType.string, mapTo: '_id', primaryKey: true), SchemaProperty('differentiator', RealmPropertyType.uuid, optional: true), - SchemaProperty('singleObject', RealmPropertyType.object, - optional: true, linkTarget: 'AllTypesEmbedded'), - SchemaProperty('list', RealmPropertyType.object, - linkTarget: 'AllTypesEmbedded', - collectionType: RealmCollectionType.list), - SchemaProperty('recursiveObject', RealmPropertyType.object, - optional: true, linkTarget: 'RecursiveEmbedded1'), - SchemaProperty('recursiveList', RealmPropertyType.object, - linkTarget: 'RecursiveEmbedded1', - collectionType: RealmCollectionType.list), + SchemaProperty('singleObject', RealmPropertyType.object, optional: true, linkTarget: 'AllTypesEmbedded'), + SchemaProperty('list', RealmPropertyType.object, linkTarget: 'AllTypesEmbedded', collectionType: RealmCollectionType.list), + SchemaProperty('recursiveObject', RealmPropertyType.object, optional: true, linkTarget: 'RecursiveEmbedded1'), + SchemaProperty('recursiveList', RealmPropertyType.object, linkTarget: 'RecursiveEmbedded1', collectionType: RealmCollectionType.list), ]); }(); @@ -3142,8 +2626,7 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class RecursiveEmbedded1 extends _RecursiveEmbedded1 - with RealmEntity, RealmObjectBase, EmbeddedObject { +class RecursiveEmbedded1 extends _RecursiveEmbedded1 with RealmEntity, RealmObjectBase, EmbeddedObject { RecursiveEmbedded1( String value, { RecursiveEmbedded2? child, @@ -3152,8 +2635,7 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 }) { RealmObjectBase.set(this, 'value', value); RealmObjectBase.set(this, 'child', child); - RealmObjectBase.set>( - this, 'children', RealmList(children)); + RealmObjectBase.set>(this, 'children', RealmList(children)); RealmObjectBase.set(this, 'realmObject', realmObject); } @@ -3165,41 +2647,28 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 set value(String value) => RealmObjectBase.set(this, 'value', value); @override - RecursiveEmbedded2? get child => - RealmObjectBase.get(this, 'child') - as RecursiveEmbedded2?; + RecursiveEmbedded2? get child => RealmObjectBase.get(this, 'child') as RecursiveEmbedded2?; @override - set child(covariant RecursiveEmbedded2? value) => - RealmObjectBase.set(this, 'child', value); + set child(covariant RecursiveEmbedded2? value) => RealmObjectBase.set(this, 'child', value); @override - RealmList get children => - RealmObjectBase.get(this, 'children') - as RealmList; + RealmList get children => RealmObjectBase.get(this, 'children') as RealmList; @override - set children(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set children(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - ObjectWithEmbedded? get realmObject => - RealmObjectBase.get(this, 'realmObject') - as ObjectWithEmbedded?; + ObjectWithEmbedded? get realmObject => RealmObjectBase.get(this, 'realmObject') as ObjectWithEmbedded?; @override - set realmObject(covariant ObjectWithEmbedded? value) => - RealmObjectBase.set(this, 'realmObject', value); + set realmObject(covariant ObjectWithEmbedded? value) => RealmObjectBase.set(this, 'realmObject', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - RecursiveEmbedded1 freeze() => - RealmObjectBase.freezeObject(this); + RecursiveEmbedded1 freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3230,16 +2699,11 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded1._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.embeddedObject, RecursiveEmbedded1, 'RecursiveEmbedded1', [ + return const SchemaObject(ObjectType.embeddedObject, RecursiveEmbedded1, 'RecursiveEmbedded1', [ SchemaProperty('value', RealmPropertyType.string), - SchemaProperty('child', RealmPropertyType.object, - optional: true, linkTarget: 'RecursiveEmbedded2'), - SchemaProperty('children', RealmPropertyType.object, - linkTarget: 'RecursiveEmbedded2', - collectionType: RealmCollectionType.list), - SchemaProperty('realmObject', RealmPropertyType.object, - optional: true, linkTarget: 'ObjectWithEmbedded'), + SchemaProperty('child', RealmPropertyType.object, optional: true, linkTarget: 'RecursiveEmbedded2'), + SchemaProperty('children', RealmPropertyType.object, linkTarget: 'RecursiveEmbedded2', collectionType: RealmCollectionType.list), + SchemaProperty('realmObject', RealmPropertyType.object, optional: true, linkTarget: 'ObjectWithEmbedded'), ]); }(); @@ -3247,8 +2711,7 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class RecursiveEmbedded2 extends _RecursiveEmbedded2 - with RealmEntity, RealmObjectBase, EmbeddedObject { +class RecursiveEmbedded2 extends _RecursiveEmbedded2 with RealmEntity, RealmObjectBase, EmbeddedObject { RecursiveEmbedded2( String value, { RecursiveEmbedded3? child, @@ -3257,8 +2720,7 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 }) { RealmObjectBase.set(this, 'value', value); RealmObjectBase.set(this, 'child', child); - RealmObjectBase.set>( - this, 'children', RealmList(children)); + RealmObjectBase.set>(this, 'children', RealmList(children)); RealmObjectBase.set(this, 'realmObject', realmObject); } @@ -3270,41 +2732,28 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 set value(String value) => RealmObjectBase.set(this, 'value', value); @override - RecursiveEmbedded3? get child => - RealmObjectBase.get(this, 'child') - as RecursiveEmbedded3?; + RecursiveEmbedded3? get child => RealmObjectBase.get(this, 'child') as RecursiveEmbedded3?; @override - set child(covariant RecursiveEmbedded3? value) => - RealmObjectBase.set(this, 'child', value); + set child(covariant RecursiveEmbedded3? value) => RealmObjectBase.set(this, 'child', value); @override - RealmList get children => - RealmObjectBase.get(this, 'children') - as RealmList; + RealmList get children => RealmObjectBase.get(this, 'children') as RealmList; @override - set children(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set children(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - ObjectWithEmbedded? get realmObject => - RealmObjectBase.get(this, 'realmObject') - as ObjectWithEmbedded?; + ObjectWithEmbedded? get realmObject => RealmObjectBase.get(this, 'realmObject') as ObjectWithEmbedded?; @override - set realmObject(covariant ObjectWithEmbedded? value) => - RealmObjectBase.set(this, 'realmObject', value); + set realmObject(covariant ObjectWithEmbedded? value) => RealmObjectBase.set(this, 'realmObject', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - RecursiveEmbedded2 freeze() => - RealmObjectBase.freezeObject(this); + RecursiveEmbedded2 freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3335,16 +2784,11 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded2._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.embeddedObject, RecursiveEmbedded2, 'RecursiveEmbedded2', [ + return const SchemaObject(ObjectType.embeddedObject, RecursiveEmbedded2, 'RecursiveEmbedded2', [ SchemaProperty('value', RealmPropertyType.string), - SchemaProperty('child', RealmPropertyType.object, - optional: true, linkTarget: 'RecursiveEmbedded3'), - SchemaProperty('children', RealmPropertyType.object, - linkTarget: 'RecursiveEmbedded3', - collectionType: RealmCollectionType.list), - SchemaProperty('realmObject', RealmPropertyType.object, - optional: true, linkTarget: 'ObjectWithEmbedded'), + SchemaProperty('child', RealmPropertyType.object, optional: true, linkTarget: 'RecursiveEmbedded3'), + SchemaProperty('children', RealmPropertyType.object, linkTarget: 'RecursiveEmbedded3', collectionType: RealmCollectionType.list), + SchemaProperty('realmObject', RealmPropertyType.object, optional: true, linkTarget: 'ObjectWithEmbedded'), ]); }(); @@ -3352,8 +2796,7 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class RecursiveEmbedded3 extends _RecursiveEmbedded3 - with RealmEntity, RealmObjectBase, EmbeddedObject { +class RecursiveEmbedded3 extends _RecursiveEmbedded3 with RealmEntity, RealmObjectBase, EmbeddedObject { RecursiveEmbedded3( String value, ) { @@ -3368,17 +2811,13 @@ class RecursiveEmbedded3 extends _RecursiveEmbedded3 set value(String value) => RealmObjectBase.set(this, 'value', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - RecursiveEmbedded3 freeze() => - RealmObjectBase.freezeObject(this); + RecursiveEmbedded3 freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3403,8 +2842,7 @@ class RecursiveEmbedded3 extends _RecursiveEmbedded3 static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded3._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.embeddedObject, RecursiveEmbedded3, 'RecursiveEmbedded3', [ + return const SchemaObject(ObjectType.embeddedObject, RecursiveEmbedded3, 'RecursiveEmbedded3', [ SchemaProperty('value', RealmPropertyType.string), ]); }(); @@ -3413,8 +2851,7 @@ class RecursiveEmbedded3 extends _RecursiveEmbedded3 SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class ObjectWithDecimal extends _ObjectWithDecimal - with RealmEntity, RealmObjectBase, RealmObject { +class ObjectWithDecimal extends _ObjectWithDecimal with RealmEntity, RealmObjectBase, RealmObject { ObjectWithDecimal( Decimal128 decimal, { Decimal128? nullableDecimal, @@ -3426,30 +2863,23 @@ class ObjectWithDecimal extends _ObjectWithDecimal ObjectWithDecimal._(); @override - Decimal128 get decimal => - RealmObjectBase.get(this, 'decimal') as Decimal128; + Decimal128 get decimal => RealmObjectBase.get(this, 'decimal') as Decimal128; @override set decimal(Decimal128 value) => RealmObjectBase.set(this, 'decimal', value); @override - Decimal128? get nullableDecimal => - RealmObjectBase.get(this, 'nullableDecimal') as Decimal128?; + Decimal128? get nullableDecimal => RealmObjectBase.get(this, 'nullableDecimal') as Decimal128?; @override - set nullableDecimal(Decimal128? value) => - RealmObjectBase.set(this, 'nullableDecimal', value); + set nullableDecimal(Decimal128? value) => RealmObjectBase.set(this, 'nullableDecimal', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - ObjectWithDecimal freeze() => - RealmObjectBase.freezeObject(this); + ObjectWithDecimal freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3476,11 +2906,9 @@ class ObjectWithDecimal extends _ObjectWithDecimal static final schema = () { RealmObjectBase.registerFactory(ObjectWithDecimal._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, ObjectWithDecimal, 'ObjectWithDecimal', [ + return const SchemaObject(ObjectType.realmObject, ObjectWithDecimal, 'ObjectWithDecimal', [ SchemaProperty('decimal', RealmPropertyType.decimal128), - SchemaProperty('nullableDecimal', RealmPropertyType.decimal128, - optional: true), + SchemaProperty('nullableDecimal', RealmPropertyType.decimal128, optional: true), ]); }(); @@ -3488,96 +2916,7 @@ class ObjectWithDecimal extends _ObjectWithDecimal SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class Asymmetric extends _Asymmetric - with RealmEntity, RealmObjectBase, AsymmetricObject { - Asymmetric( - ObjectId id, { - Symmetric? symmetric, - Iterable embeddedObjects = const [], - }) { - RealmObjectBase.set(this, '_id', id); - RealmObjectBase.set(this, 'symmetric', symmetric); - RealmObjectBase.set>( - this, 'embeddedObjects', RealmList(embeddedObjects)); - } - - Asymmetric._(); - - @override - ObjectId get id => RealmObjectBase.get(this, '_id') as ObjectId; - @override - set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); - - @override - Symmetric? get symmetric => - RealmObjectBase.get(this, 'symmetric') as Symmetric?; - @override - set symmetric(covariant Symmetric? value) => - RealmObjectBase.set(this, 'symmetric', value); - - @override - RealmList get embeddedObjects => - RealmObjectBase.get(this, 'embeddedObjects') - as RealmList; - @override - set embeddedObjects(covariant RealmList value) => - throw RealmUnsupportedSetError(); - - @override - Stream> get changes => - RealmObjectBase.getChanges(this); - - @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); - - @override - Asymmetric freeze() => RealmObjectBase.freezeObject(this); - - EJsonValue toEJson() { - return { - '_id': id.toEJson(), - 'symmetric': symmetric.toEJson(), - 'embeddedObjects': embeddedObjects.toEJson(), - }; - } - - static EJsonValue _toEJson(Asymmetric value) => value.toEJson(); - static Asymmetric _fromEJson(EJsonValue ejson) { - if (ejson is! Map) return raiseInvalidEJson(ejson); - return switch (ejson) { - { - '_id': EJsonValue id, - } => - Asymmetric( - fromEJson(id), - symmetric: fromEJson(ejson['symmetric']), - embeddedObjects: fromEJson(ejson['embeddedObjects']), - ), - _ => raiseInvalidEJson(ejson), - }; - } - - static final schema = () { - RealmObjectBase.registerFactory(Asymmetric._); - register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.asymmetricObject, Asymmetric, 'Asymmetric', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('symmetric', RealmPropertyType.object, - optional: true, linkTarget: 'Symmetric'), - SchemaProperty('embeddedObjects', RealmPropertyType.object, - linkTarget: 'Embedded', collectionType: RealmCollectionType.list), - ]); - }(); - - @override - SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; -} - -class Embedded extends _Embedded - with RealmEntity, RealmObjectBase, EmbeddedObject { +class Embedded extends _Embedded with RealmEntity, RealmObjectBase, EmbeddedObject { Embedded( int value, { RealmValue any = const RealmValue.nullValue(), @@ -3596,25 +2935,20 @@ class Embedded extends _Embedded set value(int value) => RealmObjectBase.set(this, 'value', value); @override - RealmValue get any => - RealmObjectBase.get(this, 'any') as RealmValue; + RealmValue get any => RealmObjectBase.get(this, 'any') as RealmValue; @override set any(RealmValue value) => RealmObjectBase.set(this, 'any', value); @override - Symmetric? get symmetric => - RealmObjectBase.get(this, 'symmetric') as Symmetric?; + Symmetric? get symmetric => RealmObjectBase.get(this, 'symmetric') as Symmetric?; @override - set symmetric(covariant Symmetric? value) => - RealmObjectBase.set(this, 'symmetric', value); + set symmetric(covariant Symmetric? value) => RealmObjectBase.set(this, 'symmetric', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Embedded freeze() => RealmObjectBase.freezeObject(this); @@ -3649,8 +2983,7 @@ class Embedded extends _Embedded return const SchemaObject(ObjectType.embeddedObject, Embedded, 'Embedded', [ SchemaProperty('value', RealmPropertyType.int), SchemaProperty('any', RealmPropertyType.mixed, optional: true), - SchemaProperty('symmetric', RealmPropertyType.object, - optional: true, linkTarget: 'Symmetric'), + SchemaProperty('symmetric', RealmPropertyType.object, optional: true, linkTarget: 'Symmetric'), ]); }(); @@ -3658,8 +2991,7 @@ class Embedded extends _Embedded SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class Symmetric extends _Symmetric - with RealmEntity, RealmObjectBase, RealmObject { +class Symmetric extends _Symmetric with RealmEntity, RealmObjectBase, RealmObject { Symmetric( ObjectId id, ) { @@ -3674,12 +3006,10 @@ class Symmetric extends _Symmetric set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override Symmetric freeze() => RealmObjectBase.freezeObject(this); @@ -3708,8 +3038,7 @@ class Symmetric extends _Symmetric RealmObjectBase.registerFactory(Symmetric._); register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Symmetric, 'Symmetric', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), ]); }(); @@ -3717,8 +3046,7 @@ class Symmetric extends _Symmetric SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class ObjectWithRealmValue extends _ObjectWithRealmValue - with RealmEntity, RealmObjectBase, RealmObject { +class ObjectWithRealmValue extends _ObjectWithRealmValue with RealmEntity, RealmObjectBase, RealmObject { ObjectWithRealmValue( ObjectId id, { ObjectId? differentiator, @@ -3730,12 +3058,9 @@ class ObjectWithRealmValue extends _ObjectWithRealmValue RealmObjectBase.set(this, '_id', id); RealmObjectBase.set(this, 'differentiator', differentiator); RealmObjectBase.set(this, 'oneAny', oneAny); - RealmObjectBase.set>( - this, 'manyAny', RealmList(manyAny)); - RealmObjectBase.set>( - this, 'dictOfAny', RealmMap(dictOfAny)); - RealmObjectBase.set>( - this, 'setOfAny', RealmSet(setOfAny)); + RealmObjectBase.set>(this, 'manyAny', RealmList(manyAny)); + RealmObjectBase.set>(this, 'dictOfAny', RealmMap(dictOfAny)); + RealmObjectBase.set>(this, 'setOfAny', RealmSet(setOfAny)); } ObjectWithRealmValue._(); @@ -3746,52 +3071,38 @@ class ObjectWithRealmValue extends _ObjectWithRealmValue set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - ObjectId? get differentiator => - RealmObjectBase.get(this, 'differentiator') as ObjectId?; + ObjectId? get differentiator => RealmObjectBase.get(this, 'differentiator') as ObjectId?; @override - set differentiator(ObjectId? value) => - RealmObjectBase.set(this, 'differentiator', value); + set differentiator(ObjectId? value) => RealmObjectBase.set(this, 'differentiator', value); @override - RealmValue get oneAny => - RealmObjectBase.get(this, 'oneAny') as RealmValue; + RealmValue get oneAny => RealmObjectBase.get(this, 'oneAny') as RealmValue; @override set oneAny(RealmValue value) => RealmObjectBase.set(this, 'oneAny', value); @override - RealmList get manyAny => - RealmObjectBase.get(this, 'manyAny') as RealmList; + RealmList get manyAny => RealmObjectBase.get(this, 'manyAny') as RealmList; @override - set manyAny(covariant RealmList value) => - throw RealmUnsupportedSetError(); + set manyAny(covariant RealmList value) => throw RealmUnsupportedSetError(); @override - RealmMap get dictOfAny => - RealmObjectBase.get(this, 'dictOfAny') - as RealmMap; + RealmMap get dictOfAny => RealmObjectBase.get(this, 'dictOfAny') as RealmMap; @override - set dictOfAny(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set dictOfAny(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override - RealmSet get setOfAny => - RealmObjectBase.get(this, 'setOfAny') as RealmSet; + RealmSet get setOfAny => RealmObjectBase.get(this, 'setOfAny') as RealmSet; @override - set setOfAny(covariant RealmSet value) => - throw RealmUnsupportedSetError(); + set setOfAny(covariant RealmSet value) => throw RealmUnsupportedSetError(); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override - ObjectWithRealmValue freeze() => - RealmObjectBase.freezeObject(this); + ObjectWithRealmValue freeze() => RealmObjectBase.freezeObject(this); EJsonValue toEJson() { return { @@ -3826,20 +3137,13 @@ class ObjectWithRealmValue extends _ObjectWithRealmValue static final schema = () { RealmObjectBase.registerFactory(ObjectWithRealmValue._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, ObjectWithRealmValue, 'ObjectWithRealmValue', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('differentiator', RealmPropertyType.objectid, - optional: true), - SchemaProperty('oneAny', RealmPropertyType.mixed, - optional: true, indexType: RealmIndexType.regular), - SchemaProperty('manyAny', RealmPropertyType.mixed, - optional: true, collectionType: RealmCollectionType.list), - SchemaProperty('dictOfAny', RealmPropertyType.mixed, - optional: true, collectionType: RealmCollectionType.map), - SchemaProperty('setOfAny', RealmPropertyType.mixed, - optional: true, collectionType: RealmCollectionType.set), + return const SchemaObject(ObjectType.realmObject, ObjectWithRealmValue, 'ObjectWithRealmValue', [ + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), + SchemaProperty('differentiator', RealmPropertyType.objectid, optional: true), + SchemaProperty('oneAny', RealmPropertyType.mixed, optional: true, indexType: RealmIndexType.regular), + SchemaProperty('manyAny', RealmPropertyType.mixed, optional: true, collectionType: RealmCollectionType.list), + SchemaProperty('dictOfAny', RealmPropertyType.mixed, optional: true, collectionType: RealmCollectionType.map), + SchemaProperty('setOfAny', RealmPropertyType.mixed, optional: true, collectionType: RealmCollectionType.set), ]); }(); @@ -3847,8 +3151,7 @@ class ObjectWithRealmValue extends _ObjectWithRealmValue SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; } -class ObjectWithInt extends _ObjectWithInt - with RealmEntity, RealmObjectBase, RealmObject { +class ObjectWithInt extends _ObjectWithInt with RealmEntity, RealmObjectBase, RealmObject { static var _defaultsSet = false; ObjectWithInt( @@ -3874,11 +3177,9 @@ class ObjectWithInt extends _ObjectWithInt set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); @override - ObjectId? get differentiator => - RealmObjectBase.get(this, 'differentiator') as ObjectId?; + ObjectId? get differentiator => RealmObjectBase.get(this, 'differentiator') as ObjectId?; @override - set differentiator(ObjectId? value) => - RealmObjectBase.set(this, 'differentiator', value); + set differentiator(ObjectId? value) => RealmObjectBase.set(this, 'differentiator', value); @override int get i => RealmObjectBase.get(this, 'i') as int; @@ -3886,13 +3187,10 @@ class ObjectWithInt extends _ObjectWithInt set i(int value) => RealmObjectBase.set(this, 'i', value); @override - Stream> get changes => - RealmObjectBase.getChanges(this); + Stream> get changes => RealmObjectBase.getChanges(this); @override - Stream> changesFor( - [List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); + Stream> changesFor([List? keyPaths]) => RealmObjectBase.getChangesFor(this, keyPaths); @override ObjectWithInt freeze() => RealmObjectBase.freezeObject(this); @@ -3924,12 +3222,9 @@ class ObjectWithInt extends _ObjectWithInt static final schema = () { RealmObjectBase.registerFactory(ObjectWithInt._); register(_toEJson, _fromEJson); - return const SchemaObject( - ObjectType.realmObject, ObjectWithInt, 'ObjectWithInt', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('differentiator', RealmPropertyType.objectid, - optional: true), + return const SchemaObject(ObjectType.realmObject, ObjectWithInt, 'ObjectWithInt', [ + SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), + SchemaProperty('differentiator', RealmPropertyType.objectid, optional: true), SchemaProperty('i', RealmPropertyType.int), ]); }(); diff --git a/packages/realm_dart/test/user_test.dart b/packages/realm_dart/test/user_test.dart deleted file mode 100644 index 082304074..000000000 --- a/packages/realm_dart/test/user_test.dart +++ /dev/null @@ -1,479 +0,0 @@ -// Copyright 2022 MongoDB, Inc. -// SPDX-License-Identifier: Apache-2.0 - -import 'dart:async'; -import 'dart:isolate'; - -import 'package:realm_dart/realm.dart'; - -import 'test.dart'; - -void main() { - setupTests(); - - baasTest('User logout anon user is marked as removed', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.anonymous()); - expect(user.state, UserState.loggedIn); - await user.logOut(); - expect(user.state, UserState.removed); - }); - - baasTest('User logout', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - expect(user.state, UserState.loggedIn); - await user.logOut(); - expect(user.state, UserState.loggedOut); - }); - - baasTest('User get id', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - expect(user.id, isNotEmpty); - }); - - baasTest('User get identities', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - //singleWhere throws an exception if not found - expect(user.identities.singleWhere((identity) => identity.provider == AuthProviderType.emailPassword), isA()); - }); - - baasTest('User get customdata', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - expect(user.customData, isNull); - }); - - baasTest('User refresh customdata', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - final dynamic data = await user.refreshCustomData(); - expect(data, isNull); - }); - - baasTest('User link credentials', (configuration) async { - final app = App(configuration); - final user1 = await getAnonymousUser(app); - - expect(user1.state, UserState.loggedIn); - expect(user1.identities.length, 1); - expect(user1.identities.singleWhere((identity) => identity.provider == AuthProviderType.anonymous), isA()); - - final authProvider = EmailPasswordAuthProvider(app); - final username = getAutoverifiedEmail(); - final password = generateRandomString(8); - await authProvider.registerUser(username, password); - - await user1.linkCredentials(Credentials.emailPassword(username, password)); - expect(user1.identities.length, 2); - expect(user1.identities.singleWhere((identity) => identity.provider == AuthProviderType.emailPassword), isA()); - expect(user1.identities.singleWhere((identity) => identity.provider == AuthProviderType.anonymous), isA()); - - final user2 = await app.logIn(Credentials.emailPassword(username, password)); - expect(user1, user2); - }); - - baasTest('User deviceId', (configuration) async { - final app = App(configuration); - final credentials = Credentials.anonymous(); - final user = await app.logIn(credentials); - expect(user.deviceId, isNotNull); - user.logOut(); - expect(user.deviceId, isNotNull); - }); - - baasTest('User profile', (configuration) async { - final app = App(configuration); - final user = await app.logIn(Credentials.emailPassword(testUsername, testPassword)); - expect(user.profile.email, testUsername); - }); - - Future createAndVerifyApiKey(User user, String name) async { - final result = await user.apiKeys.create(name); - await waitForConditionWithResult(() => user.apiKeys.fetch(result.id), (fetched) => fetched != null, timeout: Duration(seconds: 15)); - return result; - } - - Future enableAndVerifyApiKey(User user, ObjectId keyId) async { - await user.apiKeys.enable(keyId); - await waitForConditionWithResult(() => user.apiKeys.fetch(keyId), (fetched) => fetched!.isEnabled, timeout: Duration(seconds: 15)); - } - - Future disableAndVerifyApiKey(User user, ObjectId keyId) async { - await user.apiKeys.disable(keyId); - await waitForConditionWithResult(() => user.apiKeys.fetch(keyId), (fetched) => !fetched!.isEnabled, timeout: Duration(seconds: 15)); - } - - Future deleteAndVerifyApiKey(User user, ObjectId keyId) async { - await user.apiKeys.delete(keyId); - await waitForConditionWithResult(() => user.apiKeys.fetch(keyId), (fetched) => fetched == null, timeout: Duration(seconds: 15)); - } - - baasTest('User.apiKeys.create creates and reveals value', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final apiKey = await createAndVerifyApiKey(user, 'my-api-key'); - - expect(apiKey.isEnabled, true); - expect(apiKey.name, 'my-api-key'); - expect(apiKey.value, isNotNull); - expect(apiKey.id, isNot(ObjectId.fromValues(0, 0, 0))); - }); - - baasTest('User.apiKeys.create on background isolate', (configuration) async { - // This test is to ensure that the API key creation works on a background isolate. - // It was introduced due to: https://github.com/realm/realm-dart/issues/1467 - await getIntegrationUser(appConfig: configuration); - final appId = configuration.appId; - expect(Isolate.run(() async { - final app = App.getById(appId)!; - final user = app.currentUser!; - await createAndVerifyApiKey(user, 'my-api-key'); // <-- this would crash before the fix - }), completes); - }); - - baasTest('User.apiKeys.create with invalid name returns error', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - await expectLater( - () => user.apiKeys.create('Spaces are not allowed'), - throwsA(isA() - .having((e) => e.message, 'message', contains('can only contain ASCII letters, numbers, underscores, and hyphens')) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')) - .having((e) => e.statusCode, 'statusCode', 400))); - }); - - baasTest('User.apiKeys.create with duplicate name returns error', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - await user.apiKeys.create('my-api-key'); - await expectLater( - () => user.apiKeys.create('my-api-key'), - throwsA(isA() - .having((e) => e.message, 'message', contains('API key with name already exists')) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')) - .having((e) => e.statusCode, 'statusCode', 409))); - }); - - baasTest('User.apiKeys.fetch with non existent returns null', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final key = await user.apiKeys.fetch(ObjectId()); - expect(key, isNull); - }); - - void expectApiKey(ApiKey? fetched, ApiKey expected, [bool created = false]) { - expect(fetched, isNotNull); - expect(fetched!.id, expected.id); - expect(fetched.isEnabled, expected.isEnabled); - expect(fetched.name, expected.name); - expect(fetched.value, isNull); - } - - baasTest('User.apiKeys.fetch with existent returns result', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final apiKey = await createAndVerifyApiKey(user, 'my-api-key'); - - final refetched = await user.apiKeys.fetch(apiKey.id); - - expectApiKey(refetched, apiKey); - }); - - baasTest('User.apiKeys.fetchAll with no keys returns empty', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - final apiKeys = await user.apiKeys.fetchAll(); - - expect(apiKeys, isEmpty); - }); - - baasTest('User.apiKeys.fetchAll from background isolate', (configuration) async { - // This test is to ensure that the API key creation works on a background isolate. - // It was introduced due to: https://github.com/realm/realm-dart/issues/1467 - await getIntegrationUser(appConfig: configuration); - final appId = configuration.appId; - expect(Isolate.run(() async { - final app = App.getById(appId)!; - final user = app.currentUser!; - user.apiKeys.fetchAll(); // <-- this would crash before the fix - }), completes); - }); - - baasTest('User.apiKeys.fetchAll with one key returns it', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final original = await createAndVerifyApiKey(user, 'my-api-key'); - - final apiKeys = await user.apiKeys.fetchAll(); - - expect(apiKeys, hasLength(1)); - expectApiKey(apiKeys.single, original); - }); - - baasTest('User.apiKeys.fetchAll with multiple keys returns all', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final original = []; - for (var i = 0; i < 5; i++) { - original.add(await createAndVerifyApiKey(user, 'my-api-key-$i')); - } - - final fetched = await user.apiKeys.fetchAll(); - - for (var i = 0; i < 5; i++) { - final fetchedKey = fetched.singleWhere((key) => key.id == original[i].id); - expectApiKey(fetchedKey, original[i]); - } - }); - - baasTest('User.apiKeys.delete with non-existent key', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final key = await createAndVerifyApiKey(user, 'key'); - - await user.apiKeys.delete(ObjectId()); - - final allKeys = await user.apiKeys.fetchAll(); - expect(allKeys, hasLength(1)); - expectApiKey(allKeys.single, key); - }); - - baasTest('User.apiKeys.delete with existent key', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final toDelete = await createAndVerifyApiKey(user, 'to-delete'); - final toRemain = await createAndVerifyApiKey(user, 'to-remain'); - - await deleteAndVerifyApiKey(user, toDelete.id); - - final fetched = await user.apiKeys.fetch(toDelete.id); - expect(fetched, isNull); - - final allKeys = await user.apiKeys.fetchAll(); - expect(allKeys, hasLength(1)); - expectApiKey(allKeys.single, toRemain); - }); - - baasTest('User.apiKeys.disable with non-existent throws', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - await expectLater( - () => user.apiKeys.disable(ObjectId()), - throwsA(isA() - .having((e) => e.message, 'message', contains("doesn't exist")) - .having((e) => e.statusCode, 'statusCode', 404) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); - }); - - baasTest('User.apiKeys.enable with non-existent throws', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - await expectLater( - () => user.apiKeys.enable(ObjectId()), - throwsA(isA() - .having((e) => e.message, 'message', contains("doesn't exist")) - .having((e) => e.statusCode, 'statusCode', 404) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); - }); - - baasTest('User.apiKeys.enable when enabled is a no-op', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final key = await createAndVerifyApiKey(user, 'my-key'); - - expect(key.isEnabled, true); - - await user.apiKeys.enable(key.id); - - final fetched = await user.apiKeys.fetch(key.id); - - expect(fetched!.isEnabled, true); - }); - - baasTest('User.apiKeys.disable when disabled is a no-op', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final key = await createAndVerifyApiKey(user, 'my-key'); - - expect(key.isEnabled, true); - - await disableAndVerifyApiKey(user, key.id); - - final fetched = await user.apiKeys.fetch(key.id); - expect(fetched!.isEnabled, false); - - await user.apiKeys.disable(key.id); - - final refetched = await user.apiKeys.fetch(key.id); - expect(refetched!.isEnabled, false); - }); - - baasTest('User.apiKeys.disable disables key', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final first = await createAndVerifyApiKey(user, 'first'); - final second = await createAndVerifyApiKey(user, 'second'); - - expect(first.isEnabled, true); - expect(second.isEnabled, true); - - await disableAndVerifyApiKey(user, first.id); - - final fetched = await user.apiKeys.fetchAll(); - - final fetchedFirst = fetched.singleWhere((key) => key.id == first.id); - expect(fetchedFirst.isEnabled, false); - - final fetchedSecond = fetched.singleWhere((key) => key.id == second.id); - expect(fetchedSecond.isEnabled, true); - }); - - baasTest('User.apiKeys.enable reenables key', (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - final first = await createAndVerifyApiKey(user, 'first'); - final second = await createAndVerifyApiKey(user, 'second'); - - expect(first.isEnabled, true); - expect(second.isEnabled, true); - - await disableAndVerifyApiKey(user, first.id); - - final fetched = await user.apiKeys.fetchAll(); - - final fetchedFirst = fetched.singleWhere((key) => key.id == first.id); - expect(fetchedFirst.isEnabled, false); - - final fetchedSecond = fetched.singleWhere((key) => key.id == second.id); - expect(fetchedSecond.isEnabled, true); - - await enableAndVerifyApiKey(user, first.id); - - final refetched = await user.apiKeys.fetchAll(); - - final refetchedFirst = refetched.singleWhere((k) => k.id == first.id); - expect(refetchedFirst.isEnabled, true); - - final refetchedSecond = refetched.singleWhere((k) => k.id == second.id); - expect(refetchedSecond.isEnabled, true); - }); - - baasTest('User.apiKeys can login with generated key', (configuration) async { - final app = App(configuration); - final user = await getIntegrationUser(app: app); - - final key = await createAndVerifyApiKey(user, 'my-key'); - - final credentials = Credentials.apiKey(key.value!); - - final apiKeyUser = await app.logIn(credentials); - expect(apiKeyUser.id, user.id); - }); - - baasTest('User.apiKeys can login with reenabled key', (configuration) async { - final app = App(configuration); - final user = await getIntegrationUser(app: app); - - final key = await createAndVerifyApiKey(user, 'my-key'); - - await disableAndVerifyApiKey(user, key.id); - - final credentials = Credentials.apiKey(key.value!); - - await expectLater( - () => app.logIn(credentials), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); - - await enableAndVerifyApiKey(user, key.id); - - final apiKeyUser = await app.logIn(credentials); - expect(apiKeyUser.id, user.id); - }); - - baasTest("User.apiKeys can't login with deleted key", (configuration) async { - final app = App(configuration); - final user = await getIntegrationUser(app: app); - - final key = await createAndVerifyApiKey(user, 'my-key'); - - await deleteAndVerifyApiKey(user, key.id); - - final credentials = Credentials.apiKey(key.value!); - - await expectLater( - () => app.logIn(credentials), - throwsA(isA() - .having((e) => e.message, 'message', equals('unauthorized')) - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); - }); - - baasTest("User.apiKeys when user is logged out throws", (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - await user.logOut(); - - expect(() => user.apiKeys, throws('User must be logged in to access API keys')); - }); - - baasTest("User.apiKeys.anyMethod when user is logged out throws", (configuration) async { - final user = await getIntegrationUser(appConfig: configuration); - - // Store in a temp variable as accessing the property will throw - final apiKeys = user.apiKeys; - await user.logOut(); - - await expectLater(() => apiKeys.create('foo'), throws('User must be logged in to create an API key')); - await expectLater(() => apiKeys.delete(ObjectId()), throws('User must be logged in to delete an API key')); - await expectLater(() => apiKeys.disable(ObjectId()), throws('User must be logged in to disable an API key')); - await expectLater(() => apiKeys.enable(ObjectId()), throws('User must be logged in to enable an API key')); - await expectLater(() => apiKeys.fetch(ObjectId()), throws('User must be logged in to fetch an API key')); - await expectLater(() => apiKeys.fetchAll(), throws('User must be logged in to fetch all API keys')); - }); - - baasTest("Credentials.apiKey with server-generated can login user", (configuration) async { - final app = App(configuration); - - final apiKey = await baasHelper!.createServerApiKey(app, ObjectId().toString()); - final credentials = Credentials.apiKey(apiKey); - - final apiKeyUser = await app.logIn(credentials); - - expect(apiKeyUser.state, UserState.loggedIn); - }); - - baasTest("Credentials.apiKey with disabled server api key throws an error", (configuration) async { - final app = App(configuration); - - final apiKey = await baasHelper!.createServerApiKey(app, ObjectId().toString(), enabled: false); - final credentials = Credentials.apiKey(apiKey); - - await expectLater( - () async => await app.logIn(credentials), - throwsA(isA() - .having((e) => e.message, 'message', 'unauthorized') - .having((e) => e.statusCode, 'statusCode', 401) - .having((e) => e.linkToServerLogs, 'linkToServerLogs', contains('logs?co_id=')))); - }); - - baasTest('User.logOut raises changes', (appConfig) async { - final user = await getIntegrationUser(appConfig: appConfig); - - expect(user.state, UserState.loggedIn); - - final completer = Completer(); - final subscription = user.changes.listen((event) { - completer.complete(event); - }); - - await user.logOut(); - - expect(user.state, UserState.loggedOut); - - final changeEvent = await completer.future.timeout(Duration(seconds: 15)); - expect(changeEvent.user, user); - expect(changeEvent.user.state, UserState.loggedOut); - - await subscription.cancel(); - }); -} diff --git a/packages/realm_generator/lib/src/class_element_ex.dart b/packages/realm_generator/lib/src/class_element_ex.dart index 4f35d4b55..52fc22665 100644 --- a/packages/realm_generator/lib/src/class_element_ex.dart +++ b/packages/realm_generator/lib/src/class_element_ex.dart @@ -155,53 +155,6 @@ extension ClassElementEx on ClassElement { todo: 'Remove the @PrimaryKey annotation from the field or set the model type to a value different from ObjectType.embeddedObject.'); } - // TODO: - // What follows is the least intrusive handling of invariants for asymmetric - // objects I could come up with. - // - // Really this calls for a bigger refactoring of the generator code where we - // build a graph of RealmModelInfo and RealmFieldInfo, but I have multiple - // PRs inflight that touches this code, so I will defer the refactoring until - // they have landed. - - // Check that no objects have links to asymmetric objects. - for (final field in mappedFields) { - final fieldElement = field.fieldElement; - final classElement = fieldElement.type.basicType.element as ClassElement; - if (classElement.thisType.isRealmModelOfType(ObjectType.asymmetricObject)) { - throw RealmInvalidGenerationSourceError( - 'Linking to asymmetric objects is not allowed', - todo: 'Remove the field', - element: fieldElement, - ); - } - } - - // Check that asymmetric objects have a primary key named _id. - if (objectType == ObjectType.asymmetricObject) { - var hasPrimaryKey = false; - for (final field in mappedFields) { - final fieldElement = field.fieldElement; - if (field.isPrimaryKey) { - hasPrimaryKey = true; - if (field.realmName != '_id') { - throw RealmInvalidGenerationSourceError( - 'Asymmetric objects must have a primary key named _id', - todo: 'Add @MapTo("_id") to the @PrimaryKey field', - element: fieldElement, - ); - } - } - } - if (!hasPrimaryKey) { - throw RealmInvalidGenerationSourceError( - 'Asymmetric objects must have a primary key named _id', - todo: 'Add a primary key named _id', - element: this, - ); - } - } - // Get the generator configuration final index = realmModelInfo?.value.getField('generatorConfig')?.getField('ctorStyle')?.getField('index')?.toIntValue(); final ctorStyle = index != null ? CtorStyle.values[index] : CtorStyle.onlyOptionalNamed; diff --git a/packages/realm_generator/test/error_test_data/asymmetric_external_link.dart b/packages/realm_generator/test/error_test_data/asymmetric_external_link.dart deleted file mode 100644 index b61986aef..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_external_link.dart +++ /dev/null @@ -1,13 +0,0 @@ -import 'package:realm_common/realm_common.dart'; - -@RealmModel(ObjectType.asymmetricObject) -class _Asymmetric { - @PrimaryKey() - @MapTo('_id') - late ObjectId id; -} - -@RealmModel() -class _Bad { - _Asymmetric? asymmetric; -} diff --git a/packages/realm_generator/test/error_test_data/asymmetric_external_link.expected b/packages/realm_generator/test/error_test_data/asymmetric_external_link.expected deleted file mode 100644 index f49cfb0e9..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_external_link.expected +++ /dev/null @@ -1,12 +0,0 @@ -Linking to asymmetric objects is not allowed - -in: asset:pkg/test/error_test_data/asymmetric_external_link.dart:12:16 - ╷ -10 │ @RealmModel() -11 │ class _Bad { - │ ━━━━ in realm model for 'Bad' -12 │ _Asymmetric? asymmetric; - │ ^^^^^^^^^^ ! - ╵ -Remove the field - diff --git a/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.dart b/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.dart deleted file mode 100644 index 3cfe57a64..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:realm_common/realm_common.dart'; - -@RealmModel(ObjectType.asymmetricObject) -class _BadAsymmetric { - // missing @PrimaryKey() - @MapTo('_id') - late ObjectId id; -} diff --git a/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.expected b/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.expected deleted file mode 100644 index 0ccc2c30e..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_missing_pk.expected +++ /dev/null @@ -1,10 +0,0 @@ -Asymmetric objects must have a primary key named _id - -in: asset:pkg/test/error_test_data/asymmetric_missing_pk.dart:4:7 - ╷ -3 │ @RealmModel(ObjectType.asymmetricObject) -4 │ class _BadAsymmetric { - │ ^^^^^^^^^^^^^^ - ╵ -Add a primary key named _id - diff --git a/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.dart b/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.dart deleted file mode 100644 index 06ca2d546..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:realm_common/realm_common.dart'; - -@RealmModel(ObjectType.asymmetricObject) -class _BadAsymmetric { - @PrimaryKey() - late ObjectId wrongName; -} diff --git a/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.expected b/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.expected deleted file mode 100644 index 588e1f3eb..000000000 --- a/packages/realm_generator/test/error_test_data/asymmetric_wrong_pk.expected +++ /dev/null @@ -1,13 +0,0 @@ -Asymmetric objects must have a primary key named _id - -in: asset:pkg/test/error_test_data/asymmetric_wrong_pk.dart:6:17 - ╷ -3 │ @RealmModel(ObjectType.asymmetricObject) -4 │ class _BadAsymmetric { - │ ━━━━━━━━━━━━━━ in realm model for 'BadAsymmetric' -5 │ @PrimaryKey() -6 │ late ObjectId wrongName; - │ ^^^^^^^^^ ! - ╵ -Add @MapTo("_id") to the @PrimaryKey field - diff --git a/packages/realm_generator/test/good_test_data/asymmetric_object.dart b/packages/realm_generator/test/good_test_data/asymmetric_object.dart deleted file mode 100644 index 319059fe6..000000000 --- a/packages/realm_generator/test/good_test_data/asymmetric_object.dart +++ /dev/null @@ -1,20 +0,0 @@ -import 'package:realm_common/realm_common.dart'; - -part 'asymmetric_object.realm.dart'; - -@RealmModel() -class _Asymmetric { - @PrimaryKey() - @MapTo('_id') - late ObjectId id; - - late List<_Embedded> children; - late _Embedded? father; - late _Embedded? mother; -} - -@RealmModel(ObjectType.embeddedObject) -class _Embedded { - late String name; - late int age; -} diff --git a/packages/realm_generator/test/good_test_data/asymmetric_object.expected b/packages/realm_generator/test/good_test_data/asymmetric_object.expected deleted file mode 100644 index 8f20a3342..000000000 --- a/packages/realm_generator/test/good_test_data/asymmetric_object.expected +++ /dev/null @@ -1,176 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'asymmetric_object.dart'; - -// ************************************************************************** -// RealmObjectGenerator -// ************************************************************************** - -// ignore_for_file: type=lint -class Asymmetric extends _Asymmetric - with RealmEntity, RealmObjectBase, RealmObject { - Asymmetric( - ObjectId id, { - Iterable children = const [], - Embedded? father, - Embedded? mother, - }) { - RealmObjectBase.set(this, '_id', id); - RealmObjectBase.set>( - this, 'children', RealmList(children)); - RealmObjectBase.set(this, 'father', father); - RealmObjectBase.set(this, 'mother', mother); - } - - Asymmetric._(); - - @override - ObjectId get id => RealmObjectBase.get(this, '_id') as ObjectId; - @override - set id(ObjectId value) => RealmObjectBase.set(this, '_id', value); - - @override - RealmList get children => - RealmObjectBase.get(this, 'children') as RealmList; - @override - set children(covariant RealmList value) => - throw RealmUnsupportedSetError(); - - @override - Embedded? get father => - RealmObjectBase.get(this, 'father') as Embedded?; - @override - set father(covariant Embedded? value) => - RealmObjectBase.set(this, 'father', value); - - @override - Embedded? get mother => - RealmObjectBase.get(this, 'mother') as Embedded?; - @override - set mother(covariant Embedded? value) => - RealmObjectBase.set(this, 'mother', value); - - @override - Stream> get changes => - RealmObjectBase.getChanges(this); - - @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); - - @override - Asymmetric freeze() => RealmObjectBase.freezeObject(this); - - EJsonValue toEJson() { - return { - '_id': id.toEJson(), - 'children': children.toEJson(), - 'father': father.toEJson(), - 'mother': mother.toEJson(), - }; - } - - static EJsonValue _toEJson(Asymmetric value) => value.toEJson(); - static Asymmetric _fromEJson(EJsonValue ejson) { - if (ejson is! Map) return raiseInvalidEJson(ejson); - return switch (ejson) { - { - '_id': EJsonValue id, - } => - Asymmetric( - fromEJson(id), - children: fromEJson(ejson['children']), - father: fromEJson(ejson['father']), - mother: fromEJson(ejson['mother']), - ), - _ => raiseInvalidEJson(ejson), - }; - } - - static final schema = () { - RealmObjectBase.registerFactory(Asymmetric._); - register(_toEJson, _fromEJson); - return const SchemaObject(ObjectType.realmObject, Asymmetric, 'Asymmetric', [ - SchemaProperty('id', RealmPropertyType.objectid, - mapTo: '_id', primaryKey: true), - SchemaProperty('children', RealmPropertyType.object, - linkTarget: 'Embedded', collectionType: RealmCollectionType.list), - SchemaProperty('father', RealmPropertyType.object, - optional: true, linkTarget: 'Embedded'), - SchemaProperty('mother', RealmPropertyType.object, - optional: true, linkTarget: 'Embedded'), - ]); - }(); - - @override - SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; -} - -class Embedded extends _Embedded - with RealmEntity, RealmObjectBase, EmbeddedObject { - Embedded( - String name, - int age, - ) { - RealmObjectBase.set(this, 'name', name); - RealmObjectBase.set(this, 'age', age); - } - - Embedded._(); - - @override - String get name => RealmObjectBase.get(this, 'name') as String; - @override - set name(String value) => RealmObjectBase.set(this, 'name', value); - - @override - int get age => RealmObjectBase.get(this, 'age') as int; - @override - set age(int value) => RealmObjectBase.set(this, 'age', value); - - @override - Stream> get changes => - RealmObjectBase.getChanges(this); - - @override - Stream> changesFor([List? keyPaths]) => - RealmObjectBase.getChangesFor(this, keyPaths); - - @override - Embedded freeze() => RealmObjectBase.freezeObject(this); - - EJsonValue toEJson() { - return { - 'name': name.toEJson(), - 'age': age.toEJson(), - }; - } - - static EJsonValue _toEJson(Embedded value) => value.toEJson(); - static Embedded _fromEJson(EJsonValue ejson) { - if (ejson is! Map) return raiseInvalidEJson(ejson); - return switch (ejson) { - { - 'name': EJsonValue name, - 'age': EJsonValue age, - } => - Embedded( - fromEJson(name), - fromEJson(age), - ), - _ => raiseInvalidEJson(ejson), - }; - } - - static final schema = () { - RealmObjectBase.registerFactory(Embedded._); - register(_toEJson, _fromEJson); - return const SchemaObject(ObjectType.embeddedObject, Embedded, 'Embedded', [ - SchemaProperty('name', RealmPropertyType.string), - SchemaProperty('age', RealmPropertyType.int), - ]); - }(); - - @override - SchemaObject get objectSchema => RealmObjectBase.getSchema(this) ?? schema; -} diff --git a/packages/realm_generator/test/good_test_data/asymmetric_object.realm.dart b/packages/realm_generator/test/good_test_data/asymmetric_object.realm.dart deleted file mode 100644 index cfbe7ba16..000000000 --- a/packages/realm_generator/test/good_test_data/asymmetric_object.realm.dart +++ /dev/null @@ -1,4 +0,0 @@ -// MOCK FILE! This file exists to ensure the parent file is valid Dart. -// The parent will be used as input to the realm_generator in a test, and the -// output compared to the .expected file. -part of 'asymmetric_object.dart';