diff --git a/.github/workflows/binary-combine-android.yml b/.github/workflows/binary-combine-android.yml index 5e2f20ecb..d41d28c78 100644 --- a/.github/workflows/binary-combine-android.yml +++ b/.github/workflows/binary-combine-android.yml @@ -10,38 +10,39 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch x86 build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-android-x86 path: packages/realm_dart/binary/android - name: Fetch x86_64 build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-android-x86_64 path: packages/realm_dart/binary/android - name: Fetch armeabi-v7a build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-android-armeabi-v7a path: packages/realm_dart/binary/android - name: Fetch arm64-v8a build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-android-arm64-v8a path: packages/realm_dart/binary/android - name: Store combined artifact - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb + uses: actions/upload-artifact@v4 with: name: librealm-android path: packages/realm_dart/binary/android retention-days: 1 - name: Delete individual build artifacts - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af + uses: geekyeggo/delete-artifact@v4 with: name: | librealm-android-x86 librealm-android-x86_64 librealm-android-armeabi-v7a - librealm-android-arm64-v8a \ No newline at end of file + librealm-android-arm64-v8a + failOnError: false diff --git a/.github/workflows/binary-combine-ios.yml b/.github/workflows/binary-combine-ios.yml index d2646f41e..3ebc2c9a7 100644 --- a/.github/workflows/binary-combine-ios.yml +++ b/.github/workflows/binary-combine-ios.yml @@ -11,17 +11,17 @@ jobs: steps: - name: Fetch device build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-ios-device path: binary/ios - name: Fetch simulator build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-ios-simulator path: binary/ios - name: Fetch catalyst build - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-ios-catalyst path: binary/ios @@ -36,16 +36,17 @@ jobs: rm -rf ./binary/ios/Release-* - name: Store .xcframework artifact - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb + uses: actions/upload-artifact@v4 with: name: librealm-ios path: binary/ios retention-days: 1 - name: Delete individual framework artifacts - uses: geekyeggo/delete-artifact@54ab544f12cdb7b71613a16a2b5a37a9ade990af + uses: geekyeggo/delete-artifact@v4 with: name: | librealm-ios-device librealm-ios-simulator librealm-ios-catalyst + failOnError: false diff --git a/.github/workflows/build-native.yml b/.github/workflows/build-native.yml index c880b3edb..b013d965e 100644 --- a/.github/workflows/build-native.yml +++ b/.github/workflows/build-native.yml @@ -30,7 +30,7 @@ jobs: build: ${{ fromJSON(inputs.build) }} steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: 'recursive' @@ -41,17 +41,18 @@ jobs: path: ./packages/realm_dart/binary/** key: binaries-${{ matrix.build }}-${{ inputs.runner }}-${{hashFiles('./packages/realm_dart/src/**')}} - - name: Setup Ninja - if: steps.check-cache.outputs.cache-hit != 'true' - uses: seanmiddleditch/gha-setup-ninja@1815f2d05c2cd60c2d900f89843139b8dde09f4c + if: steps.check-cache.outputs.cache-hit != 'true' && (startsWith(matrix.build, 'android') || startsWith(matrix.build, 'linux')) + run: | + sudo apt-get update -y + sudo apt-get install -y ninja-build - name: Setup Android NDK - if: startsWith(matrix.build, 'android-') + if: startsWith(matrix.build, 'android') run: echo "ANDROID_NDK=$ANDROID_NDK_LATEST_HOME" >> $GITHUB_ENV - name: Downgrade XCode for MacOS - if: ${{ matrix.build == 'macos' }} + if: matrix.build == 'macos' run: sudo xcode-select -s /Applications/Xcode_14.0.1.app - name: Build @@ -61,7 +62,7 @@ jobs: cmake --build --preset ${{ matrix.build }} --config Release ${{ startsWith(matrix.build, 'android-') && '--target strip' || '' }} - name: Store artifacts - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb + uses: actions/upload-artifact@v4 with: name: librealm-${{ matrix.build }} path: packages/realm_dart/binary/${{ inputs.binary }}/** diff --git a/.github/workflows/check-changelog.yml b/.github/workflows/check-changelog.yml index e23ae1751..9c856000b 100644 --- a/.github/workflows/check-changelog.yml +++ b/.github/workflows/check-changelog.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@8230315d06ad95c617244d2f265d237a1682d445 + uses: actions/checkout@v4 with: submodules: false - name: Enforce Changelog diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 80c6ad5f6..9f16a9122 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -294,7 +294,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: 'recursive' @@ -302,7 +302,7 @@ jobs: run: echo "PATH=/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" >> $GITHUB_ENV - name: Fetch artifacts - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-ios path: packages/realm_dart/binary/ios @@ -312,13 +312,18 @@ jobs: with: channel: 'stable' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Install dependencies run: dart pub get - name: Launch Simulator - uses: futureware-tech/simulator-action@v2 + uses: futureware-tech/simulator-action@v3 with: - model: 'iPhone 8' + model: 'iPhone SE (3rd generation)' os: 'iOS' os_version: '>= 14.0' @@ -331,7 +336,7 @@ jobs: --suppress-analytics - name: Publish Test Report - uses: dorny/test-reporter@v1.7.0 + uses: dorny/test-reporter@v1.8.0 if: success() || failure() with: name: Test Results Flutter iOS @@ -373,7 +378,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: 'recursive' @@ -384,16 +389,16 @@ jobs: sudo udevadm trigger --name-match=kvm - name: Gradle cache - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 - name: Set up Java - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: 11 - name: Fetch artifacts - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-android path: packages/realm_dart/binary/android @@ -403,6 +408,11 @@ jobs: with: channel: 'stable' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Install dependencies run: dart pub get @@ -447,7 +457,7 @@ jobs: 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 - name: Publish Test Report - uses: dorny/test-reporter@v1.7.0 + uses: dorny/test-reporter@v1.8.0 if: success() || failure() with: name: Test Results Flutter Android @@ -481,10 +491,11 @@ jobs: runs-on: ${{ matrix.os }}-latest name: Generator Tests + timeout-minutes: 30 steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: 'recursive' @@ -493,8 +504,15 @@ jobs: with: channel: 'stable' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Delete generated files in realm_dart - run: find . -name "*.realm.dart" -delete + run: | + find . -name "*.g.dart" -delete + find . -name "*.realm.dart" -delete working-directory: packages/realm_dart - name: Run generator in realm_dart @@ -533,43 +551,11 @@ jobs: exit 1 fi - - name: Run generator tests - run: | - dart pub get - dart test -r expanded --coverage ./coverage/ --test-randomize-ordering-seed random - - - name: Generate generator coverage report - if: matrix.os == 'ubuntu' - run: | - dart run coverage:format_coverage \ - --in coverage/ \ - --out ./coverage/lcov.info \ - --check-ignore \ - --lcov \ - --packages .dart_tool/package_config.json \ - --report-on lib - - - name: Publish Generator Coverage - if: matrix.os == 'ubuntu' - id: publish-coverage - uses: coverallsapp/github-action@f350da2c033043742f89e8c0b7b5145a1616da6d - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - flag-name: generator - path-to-lcov: packages/realm_generator/coverage/lcov.info - parallel: true - - - name: Output Coveralls response - if: matrix.os == 'ubuntu' - run: echo ${{ steps.publish-coverage.outputs.coveralls-api-result }} - coverage-finished: needs: - - generator - dart-tests-linux runs-on: ubuntu-latest steps: - - name: Coveralls Finished id: publish-coverage uses: coverallsapp/github-action@f350da2c033043742f89e8c0b7b5145a1616da6d @@ -577,9 +563,6 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} parallel-finished: true - - name: Output Coveralls response - run: echo ${{ steps.publish-coverage.outputs.coveralls-api-result }} - slack-on-failure: name: Report failure in main branch needs: diff --git a/.github/workflows/dart-desktop-tests.yml b/.github/workflows/dart-desktop-tests.yml index f71066670..0f4d80087 100644 --- a/.github/workflows/dart-desktop-tests.yml +++ b/.github/workflows/dart-desktop-tests.yml @@ -30,21 +30,15 @@ jobs: runs-on: ${{ inputs.runner }} name: Dart tests on ${{inputs.os }} ${{ inputs.architecture }} timeout-minutes: 45 - defaults: - run: - working-directory: packages/realm_dart steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false - - name: Cleanup Workspace - run: git clean -fdx - - name: Fetch artifacts - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-${{ inputs.os }} path: packages/realm_dart/binary/${{ inputs.os }} @@ -55,18 +49,22 @@ jobs: sdk: stable architecture: ${{ inputs.architecture == 'arm' && 'arm64' || 'x64'}} - - name: Install dependencies - run: dart pub get + - name: Setup Melos + run: | + dart pub global activate melos + melos bootstrap --no-flutter + melos setup - - name: Bump ulimit + - name: Bump ulimit on macos run: ulimit -n 10240 if: ${{ contains(inputs.os, 'macos') }} - name: Run tests - run: ${{ inputs.architecture == 'arm' && 'arch -arm64 ' || '' }}dart test -r expanded --coverage ./coverage/ -j 1 --test-randomize-ordering-seed random --file-reporter="json:test-results.json" || true + run: ${{ inputs.architecture == 'arm' && 'arch -arm64 ' || '' }}melos test:unit + # TODO: Publish all reports - name: Publish Test Report - uses: dorny/test-reporter@v1.7.0 + uses: dorny/test-reporter@v1.8.0 if: success() || failure() with: name: Test Results Dart ${{ inputs.os }} ${{ inputs.architecture }} @@ -75,30 +73,20 @@ jobs: only-summary: true working-directory: packages/realm_dart - # we're pruning generated files, the cli folder, as well as realm_bindings.dart from our coverage reports - - name: Generate realm_dart coverage report + - name: Gather coverage report if: inputs.runner == 'ubuntu-latest' run: | - sudo apt-get install -y lcov - dart run coverage:format_coverage \ - --in coverage/ \ - --out ./coverage/lcov.info \ - --check-ignore \ - --lcov \ - --packages .dart_tool/package_config.json \ - --report-on lib,common - lcov --remove ./coverage/lcov.info '*.realm.dart' '*/lib/src/cli/*' '*/lib/src/native/realm_bindings.dart' -o coverage/pruned-lcov.info + sudo apt-get install lcov + melos coverage:convert + melos coverage:gather + melos coverage:groom - - name: Publish realm_dart coverage + - name: Publish coverage if: inputs.runner == 'ubuntu-latest' id: publish-coverage uses: coverallsapp/github-action@f350da2c033043742f89e8c0b7b5145a1616da6d with: github-token: ${{ secrets.GITHUB_TOKEN }} flag-name: realm_dart - path-to-lcov: packages/realm_dart/coverage/pruned-lcov.info - parallel: true - - - name: Output Coveralls response - if: inputs.runner == 'ubuntu-latest' - run: echo ${{ steps.publish-coverage.outputs.coveralls-api-result }} \ No newline at end of file + path-to-lcov: ./coverage/lcov.info + parallel: true \ No newline at end of file diff --git a/.github/workflows/deploy-baas.yml b/.github/workflows/deploy-baas.yml index c668c70e4..3e7263aa8 100644 --- a/.github/workflows/deploy-baas.yml +++ b/.github/workflows/deploy-baas.yml @@ -21,16 +21,21 @@ jobs: timeout-minutes: 15 steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false - - name : Setup Dart SDK + - name: Setup Dart SDK uses: dart-lang/setup-dart@main with: sdk: stable architecture: 'x64' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap --no-flutter + - name: Install dependencies run: dart pub get diff --git a/.github/workflows/flutter-desktop-tests.yml b/.github/workflows/flutter-desktop-tests.yml index d8fc0cf36..59df0e196 100644 --- a/.github/workflows/flutter-desktop-tests.yml +++ b/.github/workflows/flutter-desktop-tests.yml @@ -38,22 +38,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false - - name: Setup GTK + - name: Setup GTK & Ninja on Linux if: ${{ inputs.os == 'linux' }} run: | sudo apt-get update -y - sudo apt-get install -y libgtk-3-dev xvfb - - - name: Setup Ninja - if: ${{ inputs.os == 'linux' }} - uses: seanmiddleditch/gha-setup-ninja@1815f2d05c2cd60c2d900f89843139b8dde09f4c + sudo apt-get install -y libgtk-3-dev xvfb ninja-build - name: Fetch artifacts - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: librealm-${{ inputs.os }} path: packages/realm_dart/binary/${{ inputs.os }} @@ -67,6 +63,11 @@ jobs: - name: Enable Flutter Desktop support run: flutter config --enable-${{ inputs.os }}-desktop + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Install dependencies run: dart pub get @@ -87,7 +88,7 @@ jobs: working-directory: packages/realm/tests - name: Publish Test Report - uses: dorny/test-reporter@v1.7.0 + uses: dorny/test-reporter@v1.8.0 if: success() || failure() with: name: Test Results Flutter ${{ inputs.os }} ${{ inputs.architecture }} diff --git a/.github/workflows/issue-labeler.yml b/.github/workflows/issue-labeler.yml index 5c9af500c..a93e0c8c0 100644 --- a/.github/workflows/issue-labeler.yml +++ b/.github/workflows/issue-labeler.yml @@ -19,7 +19,7 @@ jobs: template: [ bug.yml, feature.yml ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Parse issue form uses: stefanbuck/github-issue-parser@c1a559d78bfb8dd05216dab9ffd2b91082ff5324 # v3.0.1 diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 88195cb55..d4d3e7bc6 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Code - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: true diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml index 1d505fc78..0a266cc87 100644 --- a/.github/workflows/publish-release.yml +++ b/.github/workflows/publish-release.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false @@ -35,6 +35,11 @@ jobs: with: channel: 'stable' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Download all artifacts uses: dawidd6/action-download-artifact@d0f291cf39bd21965ea9c4c6e210fc355c3844ed with: @@ -135,7 +140,7 @@ jobs: shell: pwsh - name: Upload release folder - uses: actions/upload-artifact@83fd05a356d7e2593de66fc9913b3002723633cb + uses: actions/upload-artifact@v4 with: name: release-bundle path: release/** @@ -170,12 +175,12 @@ jobs: - prepare-packages steps: - name: Checkout code - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false - name: Download release folder - uses: actions/download-artifact@9782bd6a9848b53b110e712e20e42d89988822b7 + uses: actions/download-artifact@v4 with: name: release-bundle path: release @@ -185,16 +190,16 @@ jobs: with: channel: 'stable' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap + - name: Publish packages to pub.dev run: | mkdir -p $HOME/.config/dart echo '${{ secrets.PUB_CREDENTIALS }}' >> $HOME/.config/dart/pub-credentials.json - - dart pub publish --directory realm_common --force - dart pub publish --directory realm_generator --force - dart pub publish --directory realm_dart --force - dart pub publish --directory realm --force - working-directory: release + melos publish --no-dry-run --yes - name: Find Release PR uses: juliangruber/find-pull-request-action@f9f7484f8237cf8485e5ab826e542ba5dd9e9c6e @@ -212,7 +217,6 @@ jobs: - name: Publish Github Release uses: ncipollo/release-action@10c84d509b28aae3903113151bfd832314964f2e with: - artifacts: release/*.tar.gz bodyFile: release/ExtractedChangelog.md name: ${{ needs.prepare-packages.outputs.version }} commit: main @@ -220,7 +224,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} draft: false - - name: 'Post to #realm-releases' + - name: 'Post to #appx-releases' uses: realm/ci-actions/release-to-slack@338bf3e7575015a28faec8b67614385d122aece7 continue-on-error: true with: diff --git a/.github/workflows/terminate-baas.yml b/.github/workflows/terminate-baas.yml index 098023cdd..547d5a32a 100644 --- a/.github/workflows/terminate-baas.yml +++ b/.github/workflows/terminate-baas.yml @@ -21,16 +21,21 @@ jobs: working-directory: packages/realm_dart # TODO: Move out of realm_dart steps: - name: Checkout - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 + uses: actions/checkout@v4 with: submodules: false - - name : Setup Dart SDK + - name: Setup Dart SDK uses: dart-lang/setup-dart@main with: sdk: stable architecture: 'x64' + - name: Setup Melos + run: | + dart pub global activate melos + dart pub global run melos bootstrap --no-flutter + - name: Install dependencies run: dart pub get diff --git a/.gitignore b/.gitignore index a4ce7437c..c442974be 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,7 @@ test-results.json **/coverage/ # dos -**/doc/ \ No newline at end of file +**/doc/api/ + +# custom lint +**/custom_lint.log \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8629f816a..2411f1d50 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,6 +5,7 @@ "cSpell.words": [ "apikey", "apikeys", + "armeabi", "backlinks", "BEGINSWITH", "bson", @@ -25,18 +26,23 @@ "HRESULT", "keepalive", "loggable", + "maccatalyst", "mugaritz", "nodoc", "nullptr", "posix", + "riscv", "sublist", "sublists", "TRUEPREDICATE", "unmanaged", + "unsynced", "upsert", "usercode", "userdata", - "writeln" + "writeln", + "xcframework", + "xcodebuild" ], "cmake.statusbar.advanced": { "ctest": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f964dc76..5766b380c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,18 @@ ``` ### Enhancements +* Realm objects can now be serialized as [EJSON](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/) + ```dart + import 'package:ejson/ejson.dart'; + // ... + class _Event { + late DateTime timestamp; + late String message; + } + // ... + final ejson = toEJson(aRealmObject); + final anUnmanagedRealmObject = fromEJson(ejson); + ``` * Added `isCollectionDeleted` to `RealmListChanges`, `RealmSetChanges`, and `RealmMapChanges` which will be `true` if the parent object, containing the collection has been deleted. (Core 14.0.0) * Added `isCleared` to `RealmMapChanges` which will be `true` if the map has been cleared. (Core 14.0.0) * Querying a specific entry in a collection (in particular 'first and 'last') is supported. (Core 14.0.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1e778596..9ff034c09 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,69 +27,34 @@ Realm welcomes all contributions! The only requirement we have is that, like man [Please submit your CLA electronically using our Google form](https://docs.google.com/forms/d/1ga5zIS9qnwwFPmbq-orSPsiBIXQjltKg7ytHd2NmDYo/viewform) so we can accept your submissions. The GitHub username you file there will need to match that of your Pull Requests. If you have any questions or cannot file the CLA electronically, you can email . -## Building the source - -### Building Realm Flutter +## Building from source * Clone the repo - ``` + ```shell git clone https://github.com/realm/realm-dart + cd realm-dart git submodule update --init --recursive ``` - -#### Build Realm Flutter native binaries - -* Android - ```bash - ./scripts/build-android.sh all - scripts\build-android.bat all - # Or for Android Emulator only - ./scripts/build-android.sh x86 - scripts\build-android.bat x86 +* Activate [melos](https://melos.invertase.dev) + ```shell + dart pub global activate melos ``` - -* iOS - ```bash - ./scripts/build-ios.sh - # Or for iOS Simulator only - ./scripts/build-ios.sh simulator + Make sure that `~/.pub-cache/bin/` is added to your `PATH`. Otherwise you need to prefix the following `melos` commands with `dart pub global run`. + +* Setup project + ```shell + melos bootstrap + melos run setup ``` -* Windows - ``` - scripts\build.bat - ``` -* MacOS - ``` - ./scripts/build-macos.sh +* Build artifacts + ```shell + melos run build ``` -* Linux +* Test + ```shell + melos run test ``` - ./scripts/build-linux.sh - ``` - -### Building Realm Dart - -* Windows - ``` - scripts\build.bat - ``` -* MacOS - ``` - ./scripts/build-macos.sh - ``` -* Linux - ``` - ./scripts/build-linux.sh - ``` - -## Versioning - -Realm Flutter and Dart SDK packages follow [Semantic Versioning](https://semver.org/). -During the initial development the packages will be versioned according the scheme `0.major.minor+release stage` until the first stable version is reached then packages will be versioned with `major.minor.patch` scheme. -The first versions will follow `0.1.0+preview`, `0.1.1+preview` etc. -Then next release stages will pick up the next minor version `0.1.2+beta`, `0.1.3+beta`. This will ensure dependencies are updated on `dart pub get` with the new `alpha`, `beta` versions. -If an `alpha` version is released before `beta` and it needs to not be considered for `pub get` then it should be marked as `prerelease` with `-alpha` so `0.1.2-alpha` etc. -Updating the major version with every release stage is also possible - `0.2.0+alpha`, `0.3.0+beta`, `0.3.1+beta`. +There are many more melos scripts to run, see [melos.yaml](melos.yaml) for details. diff --git a/analysis_options.yaml b/analysis_options.yaml index c532ec449..602785858 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,28 +1,18 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - +# This file is symlinked into each package's root directory. include: package:lints/recommended.yaml analyzer: - language: - strict-raw-types: true + language: + strict-casts: true # see https://github.com/dart-lang/language/blob/main/resources/type-system/strict-casts.md + strict-inference: true # see https://github.com/dart-lang/language/blob/main/resources/type-system/strict-inference.md + strict-raw-types: true # see https://github.com/dart-lang/language/blob/main/resources/type-system/strict-raw-types.md - strong-mode: - implicit-casts: false - implicit-dynamic: false + plugins: + - custom_lint exclude: - lib/**/*.g.dart + - lib/**/*.realm.dart - lib/**/realm_bindings.dart linter: diff --git a/melos.yaml b/melos.yaml new file mode 100644 index 000000000..3bf9eb4a8 --- /dev/null +++ b/melos.yaml @@ -0,0 +1,212 @@ +name: realm-dart + +repository: https://github.com/realm/realm-dart + +ide: + intellij: # no one uses android studio right? + enabled: false + +packages: + - packages/* + - packages/*/example + - packages/*/tests + +command: + bootstrap: + environment: + sdk: ^3.0.0 + flutter: ^3.10.0 + dev_dependencies: + lints: ^3.0.0 + + clean: + hooks: + pre: melos exec --flutter -- flutter clean + +scripts: + setup: + run: >- + dart pub global activate combine_coverage && + dart pub global activate coverage && + dart pub global activate coverde && + dart pub global activate dependency_validator && + dart pub global activate ffigen && + dart pub global activate melos && + dart pub global activate pana + + build: + run: >- + melos run build:native && + melos run build:binding && + melos run build:dart + + build:native: + exec: dart run tool/build.dart native + packageFilters: + dirExists: src # by convention + + build:dart: + run: dart run build_runner build --delete-conflicting-outputs + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: build_runner + + build:binding: + exec: dart pub global run ffigen --config ffigen.yaml + packageFilters: + fileExists: ffigen.yaml # by convention + + test: + description: Run all tests. + run: >- + melos run test:unit && + melos run test:widget && + melos run test:lints && + melos run test:integration + + test:unit: + run: dart test --concurrency=1 --coverage=coverage/ --file-reporter=json:test-results.json --reporter=github + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: test + dirExists: test/ + flutter: false + + test:widget: + run: flutter test --concurrency=1 --coverage --reporter=github + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: flutter_test + noDependsOn: integration_test # integration tests are run separately + dirExists: test/ + flutter: true + + test:lints: + run: dart run custom_lint + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: custom_lint + + test:integration: + run: >- + flutter test integration_test/all_tests.dart + --coverage + --dart-define=BAAS_URL='$BAAS_URL' + --dart-define=BAAS_DIFFERENTIATOR='$BAAS_DIFFERENTIATOR' + --device-id='$DEVICE_ID' + --file-reporter=json:test-results.json + --reporter=github + --suppress-analytics + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: integration_test + fileExists: integration_test/all_tests.dart + flutter: true + + doc: + description: Generate documentation. + exec: dart doc --validate-links + packageFilters: + published: true + + format: + description: Format code. + # while we wait for https://github.com/dart-lang/dart_style/issues/864 + run: >- + find lib test integration_test -name '*.dart' -not -name '*.g.dart' -not -name '*.realm.dart' -not -name 'realm_bindings.dart' 2> /dev/null + | xargs dart format --fix --line-length 160 + exec: + concurrency: 1 # only one project at a time to keep output sane + + upgrade: + description: Upgrade all dependencies. + exec: dart pub upgrade --major-versions + + lint: + description: Run all lints. + run: >- + melos run lint:format && + melos run lint:pana && + melos publish --dry-run + + lint:format: + # while we wait for https://github.com/dart-lang/dart_style/issues/864 + run: >- + find lib test integration_test -name '*.dart' -not -name '*.g.dart' -not -name '*.realm.dart' -not -name 'realm_bindings.dart' 2> /dev/null + | xargs dart format --fix --line-length 160 --output none --set-exit-if-changed + exec: + concurrency: 1 # only one project at a time to keep output sane + + lint:pana: + run: dart pub global run pana --no-warning --exit-code-threshold 40 . + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + published: true + + analyze: + description: Analyze code and dependencies. + run: >- + melos run analyze:code && + melos run analyze:deps + + analyze:code: + exec: dart analyze . --fatal-infos + + analyze:deps: + exec: dart pub global run dependency_validator + + coverage: + description: Generate, check and render coverage. + run: >- + melos run coverage:convert && + melos run coverage:gather && + melos run coverage:groom && + melos run coverage:report && + melos run coverage:check + + coverage:check: # TODO: Increase to 90 eventually + run: dart pub global run coverde check 80 + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + fileExists: coverage/lcov.info # by convention + + coverage:convert: + run: dart pub global run coverage:format_coverage --report-on=lib/ --in=coverage/test/ --lcov --out=coverage/lcov.info + exec: + concurrency: 1 # only one project at a time to keep output sane + packageFilters: + dependsOn: test + dirExists: coverage/test/ + flutter: false + + coverage:gather: + run: | + rm -rf $MELOS_ROOT_PATH/coverage + dart pub global run combine_coverage --repo-path=$MELOS_ROOT_PATH + + coverage:groom: + run: | + lcov --remove coverage/lcov.info '*/lib/src/cli/*' -o coverage/lcov.info + lcov --remove coverage/lcov.info '*/realm_bindings.dart' -o coverage/lcov.info + + coverage:report: + run: dart pub global run coverde report + + # TODO: This is actually stricter than on CI, but we should aim for this + ci: + run: >- + melos clean && + melos bootstrap && + melos run build && + melos run test && + melos run coverage && + melos run analyze && + melos run lint + \ No newline at end of file diff --git a/packages/ejson/CHANGELOG.md b/packages/ejson/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson/LICENSE b/packages/ejson/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/ejson/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/ejson/README.md b/packages/ejson/README.md new file mode 120000 index 000000000..fe8400541 --- /dev/null +++ b/packages/ejson/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/ejson/analysis_options.yaml b/packages/ejson/analysis_options.yaml new file mode 120000 index 000000000..3a0737064 --- /dev/null +++ b/packages/ejson/analysis_options.yaml @@ -0,0 +1 @@ +../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson/example/main.dart b/packages/ejson/example/main.dart new file mode 100644 index 000000000..f44d0bb72 --- /dev/null +++ b/packages/ejson/example/main.dart @@ -0,0 +1,21 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:convert'; + +import 'package:ejson/ejson.dart'; +import 'package:test/test.dart'; + +void main() { + test('round-trip', () { + final value = { + 'abe': [1, 4], + 'kat': [], + }; + final encoded = toEJson(value); + final json = jsonEncode(encoded); + print(json); + final decoded = fromEJson>>(jsonDecode(json)); + expect(value, decoded); + }); +} diff --git a/packages/ejson/lib/ejson.dart b/packages/ejson/lib/ejson.dart new file mode 100644 index 000000000..417d781bf --- /dev/null +++ b/packages/ejson/lib/ejson.dart @@ -0,0 +1,9 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +export 'src/configuration.dart'; +export 'src/decoding.dart' hide customDecoders; +export 'src/encoding.dart' hide customEncoders; +export 'src/types.dart'; + +export 'package:ejson_annotation/ejson_annotation.dart'; diff --git a/packages/ejson/lib/src/configuration.dart b/packages/ejson/lib/src/configuration.dart new file mode 100644 index 000000000..7ef45d9f9 --- /dev/null +++ b/packages/ejson/lib/src/configuration.dart @@ -0,0 +1,16 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:ejson_annotation/ejson_annotation.dart'; +import 'package:type_plus/type_plus.dart'; + +import 'decoding.dart'; +import 'encoding.dart'; + +/// Register custom EJSON [encoder] and [decoder] for a type [T]. +/// The last registered codec pair for a given type [T] will be used. +void register(EJsonEncoder encoder, EJsonDecoder decoder) { + TypePlus.add(); + customEncoders[T] = encoder; + customDecoders[T] = decoder; +} diff --git a/packages/ejson/lib/src/decoding.dart b/packages/ejson/lib/src/decoding.dart new file mode 100644 index 000000000..3c808f6ec --- /dev/null +++ b/packages/ejson/lib/src/decoding.dart @@ -0,0 +1,278 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:typed_data'; +import 'dart:convert'; + +import 'package:collection/collection.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; +import 'package:objectid/objectid.dart'; +import 'package:sane_uuid/uuid.dart'; +import 'package:type_plus/type_plus.dart'; + +import 'types.dart'; + +/// Predefined decoders for common types +const _commonDecoders = { + dynamic: _decodeAny, + Null: _decodeNull, + Object: _decodeAny, + Iterable: _decodeArray, + List: _decodeArray, + bool: _decodeBool, + DateTime: _decodeDate, + Defined: _decodeDefined, + Key: _decodeKey, + Map: _decodeDocument, + double: _decodeDouble, + num: _decodeNum, + int: _decodeInt, + ObjectId: _decodeObjectId, + String: _decodeString, + Symbol: _decodeSymbol, + Uint8List: _decodeBinary, + Uuid: _decodeUuid, + Undefined: _decodeUndefined, + UndefinedOr: _decodeUndefinedOr, +}; + +/// Custom decoders for specific types. Use `register` to add a custom decoder. +final customDecoders = {}; + +final _decoders = () { + // register extra common types on first access + undefinedOr(dynamic f) => f>(); + TypePlus.addFactory(undefinedOr); + TypePlus.addFactory((dynamic f) => f>(), superTypes: [undefinedOr]); + TypePlus.addFactory((dynamic f) => f>(), superTypes: [undefinedOr]); + TypePlus.add(); + TypePlus.add(); + TypePlus.add(); + TypePlus.add(); + + return CombinedMapView([customDecoders, _commonDecoders]); +}(); + +/// Converts [ejson] to type [T]. +/// +/// Throws [InvalidEJson] if [ejson] is not valid for [T]. +/// Throws [MissingDecoder] if no decoder is registered for [T]. +T fromEJson(EJsonValue ejson) { + final type = T; + final nullable = type.isNullable; + final decoder = nullable ? _decodeNullable : _decoders[type.base]; + if (decoder == null) { + throw MissingDecoder._(ejson, type); + } + final args = nullable ? [type.nonNull] : type.args; + if (args.isEmpty) { + return decoder(ejson) as T; // minor optimization + } + return decoder.callWith(typeArguments: args, parameters: [ejson]) as T; +} + +/// Parses [source] to [EJsonValue] and convert to type [T]. +/// +/// Throws [InvalidEJson] if [source] is not valid for [T]. +/// Throws [MissingDecoder] if no decoder is registered for [T]. +T fromEJsonString(String source) => fromEJson(jsonDecode(source)); + +// Important to return `T` as opposed to [Never] for type inference to work +/// @nodoc +T raiseInvalidEJson(Object? value) => throw InvalidEJson._(value, T); + +dynamic _decodeAny(EJsonValue ejson) { + return switch (ejson) { + null => null, + bool b => b, + double d => d, // relaxed mode + int i => i, // relaxed mode + String s => s, + {'\$date': _} => _decodeDate(ejson), + {'\$maxKey': _} => _decodeKey(ejson), + {'\$minKey': _} => _decodeKey(ejson), + {'\$numberDouble': _} => _decodeDouble(ejson), + {'\$numberInt': _} => _decodeInt(ejson), + {'\$numberLong': _} => _decodeInt(ejson), + {'\$regex': _} => _decodeString(ejson), + {'\$symbol': _} => _decodeSymbol(ejson), + {'\$undefined': _} => _decodeUndefined(ejson), + {'\$oid': _} => _decodeObjectId(ejson), + {'\$binary': {'base64': _, 'subType': '04'}} => _decodeUuid(ejson), + {'\$binary': _} => _decodeBinary(ejson), + List _ => _decodeArray(ejson), + Map _ => _tryDecodeCustom(ejson) ?? _decodeDocument(ejson), // other maps goes last!! + _ => raiseInvalidEJson(ejson), + }; +} + +dynamic _tryDecodeCustom(EJsonValue ejson) { + for (final decoder in customDecoders.values) { + try { + return decoder(ejson); + } catch (_) { + // ignore + } + } + return null; +} + +List _decodeArray(EJsonValue ejson) { + return switch (ejson) { + Iterable i => i.map((ejson) => fromEJson(ejson)).toList(), + _ => raiseInvalidEJson(ejson), + }; +} + +bool _decodeBool(EJsonValue ejson) { + return switch (ejson) { + bool b => b, + _ => raiseInvalidEJson(ejson), + }; +} + +DateTime _decodeDate(EJsonValue ejson) { + return switch (ejson) { + {'\$date': String s} => DateTime.parse(s), // relaxed mode + {'\$date': {'\$numberLong': String i}} => DateTime.fromMillisecondsSinceEpoch(int.tryParse(i) ?? raiseInvalidEJson(ejson)), + _ => raiseInvalidEJson(ejson), + }; +} + +Defined _decodeDefined(EJsonValue ejson) { + if (ejson case {'\$undefined': 1}) return raiseInvalidEJson(ejson); + return Defined(fromEJson(ejson)); +} + +Map _decodeDocument(EJsonValue ejson) { + return switch (ejson) { + Map m => m.map((key, value) => MapEntry(key as K, fromEJson(value))), + _ => raiseInvalidEJson(ejson), + }; +} + +double _decodeDouble(EJsonValue ejson) { + return switch (ejson) { + double d => d, // relaxed mode + {'\$numberDouble': String s} => switch (s) { + 'NaN' => double.nan, + 'Infinity' => double.infinity, + '-Infinity' => double.negativeInfinity, + _ => double.tryParse(s) ?? raiseInvalidEJson(ejson), + }, + _ => raiseInvalidEJson(ejson), + }; +} + +int _decodeInt(EJsonValue ejson) { + return switch (ejson) { + int i => i, // relaxed mode + {'\$numberInt': String i} => int.tryParse(i) ?? raiseInvalidEJson(ejson), + {'\$numberLong': String i} => int.tryParse(i) ?? raiseInvalidEJson(ejson), + _ => raiseInvalidEJson(ejson), + }; +} + +Key _decodeKey(EJsonValue ejson) { + return switch (ejson) { + {'\$minKey': 1} => Key.min, + {'\$maxKey': 1} => Key.max, + _ => raiseInvalidEJson(ejson), + }; +} + +// ignore: prefer_void_to_null +Null _decodeNull(EJsonValue ejson) { + return switch (ejson) { + null => null, + _ => raiseInvalidEJson(ejson), + }; +} + +T? _decodeNullable(EJsonValue ejson) { + if (ejson == null) { + return null; + } + return fromEJson(ejson); +} + +num _decodeNum(EJsonValue ejson) { + return switch (ejson) { + num n => n, // relaxed mode + {'\$numberLong': _} => _decodeInt(ejson), + {'\$numberInt': _} => _decodeInt(ejson), + {'\$numberDouble': _} => _decodeDouble(ejson), + _ => raiseInvalidEJson(ejson), + }; +} + +ObjectId _decodeObjectId(EJsonValue ejson) { + return switch (ejson) { + {'\$oid': String s} => ObjectId.fromHexString(s), + _ => raiseInvalidEJson(ejson), + }; +} + +String _decodeString(EJsonValue ejson) { + return switch (ejson) { + String s => s, + _ => raiseInvalidEJson(ejson), + }; +} + +Symbol _decodeSymbol(EJsonValue ejson) { + return switch (ejson) { + {'\$symbol': String s} => Symbol(s), + _ => raiseInvalidEJson(ejson), + }; +} + +Undefined _decodeUndefined(EJsonValue ejson) { + return switch (ejson) { + {'\$undefined': 1} => Undefined(), + _ => raiseInvalidEJson(ejson), + }; +} + +UndefinedOr _decodeUndefinedOr(EJsonValue ejson) { + return switch (ejson) { + {'\$undefined': 1} => Undefined(), + _ => _decodeDefined(ejson), + }; +} + +Uuid _decodeUuid(EJsonValue ejson) { + return switch (ejson) { + {'\$binary': {'base64': String s, 'subType': '04'}} => Uuid.fromBytes(base64.decode(s).buffer), + _ => raiseInvalidEJson(ejson), + }; +} + +Uint8List _decodeBinary(EJsonValue ejson) { + return switch (ejson) { + {'\$binary': {'base64': String s, 'subType': _}} => base64.decode(s), + _ => raiseInvalidEJson(ejson), + }; +} + +/// Thrown when a value cannot be decoded from [ejson]. +class InvalidEJson implements Exception { + final EJsonValue ejson; + final Type type; + + InvalidEJson._(this.ejson, this.type); + + @override + String toString() => 'Invalid EJson for $type: $ejson'; +} + +/// Thrown when no decoder is registered for a [type]. +class MissingDecoder implements Exception { + final EJsonValue ejson; + final Type type; + + MissingDecoder._(this.ejson, this.type); + + @override + String toString() => 'Missing decoder for $type'; +} diff --git a/packages/ejson/lib/src/encoding.dart b/packages/ejson/lib/src/encoding.dart new file mode 100644 index 000000000..48f37fa91 --- /dev/null +++ b/packages/ejson/lib/src/encoding.dart @@ -0,0 +1,242 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:ejson_annotation/ejson_annotation.dart'; +import 'package:objectid/objectid.dart'; +import 'package:sane_uuid/uuid.dart'; +import 'package:type_plus/type_plus.dart'; + +import 'types.dart'; + +/// Custom encoders for specific types. Use `register` to add a custom encoder. +var customEncoders = {}; + +/// Whether to use relaxed encoding or not, default is false +var relaxed = false; + +@pragma('vm:prefer-inline') + +/// Converts [value] to EJson +/// +/// Throws [MissingEncoder] if no encoder is registered for [value]'s type. +EJsonValue toEJson(Object? value) => _encodeAny(value); + +/// Converts [value] to EJson string +/// +/// Throws [MissingEncoder] if no encoder is registered for [value]'s type. +String toEJsonString(Object? value) => jsonEncode(toEJson(value)); + +EJsonValue _encodeAny(Object? value) { + return switch (value) { + null => null, + bool b => _encodeBool(b), + DateTime d => _encodeDate(d), + Defined d => _encodeDefined(d), + double d => _encodeDouble(d), + int i => _encodeInt(i), + Key k => _encodeKey(k), + Uint8List b => _encodeBinary(b, subtype: '00'), + Iterable l => _encodeArray(l), + Map m => _encodeDocument(m), + ObjectId o => _encodeObjectId(o), + String s => _encodeString(s), + Symbol s => _encodeSymbol(s), + Undefined u => _encodeUndefined(u), + Uuid u => _encodeUuid(u), + _ => _encodeCustom(value), + }; +} + +EJsonValue _encodeArray(Iterable items) => items.map((e) => toEJson(e)).toList(); + +EJsonValue _encodeBool(bool value) => value; + +EJsonValue _encodeCustom(Object value) { + final encoder = customEncoders[value.runtimeType.base]; + if (encoder == null) { + throw MissingEncoder(value); + } + return encoder(value); +} + +EJsonValue _encodeDate(DateTime value) { + return switch (relaxed) { + true => {'\$date': value.toIso8601String()}, + false => { + '\$date': {'\$numberLong': value.millisecondsSinceEpoch.toString()}, + }, + }; +} + +EJsonValue _encodeDefined(Defined defined) => toEJson(defined.value); + +EJsonValue _encodeDocument(Map map) => map.map((k, v) => MapEntry(k, toEJson(v))); + +EJsonValue _encodeDouble(double value) { + if (value.isNaN) { + return {'\$numberDouble': 'NaN'}; + } + return switch (value) { + double.infinity => {'\$numberDouble': 'Infinity'}, + double.negativeInfinity => {'\$numberDouble': '-Infinity'}, + _ => switch (relaxed) { + true => value, + false => {'\$numberDouble': '$value'}, + } + }; +} + +enum IntFormat { int32, int64 } + +EJsonValue _encodeInt(int value, {IntFormat? forcedFormat}) { + switch (relaxed) { + case true: + return value; + case false: + bool fitsInInt32 = value >= -0x80000000 && value < 0x80000000; + final format = forcedFormat ?? (fitsInInt32 ? IntFormat.int32 : IntFormat.int64); + if (!fitsInInt32 && format == IntFormat.int32) { + throw ArgumentError.value(value, 'value', 'Value does not fit in int32'); + } + return switch (format) { + IntFormat.int32 => {'\$numberInt': '$value'}, + IntFormat.int64 => {'\$numberLong': '$value'}, + }; + } +} + +EJsonValue _encodeKey(Key key) => {'\$${key.name}Key': 1}; + +@pragma('vm:prefer-inline') +EJsonValue _encodeString(String value) => value; + +EJsonValue _encodeSymbol(Symbol value) => {'\$symbol': value.name}; + +EJsonValue _encodeUndefined(Undefined undefined) => {'\$undefined': 1}; + +EJsonValue _encodeUuid(Uuid uuid) => _encodeBinary(uuid.bytes.asUint8List(), subtype: '04'); + +EJsonValue _encodeBinary(Uint8List buffer, {required String subtype}) => { + '\$binary': { + 'base64': base64.encode(buffer), + 'subType': subtype, + }, + }; + +EJsonValue _encodeObjectId(ObjectId objectId) => {'\$oid': objectId.hexString}; + +/// Exception thrown when no encoder is registered for the type of a [value]. +class MissingEncoder implements Exception { + final Object value; + + MissingEncoder(this.value); + + @override + String toString() => 'Missing encoder for type ${value.runtimeType} ($value)'; +} + +extension BoolEJsonEncoderExtension on bool { + /// Converts this [bool] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeBool(this); +} + +extension DateTimeEJsonEncoderExtension on DateTime { + /// Converts this [DateTime] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeDate(this); +} + +extension DefinedEJsonEncoderExtension on Defined { + /// Converts this [Defined] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeDefined(this); +} + +extension DoubleEJsonEncoderExtension on double { + /// Converts this [double] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeDouble(this); +} + +extension IntEJsonEncoderExtension on int { + /// Converts this [int] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson({IntFormat? forcedFormat}) => _encodeInt(this, forcedFormat: forcedFormat); +} + +extension KeyEJsonEncoderExtension on Key { + /// Converts this [Key] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeKey(this); +} + +extension ListEJsonEncoderExtension on List { + /// Converts this [List] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeArray(this); +} + +extension MapEJsonEncoderExtension on Map { + /// Converts this [Map] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeDocument(this); +} + +extension NullEJsonEncoderExtension on Null { + /// Converts this [Null] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => null; +} + +extension NullableObjectEJsonEncoderExtension on Object? { + /// Converts this [Object] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeAny(this); +} + +extension ObjectIdEJsonEncoderExtension on ObjectId { + /// Converts this [ObjectId] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeObjectId(this); +} + +extension StringEJsonEncoderExtension on String { + /// Converts this [String] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeString(this); +} + +extension SymbolEJsonEncoderExtension on Symbol { + /// Extract the name of this [Symbol] + String get name { + final full = toString(); + // remove leading 'Symbol("' and trailing '")' + return full.substring(8, full.length - 2); + } + + /// Converts this [Symbol] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeSymbol(this); +} + +extension Uint8ListEJsonEncoderExtension on Uint8List { + /// Converts this [Uint8List] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeBinary(this, subtype: '00'); +} + +extension UndefinedEJsonEncoderExtension on Undefined { + /// Converts this [Undefined] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeUndefined(this); +} + +extension UuidEJsonEncoderExtension on Uuid { + /// Converts this [Uuid] to EJson + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeUuid(this); +} diff --git a/packages/ejson/lib/src/types.dart b/packages/ejson/lib/src/types.dart new file mode 100644 index 000000000..8a0027afa --- /dev/null +++ b/packages/ejson/lib/src/types.dart @@ -0,0 +1,66 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +enum EJsonType { + array, + binary, + boolean, + date, + decimal128, + document, + double, + int32, + int64, + maxKey, + minKey, + objectId, + string, + symbol, + nil, // aka. null + undefined, + // TODO: The following is not supported yet + // code, + // codeWithScope, + // databasePointer, + // databaseRef, + // regularExpression, + // timestamp, // This is not what you think, see https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-bsontype-Timestamp +} + +/// See [MaxKey](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-bsontype-MaxKey) +/// and [MinKey](https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-bsontype-MinKey) +enum Key { min, max } + +sealed class UndefinedOr { + const UndefinedOr(); +} + +final class Undefined extends UndefinedOr { + const Undefined(); + + @override + int get hashCode => (Undefined).hashCode; + + @override + operator ==(Object other) => other is Undefined; + + @override + String toString() => 'Undefined<$T>()'; +} + +const undefined = Undefined(); + +final class Defined extends UndefinedOr { + final T value; + + const Defined(this.value); + + @override + int get hashCode => value.hashCode; + + @override + bool operator ==(Object other) => identical(this, other) || other is Defined && value == other.value; + + @override + String toString() => 'Defined<$T>($value)'; +} diff --git a/packages/ejson/pubspec.yaml b/packages/ejson/pubspec.yaml new file mode 100644 index 000000000..e271da5f2 --- /dev/null +++ b/packages/ejson/pubspec.yaml @@ -0,0 +1,32 @@ +name: ejson +description: >- + EJSON serialization. + + BSON is a binary format used to store JSON-like documents efficiently. + EJSON extends JSON defining how all BSON types should be represented in JSON. + +topics: + - ejson + - bson + - json + - build-runner + - codegen + +version: 0.1.0 +repository: https://github.com/realm/realm-dart/ejson/packages/ejson + +environment: + sdk: ^3.0.0 + +dependencies: + collection: ^1.17.0 + ejson_annotation: ^0.1.0 + objectid: ^3.0.0 + sane_uuid: ^1.0.0-alpha.5 + type_plus: ^2.0.0 + +dev_dependencies: + build_runner: ^2.0.0 + ejson_generator: ^0.1.0 + lints: ^3.0.0 + test: ^1.21.0 diff --git a/packages/ejson/test/ejson_test.dart b/packages/ejson/test/ejson_test.dart new file mode 100644 index 000000000..a0f77962d --- /dev/null +++ b/packages/ejson/test/ejson_test.dart @@ -0,0 +1,342 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// ignore_for_file: inference_failure_on_function_invocation + +import 'dart:convert'; +import 'dart:typed_data'; + +import 'package:ejson/ejson.dart'; +import 'package:objectid/objectid.dart'; +import 'package:sane_uuid/uuid.dart'; +import 'package:test/test.dart'; + +import 'person.dart'; + +void _testCase(T value, EJsonValue expected) { + test('encode from $value of type $T', () { + expect(toEJson(value), expected); + }); + + test('encode fluent from $value of type $T', () { + expect(value.toEJson(), expected); + }); + + test('decode to $value of type $T', () { + expect(fromEJson(expected), value); + }); + + test('roundtrip $value of type $T', () { + expect(fromEJson(toEJson(value)), value); + }); + + test('reverse roundtrip $value of type $T', () { + expect(toEJson(fromEJson(expected)), expected); + }); + + test('roundtrip $value of type $T as String', () { + expect( + fromEJsonString(toEJsonString(value)), // roundtrip as String + value, + ); + }); + + test('decode to dynamic', () { + // no here, so dynamic + expect(() => fromEJson(expected), returnsNormally); + }); + + if (value is! Defined) { + test('roundtrip $value of type $T as dynamic', () { + // no here, so dynamic + expect(fromEJson(toEJson(value)), value); + }); + + test('reverse roundtrip $value of type $T as dynamic', () { + // no here, so dynamic + expect(toEJson(fromEJson(expected)), expected); + }); + } +} + +class Dummy {} + +void _invalidTestCase([EJsonValue ejson = const {}]) { + test('decode $T from invalid ejson: $ejson', () { + expect(() => fromEJson(ejson), throwsA(isA().having((e) => e.toString(), 'toString', 'Invalid EJson for $T: $ejson'))); + }); +} + +void main() { + test('fluent encoding', () { + // NOTE: These cannot be handled generically, as we want to hit the correct + // extension method, ie. not the fallback on Object?. + expect(null.toEJson(), toEJson(null)); + expect(1.toEJson(), toEJson(1)); + expect(1.toEJson(forcedFormat: IntFormat.int64), {'\$numberLong': '1'}); + expect(() => (1 << 33).toEJson(forcedFormat: IntFormat.int32), throwsArgumentError); + expect(1.0.toEJson(), toEJson(1.0)); + expect('a'.toEJson(), toEJson('a')); + expect(true.toEJson(), toEJson(true)); + expect(false.toEJson(), toEJson(false)); + expect([1, 2, 3].toEJson(), toEJson([1, 2, 3])); + expect({'a': 1, 'b': 2}.toEJson(), toEJson({'a': 1, 'b': 2})); + expect(DateTime(1974, 4, 10, 2, 42, 12, 202).toEJson(), toEJson(DateTime(1974, 4, 10, 2, 42, 12, 202))); + expect((#sym).toEJson(), toEJson(#sym)); + expect(Key.max.toEJson(), toEJson(Key.max)); + expect(Key.min.toEJson(), toEJson(Key.min)); + expect(undefined.toEJson(), toEJson(undefined)); + expect(const Undefined().toEJson(), toEJson(const Undefined())); + expect(Undefined().toEJson(), toEJson(Undefined())); + expect(const Defined(42).toEJson(), toEJson(const Defined(42))); + expect(const Defined(null).toEJson(), toEJson(const Defined(null))); + expect(ObjectId.fromValues(1, 2, 3).toEJson(), toEJson(ObjectId.fromValues(1, 2, 3))); + final uuid = Uuid.v4(); + expect(uuid.toEJson(), toEJson(uuid)); + final bytes = uuid.bytes.asUint8List(); + expect(bytes.toEJson(), toEJson(bytes)); + }); + + test('missing encoder', () { + expect( + () => toEJson(Dummy()), throwsA(isA().having((e) => e.toString(), 'toString', "Missing encoder for type Dummy (Instance of 'Dummy')"))); + }); + + group('invalid', () { + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase({'\$numberDouble': 'foobar'}); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase>(); + _invalidTestCase>([]); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase(); + _invalidTestCase>(); + _invalidTestCase(); + + test('missing decoder', () { + expect(() => fromEJson({}), throwsA(isA().having((e) => e.toString(), 'toString', 'Missing decoder for Dummy'))); + }); + }); + + for (final canonical in [true, false]) { + group(canonical ? 'canonical' : 'relaxed', () { + setUp(() => relaxed = !canonical); + + group('common types', () { + final time = DateTime(1974, 4, 10, 2, 42, 12, 202); // no microseconds! + + _testCase(null, null); + _testCase(1, canonical ? {'\$numberInt': '1'} : 1); + _testCase(1.0, canonical ? {'\$numberDouble': '1.0'} : 1.0); + _testCase(double.infinity, {'\$numberDouble': 'Infinity'}); + _testCase(double.negativeInfinity, {'\$numberDouble': '-Infinity'}); + _testCase('a', 'a'); + _testCase(true, true); + _testCase(false, false); + _testCase( + [1, 2, 3], + canonical + ? [ + {'\$numberInt': '1'}, + {'\$numberInt': '2'}, + {'\$numberInt': '3'}, + ] + : [1, 2, 3], + ); + _testCase( + [1, 1.1], + canonical + ? [ + {'\$numberInt': '1'}, + {'\$numberDouble': '1.1'}, + ] + : [1, 1.1], + ); + _testCase( + [1, null, 3], + canonical + ? [ + {'\$numberInt': '1'}, + null, + {'\$numberInt': '3'}, + ] + : [1, null, 3], + ); + _testCase( + {'a': 'abe', 'b': 1}, + canonical + ? { + 'a': 'abe', + 'b': {'\$numberInt': '1'}, + } + : {'a': 'abe', 'b': 1}, + ); + _testCase( + time, + canonical + ? { + '\$date': {'\$numberLong': time.millisecondsSinceEpoch.toString()} + } + : {'\$date': time.toIso8601String()}, + ); + _testCase(#sym, {'\$symbol': 'sym'}); + _testCase(Key.max, {'\$maxKey': 1}); + _testCase(Key.min, {'\$minKey': 1}); + _testCase(undefined, {'\$undefined': 1}); + _testCase(const Undefined(), {'\$undefined': 1}); + _testCase(Undefined(), {'\$undefined': 1}); + _testCase(const Defined(42), canonical ? {'\$numberInt': '42'} : 42); + _testCase(const Defined(null), null); + _testCase(Defined(42), canonical ? {'\$numberInt': '42'} : 42); + _testCase(Defined(null), null); + _testCase(ObjectId.fromValues(1, 2, 3), {'\$oid': '000000000000000002000003'}); + final uuid = Uuid.v4(); + _testCase(uuid, { + '\$binary': {'base64': base64.encode(uuid.bytes.asUint8List()), 'subType': '04'} + }); + final uint8list = Uint8List.fromList(List.generate(32, (i) => i)); + _testCase(uint8list, { + '\$binary': {'base64': base64.encode(uint8list), 'subType': '00'} + }); + // a complex nested generic type + _testCase?>>>( + { + 'a': { + 'b': null, + 'c': [1, 1.1, null] + } + }, + canonical + ? { + 'a': { + 'b': null, + 'c': [ + {'\$numberInt': '1'}, + {'\$numberDouble': '1.1'}, + null + ] + } + } + : { + 'a': { + 'b': null, + 'c': [1, 1.1, null] + } + }, + ); + + test('UndefinedOr', () { + UndefinedOr x = Undefined(); + expect(x.toEJson(), {'\$undefined': 1}); + + x = Defined(42); + expect(x.toEJson(), relaxed ? 42 : {'\$numberInt': '42'}); + + x = Defined(null); + expect(x.toEJson(), isNull); + + expect( + fromEJson>({'\$undefined': 1}), + const Undefined(), + ); + + expect( + fromEJson>({'\$numberInt': '42'}), + Defined(42), + ); + + expect(fromEJson>(null), Defined(null)); + }); + + test('NaN', () { + expect(toEJson(double.nan), {'\$numberDouble': 'NaN'}); + expect(fromEJson({'\$numberDouble': 'NaN'}), isNaN); + }); + }); + + group('custom types', () { + registerPerson(); + + final person = Person( + 'John', + DateTime(1974), + 80000, + spouse: Person('Jane', DateTime(1973), 90000), + ); + + _testCase( + person, + canonical + ? { + 'name': 'John', + 'birthDate': { + '\$date': {'\$numberLong': person.birthDate.millisecondsSinceEpoch.toString()} + }, + 'income': {'\$numberDouble': '80000.0'}, + 'spouse': { + 'name': 'Jane', + 'birthDate': { + '\$date': {'\$numberLong': person.spouse!.birthDate.millisecondsSinceEpoch.toString()} + }, + 'income': {'\$numberDouble': '90000.0'}, + 'spouse': null + } + } + : { + 'name': 'John', + 'birthDate': {'\$date': '1974-01-01T00:00:00.000'}, + 'income': 80000.0, + 'spouse': { + 'name': 'Jane', + 'birthDate': {'\$date': '1973-01-01T00:00:00.000'}, + 'income': 90000.0, + 'spouse': null + } + }, + ); + _testCase>( + {'a': person}, + canonical + ? { + 'a': { + 'name': 'John', + 'birthDate': { + '\$date': {'\$numberLong': person.birthDate.millisecondsSinceEpoch.toString()} + }, + 'income': {'\$numberDouble': '80000.0'}, + 'spouse': { + 'name': 'Jane', + 'birthDate': { + '\$date': {'\$numberLong': person.spouse!.birthDate.millisecondsSinceEpoch.toString()} + }, + 'income': {'\$numberDouble': '90000.0'}, + 'spouse': null + } + } + } + : { + 'a': { + 'name': 'John', + 'birthDate': {'\$date': '1974-01-01T00:00:00.000'}, + 'income': 80000.0, + 'spouse': { + 'name': 'Jane', + 'birthDate': {'\$date': '1973-01-01T00:00:00.000'}, + 'income': 90000.0, + 'spouse': null + } + } + }, + ); + }); + }); + } +} diff --git a/packages/ejson/test/person.dart b/packages/ejson/test/person.dart new file mode 100644 index 000000000..2e588e5b2 --- /dev/null +++ b/packages/ejson/test/person.dart @@ -0,0 +1,30 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:ejson/ejson.dart'; + +part 'person.g.dart'; + +class Person { + final String name; + final DateTime birthDate; + Duration get age => DateTime.now().difference(birthDate); + + final double income; + final Person? spouse; + + final children = []; + + @ejson // annotate constructor to generate decoder and encoder + Person(this.name, this.birthDate, this.income, {this.spouse}); + + @override + operator ==(other) => + identical(this, other) || (other is Person && other.name == name && other.birthDate == birthDate && other.income == income && other.spouse == spouse); + + @override + String toString() => 'Person{name: $name, birthDate: $birthDate, income: $income, spouse: $spouse}'; + + @override + int get hashCode => Object.hashAll([name, birthDate, income, spouse]); +} diff --git a/packages/ejson/test/person.g.dart b/packages/ejson/test/person.g.dart new file mode 100644 index 000000000..586efed81 --- /dev/null +++ b/packages/ejson/test/person.g.dart @@ -0,0 +1,37 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'person.dart'; + +// ************************************************************************** +// EJsonGenerator +// ************************************************************************** + +EJsonValue _encodePerson(Person value) { + return { + 'name': value.name.toEJson(), + 'birthDate': value.birthDate.toEJson(), + 'income': value.income.toEJson(), + 'spouse': value.spouse.toEJson() + }; +} + +Person _decodePerson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'birthDate': EJsonValue birthDate, + 'income': EJsonValue income, + 'spouse': EJsonValue spouse + } => + Person(fromEJson(name), fromEJson(birthDate), fromEJson(income), + spouse: fromEJson(spouse)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension PersonEJsonEncoderExtension on Person { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodePerson(this); +} + +void registerPerson() => register(_encodePerson, _decodePerson); diff --git a/packages/ejson_analyzer/CHANGELOG.md b/packages/ejson_analyzer/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson_analyzer/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson_analyzer/LICENSE b/packages/ejson_analyzer/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/ejson_analyzer/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/ejson_analyzer/README.md b/packages/ejson_analyzer/README.md new file mode 120000 index 000000000..fe8400541 --- /dev/null +++ b/packages/ejson_analyzer/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/ejson_analyzer/analysis_options.yaml b/packages/ejson_analyzer/analysis_options.yaml new file mode 120000 index 000000000..3a0737064 --- /dev/null +++ b/packages/ejson_analyzer/analysis_options.yaml @@ -0,0 +1 @@ +../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson_analyzer/lib/ejson_analyzer.dart b/packages/ejson_analyzer/lib/ejson_analyzer.dart new file mode 100644 index 000000000..e3e5d9351 --- /dev/null +++ b/packages/ejson_analyzer/lib/ejson_analyzer.dart @@ -0,0 +1,4 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +export 'src/ejson_analyzer_base.dart'; diff --git a/packages/ejson_analyzer/lib/src/ejson_analyzer_base.dart b/packages/ejson_analyzer/lib/src/ejson_analyzer_base.dart new file mode 100644 index 000000000..c2b89c32b --- /dev/null +++ b/packages/ejson_analyzer/lib/src/ejson_analyzer_base.dart @@ -0,0 +1,11 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:analyzer/dart/element/element.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; +import 'package:source_gen/source_gen.dart'; + +TypeChecker get typeChecker => TypeChecker.fromRuntime(EJson); + +EJson getEJsonAnnotation(Element element) => typeChecker.firstAnnotationOfExact(element) as EJson; +bool isEJsonAnnotated(Element element) => typeChecker.hasAnnotationOfExact(element); diff --git a/packages/ejson_analyzer/pubspec.yaml b/packages/ejson_analyzer/pubspec.yaml new file mode 100644 index 000000000..ce68df435 --- /dev/null +++ b/packages/ejson_analyzer/pubspec.yaml @@ -0,0 +1,17 @@ +name: ejson_analyzer +description: A starting point for Dart libraries or applications. + +version: 0.1.0 +repository: https://github.com/realm/realm-dart/ejson/packages/ejson_analyzer + +environment: + sdk: ^3.0.0 + +dependencies: + analyzer: ^6.0.0 + ejson_annotation: ^0.1.0 + source_gen: ^1.3.2 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.21.0 diff --git a/packages/ejson_annotation/CHANGELOG.md b/packages/ejson_annotation/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson_annotation/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson_annotation/LICENSE b/packages/ejson_annotation/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/ejson_annotation/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/ejson_annotation/README.md b/packages/ejson_annotation/README.md new file mode 120000 index 000000000..fe8400541 --- /dev/null +++ b/packages/ejson_annotation/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/ejson_annotation/analysis_options.yaml b/packages/ejson_annotation/analysis_options.yaml new file mode 120000 index 000000000..3a0737064 --- /dev/null +++ b/packages/ejson_annotation/analysis_options.yaml @@ -0,0 +1 @@ +../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson_annotation/lib/ejson_annotation.dart b/packages/ejson_annotation/lib/ejson_annotation.dart new file mode 100644 index 000000000..96d5d6e24 --- /dev/null +++ b/packages/ejson_annotation/lib/ejson_annotation.dart @@ -0,0 +1,23 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +/// Annotation to mark a class for extended json (ejson) serialization +const ejson = EJson(); + +/// Annotation to mark a class for extended json (ejson) serialization +class EJson { + final EJsonEncoder? encoder; + final EJsonDecoder? decoder; + + const EJson._(this.encoder, this.decoder); + const EJson() : this._(null, null); + const EJson.custom({required EJsonEncoder this.encoder, required EJsonDecoder this.decoder}); +} + +typedef EJsonDecoder = T Function(EJsonValue ejson); + +typedef EJsonEncoder = EJsonValue Function(T object); + +// while we wait for +// typedef EJsonValue = Null | String | bool | int | double | List | Map; +typedef EJsonValue = Object?; diff --git a/packages/ejson_annotation/pubspec.yaml b/packages/ejson_annotation/pubspec.yaml new file mode 100644 index 000000000..d316dd0ce --- /dev/null +++ b/packages/ejson_annotation/pubspec.yaml @@ -0,0 +1,15 @@ +name: ejson_annotation +description: >- + Annotation for EJSON serialization. + + BSON is a binary format used to store JSON-like documents efficiently. + EJSON extends JSON defining how all BSON types should be represented in JSON. + +version: 0.1.0 +repository: https://github.com/realm/realm-dart/ejson/packages/ejson_annotation + +environment: + sdk: ^3.0.0 + +dev_dependencies: + lints: ^3.0.0 diff --git a/packages/ejson_generator/CHANGELOG.md b/packages/ejson_generator/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson_generator/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson_generator/LICENSE b/packages/ejson_generator/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/ejson_generator/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/ejson_generator/README.md b/packages/ejson_generator/README.md new file mode 120000 index 000000000..fe8400541 --- /dev/null +++ b/packages/ejson_generator/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/ejson_generator/analysis_options.yaml b/packages/ejson_generator/analysis_options.yaml new file mode 120000 index 000000000..3a0737064 --- /dev/null +++ b/packages/ejson_generator/analysis_options.yaml @@ -0,0 +1 @@ +../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson_generator/build.yaml b/packages/ejson_generator/build.yaml new file mode 100644 index 000000000..450d5362f --- /dev/null +++ b/packages/ejson_generator/build.yaml @@ -0,0 +1,17 @@ +targets: + $default: + builders: + ejson_generator: + enabled: true + generate_for: + include: + - test/** + +builders: + ejson_generator: + import: "package:ejson_generator/ejson_generator.dart" + builder_factories: ["getEJsonGenerator"] + build_extensions: { ".dart": ["ejson.g.part"] } + auto_apply: dependents + build_to: cache + applies_builders: ["source_gen|combining_builder"] diff --git a/packages/ejson_generator/lib/ejson_generator.dart b/packages/ejson_generator/lib/ejson_generator.dart new file mode 100644 index 000000000..7dd0d98fb --- /dev/null +++ b/packages/ejson_generator/lib/ejson_generator.dart @@ -0,0 +1,4 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +export 'src/builder.dart'; diff --git a/packages/ejson_generator/lib/src/builder.dart b/packages/ejson_generator/lib/src/builder.dart new file mode 100644 index 000000000..4f46b17db --- /dev/null +++ b/packages/ejson_generator/lib/src/builder.dart @@ -0,0 +1,11 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:build/build.dart'; +import 'package:source_gen/source_gen.dart'; + +import 'generator.dart'; + +Builder getEJsonGenerator([BuilderOptions? options]) { + return SharedPartBuilder([EJsonGenerator()], 'ejson'); +} diff --git a/packages/ejson_generator/lib/src/generator.dart b/packages/ejson_generator/lib/src/generator.dart new file mode 100644 index 000000000..66fe6fea5 --- /dev/null +++ b/packages/ejson_generator/lib/src/generator.dart @@ -0,0 +1,116 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'dart:async'; + +import 'package:analyzer/dart/element/element.dart'; +import 'package:build/build.dart'; +import 'package:ejson_analyzer/ejson_analyzer.dart'; +import 'package:source_gen/source_gen.dart'; + +enum EJsonError { + tooManyAnnotatedConstructors('Too many annotated constructors'), + tooManyConstructorsOnAnnotatedClass('Too many constructors on annotated class'), + noExplicitConstructor('No explicit constructor'), + missingGetter('Missing getter'), + mismatchedGetterType('Mismatched getter type'); + + final String message; + + const EJsonError(this.message); + + Never raise() { + throw EJsonSourceError._(this); + } +} + +class EJsonSourceError extends InvalidGenerationSourceError { + final EJsonError error; + EJsonSourceError._(this.error) : super(error.message); +} + +/// @nodoc +class EJsonGenerator extends Generator { + const EJsonGenerator(); + + @override + FutureOr generate(LibraryReader library, BuildStep buildStep) async { + // find all classes with annotated constructors or classes directly annotated + final annotated = library.classes.map((cls) => (cls, cls.constructors.where((ctor) => isEJsonAnnotated(ctor)))).where((element) { + final (cls, ctors) = element; + return ctors.isNotEmpty || isEJsonAnnotated(cls); + }); + + return annotated.map((x) { + final (cls, annotatedCtors) = x; + final className = cls.name; + + if (annotatedCtors.length > 1) { + EJsonError.tooManyAnnotatedConstructors.raise(); + } + + if (annotatedCtors.isEmpty) { + // class is directly annotated, and no constructors are annotated. + final annotation = getEJsonAnnotation(cls); + if (annotation.decoder != null && annotation.encoder != null) { + return ''; // class has custom defined encoder and decoder + } + if (cls.constructors.length > 1) { + EJsonError.tooManyConstructorsOnAnnotatedClass.raise(); + } + } + + final ctor = annotatedCtors.singleOrNull ?? cls.constructors.singleOrNull; + if (ctor == null) { + // class is annotated, but has no explicit constructors + EJsonError.noExplicitConstructor.raise(); + } + + for (final p in ctor.parameters) { + // check that all ctor parameters have a getter with the same name and type + final getter = cls.getGetter(p.name); + if (getter == null) { + EJsonError.missingGetter.raise(); + } + if (!TypeChecker.fromStatic(p.type).isAssignableFromType(getter.returnType)) { + EJsonError.mismatchedGetterType.raise(); + } + } + + // generate the codec pair + log.info('Generating EJson for $className'); + return ''' + EJsonValue _encode$className($className value) { + return { + ${ctor.parameters.map((p) => "'${p.name}': value.${p.name}.toEJson()").join(',\n')} + }; + } + + $className _decode$className(EJsonValue ejson) { + return switch (ejson) { + ${decodePattern(ctor.parameters)} => $className${ctor.name.isEmpty ? '' : '.${ctor.name}'}( + ${ctor.parameters.map((p) => "${p.isNamed ? '${p.name} : ' : ''}fromEJson(${p.name})").join(',\n')} + ), + _ => raiseInvalidEJson(ejson), + }; + } + + extension ${className}EJsonEncoderExtension on $className { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encode$className(this); + } + + void register$className() => register(_encode$className, _decode$className); + '''; + }).join('\n\n'); + } +} + +String decodePattern(Iterable parameters) { + if (parameters.isEmpty) { + return 'Map m when m.isEmpty'; + } + return '''{ + ${parameters.map((p) => "'${p.name}': EJsonValue ${p.name}").join(',\n')} + }'''; +} diff --git a/packages/ejson_generator/pubspec.yaml b/packages/ejson_generator/pubspec.yaml new file mode 100644 index 000000000..1119728eb --- /dev/null +++ b/packages/ejson_generator/pubspec.yaml @@ -0,0 +1,35 @@ +name: ejson_generator +description: >- + EJSON serialization. + + BSON is a binary format used to store JSON-like documents efficiently. + EJSON extends JSON defining how all BSON types should be represented in JSON. + +topics: + - ejson + - bson + - json + - build-runner + - codegen + +version: 0.1.0 +repository: https://github.com/realm/realm-dart/ejson/packages/ejson_generator + +environment: + sdk: ^3.0.0 + +dependencies: + analyzer: ^6.0.0 + build: ^2.4.0 + ejson_analyzer: ^0.1.0 + source_gen: ^1.3.2 + +dev_dependencies: + build_runner: ^2.4.4 + build_test: ^2.1.7 + dart_style: ^2.3.1 + ejson: ^0.1.0 + ejson_annotation: ^0.1.0 + lints: ^3.0.0 + meta: ^1.9.1 + test: ^1.21.0 diff --git a/packages/ejson_generator/test/compile_test.dart b/packages/ejson_generator/test/compile_test.dart new file mode 100644 index 000000000..c4006b073 --- /dev/null +++ b/packages/ejson_generator/test/compile_test.dart @@ -0,0 +1,173 @@ +import 'dart:io'; + +import 'package:build_test/build_test.dart'; +import 'package:dart_style/dart_style.dart'; +import 'package:ejson_generator/ejson_generator.dart'; +import 'package:source_gen/source_gen.dart'; +import 'package:test/test.dart'; +import 'package:meta/meta.dart'; + +final _formatter = DartFormatter(lineEnding: '\n'); +final _tag = RegExp(r'// \*.*\n// EJsonGenerator\n// \*.*'); + +@isTest +void testCompile(String description, dynamic source, dynamic matcher, {dynamic skip}) { + source = source is File ? source.readAsStringSync() : source; + if (source is! String) throw ArgumentError.value(source, 'source'); + + matcher = matcher is File ? matcher.readAsStringSync() : matcher; + if (matcher is String) { + final source = _formatter.format(matcher); + matcher = completion(equals(source.substring(_tag.firstMatch(source)?.start ?? 0))); + } + matcher ??= completes; // fallback + + if (matcher is! Matcher) throw ArgumentError.value(matcher, 'matcher'); + + test(description, () { + generate() async { + final writer = InMemoryAssetWriter(); + await testBuilder( + getEJsonGenerator(), + {'pkg|source.dart': source as Object}, + writer: writer, + reader: await PackageAssetReader.currentIsolate(), + ); + return _formatter.format(String.fromCharCodes(writer.assets.entries.single.value)); + } + + expect(generate(), matcher); + }, skip: skip); +} + +Future main() async { + group('user errors', () { + testCompile( + 'two annotated ctors', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +class TwoAnnotatedCtors { + final int i; + @ejson + TwoAnnotatedCtors(this.i); + @ejson + TwoAnnotatedCtors.named(this.i); +} +''', + throwsA(isA().having( + (e) => e.message, + 'message', + 'Too many annotated constructors', + )), + ); + testCompile( + 'missing getter', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +class MissingGetter { + final int _i; // missing a getter for _i called i + @ejson + MissingGetter(int i) : _i = i; +} +''', + throwsA(isA()), + ); + + testCompile( + 'mismatching getter', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +class MismatchingGetter { + final int _i; + String get i => _i.toString(); // getter is not of type int + @ejson + MismatchingGetter(int i) : _i = i; +} +''', + throwsA(isA()), + ); + }); + + group('good', () { + testCompile( + 'private field', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +class PrivateFieldIsOkay { + final int _i; // private fields are okay + @ejson + PrivateFieldIsOkay(this._i); +} +''', + completes, + ); + + testCompile( + 'mismatching getter but custom encoder', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +EJsonValue _encode(MismatchingGetterButCustomEncoder value) => {'i': value._i}; + +class MismatchingGetterButCustomEncoder { + final int _i; + String get i => _i.toString(); // getter is not of type int + @EJson(encoder: _encode) + MismatchingGetterButCustomEncoder(int i) : _i = i; +} +''', + completes, + skip: "don't work yet", + ); + + testCompile( + 'empty class', + r''' +import 'package:ejson/ejson.dart'; +import 'package:ejson_annotation/ejson_annotation.dart'; + +class Empty { + @ejson + const Empty(); +} +''', + ''' +// ************************************************************************** +// EJsonGenerator +// ************************************************************************** + +EJsonValue _encodeEmpty(Empty value) { + return {}; +} + +Empty _decodeEmpty(EJsonValue ejson) { + return switch (ejson) { + Map m when m.isEmpty => Empty(), + _ => raiseInvalidEJson(ejson), + }; +} + +extension EmptyEJsonEncoderExtension on Empty { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeEmpty(this); +} + +void registerEmpty() => register(_encodeEmpty, _decodeEmpty); +''', + ); + }); + + await for (final generatedFile in Directory.current.list(recursive: true).where((f) => f is File && f.path.endsWith('.g.dart'))) { + final sourceFile = File(generatedFile.path.replaceFirst('.g.dart', '.dart')); + testCompile('$sourceFile', sourceFile, generatedFile); + } +} diff --git a/packages/ejson_generator/test/ctor_test.dart b/packages/ejson_generator/test/ctor_test.dart new file mode 100644 index 000000000..e97641993 --- /dev/null +++ b/packages/ejson_generator/test/ctor_test.dart @@ -0,0 +1,131 @@ +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:ejson/ejson.dart'; +import 'package:meta/meta.dart'; +import 'package:test/test.dart'; + +part 'ctor_test.g.dart'; + +class Empty { + @ejson + const Empty(); +} + +class Simple { + final int i; + @ejson + const Simple(this.i); +} + +class Named { + String namedCtor; + @ejson + Named.nameIt(this.namedCtor); +} + +class RequiredNamedParameters { + final String requiredNamed; + @ejson + const RequiredNamedParameters({required this.requiredNamed}); +} + +class OptionalNamedParameters { + String optionalNamed; + @ejson + OptionalNamedParameters({this.optionalNamed = 'rabbit'}); +} + +class OptionalParameters { + String optional; + @ejson + OptionalParameters([this.optional = 'racoon']); +} + +class PrivateMembers { + final int _id; + + int get id => _id; // must match constructor parameter name + + @ejson + const PrivateMembers(int id) : _id = id; // instead of @MapTo +} + +class Person { + final String name; + final DateTime birthDate; + Duration get age => DateTime.now().difference(birthDate); + + final int? cprNumber; + final double income; + final Person? spouse; + + final children = []; + + @ejson // annotate constructor to generate decoder and encoder + Person(this.name, this.birthDate, this.income, {this.spouse, this.cprNumber}); +} + +@isTest +void _testCase(T value, EJsonValue expected) { + test('encode $T to $expected', () { + expect(toEJson(value), expected); + }); + + test('decode $expected to $T', () { + expect(() => fromEJson(expected), returnsNormally); + }); + + EJsonValue badInput = {'bad': 'input'}; + badInput = value is Map ? [badInput] : badInput; // wrap in list for maps + test('decode $badInput to $T fails', () { + expect(() => fromEJson(badInput), throwsA(isA())); + }); + + test('roundtrip $expected as $T', () { + expect(toEJson(fromEJson(expected)), expected); + }); + + test('roundtrip $expected of type $T as dynamic', () { + // no here, so dynamic + final decoded = fromEJson(expected); + expect(decoded, isA()); + expect(toEJson(decoded), expected); + }); +} + +void main() { + group('ctors', () { + registerEmpty(); + registerSimple(); + registerNamed(); + registerRequiredNamedParameters(); + registerOptionalNamedParameters(); + registerOptionalParameters(); + registerPrivateMembers(); + registerPerson(); + + _testCase(const Empty(), {}); + _testCase(const Simple(42), { + 'i': {'\$numberInt': '42'} + }); + _testCase(Named.nameIt('foobar'), {'namedCtor': 'foobar'}); + _testCase(const RequiredNamedParameters(requiredNamed: 'foobar'), {'requiredNamed': 'foobar'}); + _testCase(OptionalNamedParameters(), {'optionalNamed': 'rabbit'}); + _testCase(OptionalParameters(), {'optional': 'racoon'}); + _testCase(const PrivateMembers(42), { + 'id': {'\$numberInt': '42'} + }); + + final birthDate = DateTime.utc(1973); + _testCase(Person('Eva', DateTime.utc(1973), 90000.0), { + 'name': 'Eva', + 'birthDate': { + '\$date': {'\$numberLong': birthDate.millisecondsSinceEpoch.toString()} + }, + 'income': {'\$numberDouble': '90000.0'}, + 'spouse': null, + 'cprNumber': null, + }); + }); +} diff --git a/packages/ejson_generator/test/ctor_test.g.dart b/packages/ejson_generator/test/ctor_test.g.dart new file mode 100644 index 000000000..c0d5dd4c4 --- /dev/null +++ b/packages/ejson_generator/test/ctor_test.g.dart @@ -0,0 +1,174 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'ctor_test.dart'; + +// ************************************************************************** +// EJsonGenerator +// ************************************************************************** + +EJsonValue _encodeEmpty(Empty value) { + return {}; +} + +Empty _decodeEmpty(EJsonValue ejson) { + return switch (ejson) { + Map m when m.isEmpty => Empty(), + _ => raiseInvalidEJson(ejson), + }; +} + +extension EmptyEJsonEncoderExtension on Empty { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeEmpty(this); +} + +void registerEmpty() => register(_encodeEmpty, _decodeEmpty); + +EJsonValue _encodeSimple(Simple value) { + return {'i': value.i.toEJson()}; +} + +Simple _decodeSimple(EJsonValue ejson) { + return switch (ejson) { + {'i': EJsonValue i} => Simple(fromEJson(i)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension SimpleEJsonEncoderExtension on Simple { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeSimple(this); +} + +void registerSimple() => register(_encodeSimple, _decodeSimple); + +EJsonValue _encodeNamed(Named value) { + return {'namedCtor': value.namedCtor.toEJson()}; +} + +Named _decodeNamed(EJsonValue ejson) { + return switch (ejson) { + {'namedCtor': EJsonValue namedCtor} => Named.nameIt(fromEJson(namedCtor)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension NamedEJsonEncoderExtension on Named { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeNamed(this); +} + +void registerNamed() => register(_encodeNamed, _decodeNamed); + +EJsonValue _encodeRequiredNamedParameters(RequiredNamedParameters value) { + return {'requiredNamed': value.requiredNamed.toEJson()}; +} + +RequiredNamedParameters _decodeRequiredNamedParameters(EJsonValue ejson) { + return switch (ejson) { + {'requiredNamed': EJsonValue requiredNamed} => + RequiredNamedParameters(requiredNamed: fromEJson(requiredNamed)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension RequiredNamedParametersEJsonEncoderExtension + on RequiredNamedParameters { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeRequiredNamedParameters(this); +} + +void registerRequiredNamedParameters() => + register(_encodeRequiredNamedParameters, _decodeRequiredNamedParameters); + +EJsonValue _encodeOptionalNamedParameters(OptionalNamedParameters value) { + return {'optionalNamed': value.optionalNamed.toEJson()}; +} + +OptionalNamedParameters _decodeOptionalNamedParameters(EJsonValue ejson) { + return switch (ejson) { + {'optionalNamed': EJsonValue optionalNamed} => + OptionalNamedParameters(optionalNamed: fromEJson(optionalNamed)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension OptionalNamedParametersEJsonEncoderExtension + on OptionalNamedParameters { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeOptionalNamedParameters(this); +} + +void registerOptionalNamedParameters() => + register(_encodeOptionalNamedParameters, _decodeOptionalNamedParameters); + +EJsonValue _encodeOptionalParameters(OptionalParameters value) { + return {'optional': value.optional.toEJson()}; +} + +OptionalParameters _decodeOptionalParameters(EJsonValue ejson) { + return switch (ejson) { + {'optional': EJsonValue optional} => + OptionalParameters(fromEJson(optional)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension OptionalParametersEJsonEncoderExtension on OptionalParameters { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodeOptionalParameters(this); +} + +void registerOptionalParameters() => + register(_encodeOptionalParameters, _decodeOptionalParameters); + +EJsonValue _encodePrivateMembers(PrivateMembers value) { + return {'id': value.id.toEJson()}; +} + +PrivateMembers _decodePrivateMembers(EJsonValue ejson) { + return switch (ejson) { + {'id': EJsonValue id} => PrivateMembers(fromEJson(id)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension PrivateMembersEJsonEncoderExtension on PrivateMembers { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodePrivateMembers(this); +} + +void registerPrivateMembers() => + register(_encodePrivateMembers, _decodePrivateMembers); + +EJsonValue _encodePerson(Person value) { + return { + 'name': value.name.toEJson(), + 'birthDate': value.birthDate.toEJson(), + 'income': value.income.toEJson(), + 'spouse': value.spouse.toEJson(), + 'cprNumber': value.cprNumber.toEJson() + }; +} + +Person _decodePerson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'birthDate': EJsonValue birthDate, + 'income': EJsonValue income, + 'spouse': EJsonValue spouse, + 'cprNumber': EJsonValue cprNumber + } => + Person(fromEJson(name), fromEJson(birthDate), fromEJson(income), + spouse: fromEJson(spouse), cprNumber: fromEJson(cprNumber)), + _ => raiseInvalidEJson(ejson), + }; +} + +extension PersonEJsonEncoderExtension on Person { + @pragma('vm:prefer-inline') + EJsonValue toEJson() => _encodePerson(this); +} + +void registerPerson() => register(_encodePerson, _decodePerson); diff --git a/packages/ejson_lint/CHANGELOG.md b/packages/ejson_lint/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson_lint/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson_lint/LICENSE b/packages/ejson_lint/LICENSE new file mode 120000 index 000000000..30cff7403 --- /dev/null +++ b/packages/ejson_lint/LICENSE @@ -0,0 +1 @@ +../../LICENSE \ No newline at end of file diff --git a/packages/ejson_lint/README.md b/packages/ejson_lint/README.md new file mode 120000 index 000000000..fe8400541 --- /dev/null +++ b/packages/ejson_lint/README.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/packages/ejson_lint/analysis_options.yaml b/packages/ejson_lint/analysis_options.yaml new file mode 120000 index 000000000..3a0737064 --- /dev/null +++ b/packages/ejson_lint/analysis_options.yaml @@ -0,0 +1 @@ +../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson_lint/dart_dependency_validator.yaml b/packages/ejson_lint/dart_dependency_validator.yaml new file mode 100644 index 000000000..84e889b1c --- /dev/null +++ b/packages/ejson_lint/dart_dependency_validator.yaml @@ -0,0 +1,2 @@ +exclude: + - "example/**" # example is its own project \ No newline at end of file diff --git a/packages/ejson_lint/example/.gitignore b/packages/ejson_lint/example/.gitignore new file mode 100644 index 000000000..52b7a51ed --- /dev/null +++ b/packages/ejson_lint/example/.gitignore @@ -0,0 +1,7 @@ +# Don't commit platform specific files for examples +# Use flutter create . --platforms= to generate them +android/ +ios/ +linux/ +macos/ +windows/ diff --git a/packages/ejson_lint/example/CHANGELOG.md b/packages/ejson_lint/example/CHANGELOG.md new file mode 100644 index 000000000..effe43c82 --- /dev/null +++ b/packages/ejson_lint/example/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/packages/ejson_lint/example/README.md b/packages/ejson_lint/example/README.md new file mode 100644 index 000000000..b7bb61e83 --- /dev/null +++ b/packages/ejson_lint/example/README.md @@ -0,0 +1,4 @@ +This project is used to test lint rules using +```shell +dart run custom_lint +``` diff --git a/packages/ejson_lint/example/analysis_options.yaml b/packages/ejson_lint/example/analysis_options.yaml new file mode 120000 index 000000000..d573f89e6 --- /dev/null +++ b/packages/ejson_lint/example/analysis_options.yaml @@ -0,0 +1 @@ +../../../analysis_options.yaml \ No newline at end of file diff --git a/packages/ejson_lint/example/bin/example.dart b/packages/ejson_lint/example/bin/example.dart new file mode 100644 index 000000000..d08534470 --- /dev/null +++ b/packages/ejson_lint/example/bin/example.dart @@ -0,0 +1,29 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:ejson_annotation/ejson_annotation.dart'; + +// This file is used to test lint rules using +// dart run custom_lint +class Person { + final String name; + // expect_lint: mismatched_getter_type + final int age; + + @ejson + // expect_lint: too_many_annotated_constructors + Person(this.name, {required this.age}); + + @ejson + // expect_lint: too_many_annotated_constructors, mismatched_getter_type + Person.second(this.name, double age) : age = age.toInt(); + + @ejson + // expect_lint: too_many_annotated_constructors, missing_getter + Person.third(String navn, int alder) : this(navn, age: alder); +} + +@ejson +class Dog { + late final Person owner; +} diff --git a/packages/ejson_lint/example/dart_dependency_validator.yaml b/packages/ejson_lint/example/dart_dependency_validator.yaml new file mode 100644 index 000000000..55bdce175 --- /dev/null +++ b/packages/ejson_lint/example/dart_dependency_validator.yaml @@ -0,0 +1,4 @@ + +ignore: + # validator mistakenly flags this + - ejson_lint diff --git a/packages/ejson_lint/example/pubspec.yaml b/packages/ejson_lint/example/pubspec.yaml new file mode 100644 index 000000000..171fd2d3c --- /dev/null +++ b/packages/ejson_lint/example/pubspec.yaml @@ -0,0 +1,18 @@ +name: example +description: A sample command-line application. +version: 1.0.0 + +publish_to: none + +environment: + sdk: ^3.0.0 + +dependencies: + ejson_annotation: ^0.1.0 + +dev_dependencies: + custom_lint: ^0.6.2 + ejson_lint: ^0.1.0 + lints: ^3.0.0 + + diff --git a/packages/ejson_lint/lib/ejson_lint.dart b/packages/ejson_lint/lib/ejson_lint.dart new file mode 100644 index 000000000..4014edccf --- /dev/null +++ b/packages/ejson_lint/lib/ejson_lint.dart @@ -0,0 +1,4 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +export 'src/ejson_lint_base.dart'; diff --git a/packages/ejson_lint/lib/src/ejson_lint_base.dart b/packages/ejson_lint/lib/src/ejson_lint_base.dart new file mode 100644 index 000000000..e931818ab --- /dev/null +++ b/packages/ejson_lint/lib/src/ejson_lint_base.dart @@ -0,0 +1,19 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:custom_lint_builder/custom_lint_builder.dart'; + +import 'lints/mismatched_getter_type.dart'; +import 'lints/missing_getter.dart'; +import 'lints/too_many_annotated_constructors.dart'; + +PluginBase createPlugin() => _EJsonLinter(); + +class _EJsonLinter extends PluginBase { + @override + List getLintRules(CustomLintConfigs configs) => [ + TooManyAnnotatedConstructors(), + MissingGetter(), + MismatchedGetterType(), + ]; +} diff --git a/packages/ejson_lint/lib/src/lints/mismatched_getter_type.dart b/packages/ejson_lint/lib/src/lints/mismatched_getter_type.dart new file mode 100644 index 000000000..053806ce0 --- /dev/null +++ b/packages/ejson_lint/lib/src/lints/mismatched_getter_type.dart @@ -0,0 +1,42 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/error/error.dart'; +import 'package:analyzer/error/listener.dart'; +import 'package:custom_lint_builder/custom_lint_builder.dart'; +import 'package:ejson_analyzer/ejson_analyzer.dart'; + +class MismatchedGetterType extends DartLintRule { + MismatchedGetterType() + : super( + code: const LintCode( + name: 'mismatched_getter_type', + problemMessage: 'Type of getter does not match type of constructor parameter', + errorSeverity: ErrorSeverity.ERROR, + ), + ); + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addConstructorDeclaration((node) { + final ctor = node.declaredElement; + if (ctor == null) return; // not resolved; + if (isEJsonAnnotated(ctor)) { + final cls = ctor.enclosingElement as ClassElement; + for (final param in ctor.parameters) { + final getter = cls.getGetter(param.name); + if (getter == null) continue; + if (getter.returnType != param.type) { + reporter.reportErrorForElement(code, getter); + reporter.reportErrorForElement(code, param); + } + } + } + }); + } +} diff --git a/packages/ejson_lint/lib/src/lints/missing_getter.dart b/packages/ejson_lint/lib/src/lints/missing_getter.dart new file mode 100644 index 000000000..a9ac929f4 --- /dev/null +++ b/packages/ejson_lint/lib/src/lints/missing_getter.dart @@ -0,0 +1,38 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/error/error.dart'; +import 'package:analyzer/error/listener.dart'; +import 'package:custom_lint_builder/custom_lint_builder.dart'; +import 'package:ejson_analyzer/ejson_analyzer.dart'; + +class MissingGetter extends DartLintRule { + MissingGetter() + : super( + code: const LintCode( + name: 'missing_getter', + problemMessage: 'Missing getter for constructor parameter', + errorSeverity: ErrorSeverity.ERROR, + ), + ); + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addConstructorDeclaration((node) { + final ctor = node.declaredElement; + if (ctor == null) return; // not resolved; + if (isEJsonAnnotated(ctor)) { + final cls = ctor.enclosingElement as ClassElement; + for (final param in ctor.parameters) { + final getter = cls.getGetter(param.name); + if (getter == null) reporter.reportErrorForElement(code, param); + } + } + }); + } +} diff --git a/packages/ejson_lint/lib/src/lints/too_many_annotated_constructors.dart b/packages/ejson_lint/lib/src/lints/too_many_annotated_constructors.dart new file mode 100644 index 000000000..7dfc7575b --- /dev/null +++ b/packages/ejson_lint/lib/src/lints/too_many_annotated_constructors.dart @@ -0,0 +1,46 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +import 'package:analyzer/error/error.dart'; +import 'package:analyzer/error/listener.dart'; +import 'package:custom_lint_builder/custom_lint_builder.dart'; +import 'package:ejson_analyzer/ejson_analyzer.dart'; + +abstract class EJsonLintRule extends DartLintRule { + EJsonLintRule({required super.code}); + + @override + Future startUp(CustomLintResolver resolver, CustomLintContext context) async { + return await super.startUp(resolver, context); + } +} + +class TooManyAnnotatedConstructors extends DartLintRule { + TooManyAnnotatedConstructors() + : super( + code: const LintCode( + name: 'too_many_annotated_constructors', + problemMessage: 'Only one constructor can be annotated', + errorSeverity: ErrorSeverity.ERROR, + ), + ); + + @override + void run( + CustomLintResolver resolver, + ErrorReporter reporter, + CustomLintContext context, + ) { + context.registry.addClassDeclaration((node) { + final cls = node.declaredElement; + if (cls == null) return; // not resolved; + + final annotatedConstructors = cls.constructors.where((ctor) => isEJsonAnnotated(ctor)); + if (annotatedConstructors.length > 1) { + for (final ctor in annotatedConstructors) { + reporter.reportErrorForElement(code, ctor); + } + } + }); + } +} diff --git a/packages/ejson_lint/pubspec.yaml b/packages/ejson_lint/pubspec.yaml new file mode 100644 index 000000000..53af72f5d --- /dev/null +++ b/packages/ejson_lint/pubspec.yaml @@ -0,0 +1,17 @@ +name: ejson_lint +description: A starting point for Dart libraries or applications. + +version: 0.1.0 +repository: https://github.com/realm/realm-dart/ejson/packages/ejson_lint + +environment: + sdk: ^3.0.0 + +dependencies: + analyzer: ^6.0.0 + custom_lint_builder: ^0.6.2 + ejson_analyzer: ^0.1.0 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.21.0 diff --git a/packages/realm/android/build.gradle b/packages/realm/android/build.gradle index 21b286f03..4469445ba 100644 --- a/packages/realm/android/build.gradle +++ b/packages/realm/android/build.gradle @@ -101,7 +101,7 @@ tasks.register("downloadRealmBinaries", Exec) { def (flutterRoot, dartExecutable) = getPaths() workingDir "${project.rootProject.projectDir}${File.separator}.." - commandLine dartExecutable, 'run', 'realm', 'install', '--target-os-type', 'android', '--flavor', 'flutter' + commandLine dartExecutable, 'run', 'realm', 'install', '--target-os-type', 'android' } def getBundleId() { diff --git a/packages/realm/bin/realm.dart b/packages/realm/bin/realm.dart index 689c19fc8..80569db28 100644 --- a/packages/realm/bin/realm.dart +++ b/packages/realm/bin/realm.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:realm_dart/src/cli/main.dart' as x; void main(List arguments) => x.main(arguments); diff --git a/packages/realm/example/analysis_options.yaml b/packages/realm/example/analysis_options.yaml deleted file mode 100644 index 61b6c4de1..000000000 --- a/packages/realm/example/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/realm/example/analysis_options.yaml b/packages/realm/example/analysis_options.yaml new file mode 120000 index 000000000..d573f89e6 --- /dev/null +++ b/packages/realm/example/analysis_options.yaml @@ -0,0 +1 @@ +../../../analysis_options.yaml \ No newline at end of file diff --git a/packages/realm/example/lib/main.dart b/packages/realm/example/lib/main.dart index 1d84d335b..4e70f5986 100644 --- a/packages/realm/example/lib/main.dart +++ b/packages/realm/example/lib/main.dart @@ -1,23 +1,10 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: avoid_print + import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:realm/realm.dart'; diff --git a/packages/realm/example/lib/main.realm.dart b/packages/realm/example/lib/main.realm.dart index c0cc2b3a5..dfecf73ff 100644 --- a/packages/realm/example/lib/main.realm.dart +++ b/packages/realm/example/lib/main.realm.dart @@ -57,10 +57,37 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + 'model': model.toEJson(), + 'kilometers': kilometers.toEJson(), + 'owner': owner.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + 'model': EJsonValue model, + 'kilometers': EJsonValue kilometers, + 'owner': EJsonValue owner, + } => + Car( + fromEJson(make), + model: fromEJson(model), + kilometers: fromEJson(kilometers), + owner: fromEJson(owner), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string), SchemaProperty('model', RealmPropertyType.string, optional: true), @@ -68,7 +95,7 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('owner', RealmPropertyType.object, optional: true, linkTarget: 'Person'), ]); - } + }(); } class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @@ -106,13 +133,34 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'age': age.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'age': EJsonValue age, + } => + Person( + fromEJson(name), + age: fromEJson(age), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('age', RealmPropertyType.int), ]); - } + }(); } diff --git a/packages/realm/example/pubspec.yaml b/packages/realm/example/pubspec.yaml index 768d677ec..91c108ca3 100644 --- a/packages/realm/example/pubspec.yaml +++ b/packages/realm/example/pubspec.yaml @@ -2,8 +2,6 @@ name: realm_example description: Demonstrates how to use the Realm SDK for Flutter. version: 2.0.0-alpha.2 -# The following line prevents the package from being accidentally published to -# pub.dev using `pub publish`. This is preferred for private packages. publish_to: "none" environment: @@ -13,21 +11,10 @@ environment: dependencies: flutter: sdk: flutter - - realm: - # When depending on this package from a real application you should use: - # realm: ^x.y.z - # See https://dart.dev/tools/pub/dependencies#version-constraints - # The example app is bundled with the plugin so we use a path dependency on - # the parent directory to use the current plugin's version. - path: ../ - - cupertino_icons: ^1.0.3 + realm: ^1.8.0 characters: ^1.1.0 dev_dependencies: - flutter_test: - sdk: flutter flutter_lints: ^3.0.1 flutter: diff --git a/packages/realm/ios/realm.podspec b/packages/realm/ios/realm.podspec index c5bee8091..11a6ed87f 100644 --- a/packages/realm/ios/realm.podspec +++ b/packages/realm/ios/realm.podspec @@ -51,11 +51,11 @@ Pod::Spec.new do |s| 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/**"' } #Use --debug to debug the install command on both prepare_command and script_phase below - s.prepare_command = "source \"#{project_dir}/Flutter/flutter_export_environment.sh\" && cd \"$FLUTTER_APPLICATION_PATH\" && \"$FLUTTER_ROOT/bin/dart\" run realm install --target-os-type ios --flavor flutter" + s.prepare_command = "source \"#{project_dir}/Flutter/flutter_export_environment.sh\" && cd \"$FLUTTER_APPLICATION_PATH\" && \"$FLUTTER_ROOT/bin/dart\" run realm install --target-os-type ios" s.script_phases = [ { :name => 'Download Realm Flutter iOS Binaries', #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 --flavor flutter', + :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', diff --git a/packages/realm/lib/realm.dart b/packages/realm/lib/realm.dart index d8f89a2e2..13dbd21f3 100644 --- a/packages/realm/lib/realm.dart +++ b/packages/realm/lib/realm.dart @@ -1 +1,4 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + export 'package:realm_dart/realm.dart'; diff --git a/packages/realm/linux/CMakeLists.txt b/packages/realm/linux/CMakeLists.txt index 0c36cebe7..688310714 100644 --- a/packages/realm/linux/CMakeLists.txt +++ b/packages/realm/linux/CMakeLists.txt @@ -55,7 +55,7 @@ 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" "run" "realm" "install" "--target-os-type" "linux" "--flavor" "flutter" # "--debug" +execute_process(COMMAND "${FLUTTER_ROOT}/bin/dart" "run" "realm" "install" "--target-os-type" "linux" # "--debug" WORKING_DIRECTORY ${ABSOLUTE_PATH_APP_DIR} OUTPUT_VARIABLE output RESULT_VARIABLE result diff --git a/packages/realm/macos/realm.podspec b/packages/realm/macos/realm.podspec index b054aec32..06f2c16bf 100644 --- a/packages/realm/macos/realm.podspec +++ b/packages/realm/macos/realm.podspec @@ -57,7 +57,7 @@ Pod::Spec.new do |s| s.script_phases = [ { :name => 'Download Realm Flutter macOS Binaries', #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 --flavor flutter', + :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', diff --git a/packages/realm/pubspec.yaml b/packages/realm/pubspec.yaml index c4d482d81..94a0c200f 100644 --- a/packages/realm/pubspec.yaml +++ b/packages/realm/pubspec.yaml @@ -6,8 +6,6 @@ homepage: https://www.realm.io repository: https://github.com/realm/realm-dart issue_tracker: https://github.com/realm/realm-dart/issues -publish_to: none - environment: sdk: ^3.0.0 flutter: ^3.10.0 @@ -15,8 +13,7 @@ environment: dependencies: flutter: sdk: flutter - realm_dart: - path: ../realm_dart + realm_dart: ^1.8.0 flutter: plugin: diff --git a/packages/realm/tests/analysis_options.yaml b/packages/realm/tests/analysis_options.yaml deleted file mode 100644 index 61b6c4de1..000000000 --- a/packages/realm/tests/analysis_options.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/packages/realm/tests/analysis_options.yaml b/packages/realm/tests/analysis_options.yaml new file mode 120000 index 000000000..d573f89e6 --- /dev/null +++ b/packages/realm/tests/analysis_options.yaml @@ -0,0 +1 @@ +../../../analysis_options.yaml \ No newline at end of file diff --git a/packages/realm/tests/integration_test/all_tests.dart b/packages/realm/tests/integration_test/all_tests.dart index f2c0b8043..8cb86c25a 100644 --- a/packages/realm/tests/integration_test/all_tests.dart +++ b/packages/realm/tests/integration_test/all_tests.dart @@ -1,3 +1,6 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:io'; import 'package:flutter/services.dart' show rootBundle; diff --git a/packages/realm/windows/CMakeLists.txt b/packages/realm/windows/CMakeLists.txt index b672b42de..8b8130ada 100644 --- a/packages/realm/windows/CMakeLists.txt +++ b/packages/realm/windows/CMakeLists.txt @@ -47,7 +47,7 @@ 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" "--flavor" "flutter" #"--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 diff --git a/packages/realm_common/lib/realm_common.dart b/packages/realm_common/lib/realm_common.dart index 07818387f..06fbd3ff9 100644 --- a/packages/realm_common/lib/realm_common.dart +++ b/packages/realm_common/lib/realm_common.dart @@ -1,23 +1,8 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 export 'src/realm_common_base.dart'; export 'src/realm_types.dart'; export 'package:objectid/objectid.dart' show ObjectId; -export 'package:sane_uuid/uuid.dart' show Uuid; \ No newline at end of file +export 'package:sane_uuid/uuid.dart' show Uuid; diff --git a/packages/realm_common/lib/src/realm_common_base.dart b/packages/realm_common/lib/src/realm_common_base.dart index e9c7b01b7..caea8a336 100644 --- a/packages/realm_common/lib/src/realm_common_base.dart +++ b/packages/realm_common/lib/src/realm_common_base.dart @@ -1,20 +1,5 @@ -// ////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -// ////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'realm_types.dart'; diff --git a/packages/realm_common/lib/src/realm_types.dart b/packages/realm_common/lib/src/realm_types.dart index c41f8bdb4..36b254b7a 100644 --- a/packages/realm_common/lib/src/realm_types.dart +++ b/packages/realm_common/lib/src/realm_types.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:math'; import 'dart:typed_data'; @@ -127,7 +112,7 @@ class RealmError extends Error { /// An error throw when operating on an object that has been closed. /// {@category Realm} class RealmClosedError extends RealmError { - RealmClosedError(String message) : super(message); + RealmClosedError(super.message); } /// Thrown if the operation is not supported. diff --git a/packages/realm_common/pubspec.yaml b/packages/realm_common/pubspec.yaml index f0988e752..14fe66c46 100644 --- a/packages/realm_common/pubspec.yaml +++ b/packages/realm_common/pubspec.yaml @@ -9,15 +9,13 @@ homepage: https://www.realm.io repository: https://github.com/realm/realm-dart issue_tracker: https://github.com/realm/realm-dart/issues -publish_to: none - environment: sdk: ^3.0.0 dependencies: collection: ^1.18.0 objectid: ^3.0.0 - sane_uuid: ^1.0.0-alpha.4 + sane_uuid: ^1.0.0-alpha.5 dev_dependencies: lints: ^3.0.0 diff --git a/packages/realm_dart/bin/realm_dart.dart b/packages/realm_dart/bin/realm_dart.dart index 689c19fc8..80569db28 100644 --- a/packages/realm_dart/bin/realm_dart.dart +++ b/packages/realm_dart/bin/realm_dart.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:realm_dart/src/cli/main.dart' as x; void main(List arguments) => x.main(arguments); diff --git a/packages/realm_dart/build.yaml b/packages/realm_dart/build.yaml index 48004f652..626a99d8a 100644 --- a/packages/realm_dart/build.yaml +++ b/packages/realm_dart/build.yaml @@ -21,3 +21,4 @@ builders: build_extensions: { ".dart": [".realm.dart"] } auto_apply: dependents build_to: source + runs_before: ["ejson_generator|ejson_generator"] diff --git a/packages/realm_dart/example/analysis_options.yaml b/packages/realm_dart/example/analysis_options.yaml deleted file mode 100644 index dee8927aa..000000000 --- a/packages/realm_dart/example/analysis_options.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# This file configures the static analysis results for your project (errors, -# warnings, and lints). -# -# This enables the 'recommended' set of lints from `package:lints`. -# This set helps identify many issues that may lead to problems when running -# or consuming Dart code, and enforces writing Dart using a single, idiomatic -# style and format. -# -# If you want a smaller set of lints you can change this to specify -# 'package:lints/core.yaml'. These are just the most critical lints -# (the recommended set includes the core lints). -# The core lints are also what is used by pub.dev for scoring packages. - -include: package:lints/recommended.yaml - -# Uncomment the following section to specify additional rules. - -# linter: -# rules: -# - camel_case_types - -# analyzer: -# exclude: -# - path/to/excluded/files/** - -# For more information about the core and recommended set of lints, see -# https://dart.dev/go/core-lints - -# For additional information about configuring this file, see -# https://dart.dev/guides/language/analysis-options diff --git a/packages/realm_dart/example/analysis_options.yaml b/packages/realm_dart/example/analysis_options.yaml new file mode 120000 index 000000000..d573f89e6 --- /dev/null +++ b/packages/realm_dart/example/analysis_options.yaml @@ -0,0 +1 @@ +../../../analysis_options.yaml \ No newline at end of file diff --git a/packages/realm_dart/example/bin/myapp.dart b/packages/realm_dart/example/bin/myapp.dart index ea1835071..7d733ad21 100644 --- a/packages/realm_dart/example/bin/myapp.dart +++ b/packages/realm_dart/example/bin/myapp.dart @@ -1,4 +1,8 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'package:realm_dart/realm.dart'; @@ -15,7 +19,7 @@ class _Car { @RealmModel() class _Person { late String name; - int age = 1; + int age = 42; } void main(List arguments) async { @@ -51,6 +55,15 @@ void main(List arguments) async { var cars = realm.all(); print("There are ${cars.length} cars in the Realm."); + print('Serializing the cars to EJSON.'); + final ejson = toEJson(cars); + final jsonString = JsonEncoder.withIndent(' ').convert(ejson); // ejson is still json + print(jsonString); + print('Deserializing the EJSON back to objects.'); + final decoded = fromEJson>(jsonDecode(jsonString)); // decode objects are always unmanaged + print('Adding the deserialized cars back to the Realm, creating duplicates.'); + realm.write(() => realm.addAll(decoded)); // add duplicates back + var indexedCar = cars[0]; print('The first car is ${indexedCar.make} ${indexedCar.model}'); @@ -62,7 +75,7 @@ void main(List arguments) async { await Future.delayed(Duration(milliseconds: 1)); realm.close(); - + //This is only needed in Dart apps as a workaround for https://github.com/dart-lang/sdk/issues/49083 Realm.shutdown(); print("Done"); diff --git a/packages/realm_dart/example/bin/myapp.realm.dart b/packages/realm_dart/example/bin/myapp.realm.dart index e2e05c69b..f6681c65e 100644 --- a/packages/realm_dart/example/bin/myapp.realm.dart +++ b/packages/realm_dart/example/bin/myapp.realm.dart @@ -57,10 +57,37 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + 'model': model.toEJson(), + 'kilometers': kilometers.toEJson(), + 'owner': owner.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + 'model': EJsonValue model, + 'kilometers': EJsonValue kilometers, + 'owner': EJsonValue owner, + } => + Car( + fromEJson(make), + model: fromEJson(model), + kilometers: fromEJson(kilometers), + owner: fromEJson(owner), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string), SchemaProperty('model', RealmPropertyType.string, optional: true), @@ -68,7 +95,7 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('owner', RealmPropertyType.object, optional: true, linkTarget: 'Person'), ]); - } + }(); } class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @@ -76,11 +103,11 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { Person( String name, { - int age = 1, + int age = 42, }) { if (!_defaultsSet) { _defaultsSet = RealmObjectBase.setDefaults({ - 'age': 1, + 'age': 42, }); } RealmObjectBase.set(this, 'name', name); @@ -106,13 +133,34 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'age': age.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'age': EJsonValue age, + } => + Person( + fromEJson(name), + age: fromEJson(age), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('age', RealmPropertyType.int), ]); - } + }(); } diff --git a/packages/realm_dart/lib/realm.dart b/packages/realm_dart/lib/realm.dart index 1ed53d3b6..70bd5dc37 100644 --- a/packages/realm_dart/lib/realm.dart +++ b/packages/realm_dart/lib/realm.dart @@ -1,21 +1,6 @@ -// ////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -// ////////////////////////////////////////////////////////////////////////////// - +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 //dart.library.cli is available only on dart desktop -export 'src/realm_flutter.dart' if (dart.library.cli) 'src/realm_dart.dart'; \ No newline at end of file +export 'src/realm_flutter.dart' if (dart.library.cli) 'src/realm_dart.dart'; +export 'package:ejson/ejson.dart'; diff --git a/packages/realm_dart/lib/src/app.dart b/packages/realm_dart/lib/src/app.dart index bf0c5f62c..76757ac59 100644 --- a/packages/realm_dart/lib/src/app.dart +++ b/packages/realm_dart/lib/src/app.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:convert'; import 'dart:ffi'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/archive/archive_command.dart b/packages/realm_dart/lib/src/cli/archive/archive_command.dart index 696205fa7..715b12d02 100644 --- a/packages/realm_dart/lib/src/cli/archive/archive_command.dart +++ b/packages/realm_dart/lib/src/cli/archive/archive_command.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/archive/options.dart b/packages/realm_dart/lib/src/cli/archive/options.dart index 2c388ad16..1fb7e6f75 100644 --- a/packages/realm_dart/lib/src/cli/archive/options.dart +++ b/packages/realm_dart/lib/src/cli/archive/options.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:build_cli_annotations/build_cli_annotations.dart'; @@ -22,9 +7,9 @@ part 'options.g.dart'; @CliOptions() class Options { - @CliOption(help: "This option is required") + @CliOption(help: "This option is required") final String? sourceDir; - @CliOption(help: "This option is required") + @CliOption(help: "This option is required") final String? outputFile; Options({this.sourceDir, this.outputFile}); 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 index dba3f0d6d..1ab83f00f 100644 --- a/packages/realm_dart/lib/src/cli/atlas_apps/baas_client.dart +++ b/packages/realm_dart/lib/src/cli/atlas_apps/baas_client.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:collection/collection.dart'; import 'package:http/http.dart' as http; @@ -200,7 +185,9 @@ class BaasClient { } static Future> _getContainers(BaasAuthHelper helper, {String? differentiator}) async { - var result = (await helper.callEndpoint('listContainers', isPost: false) as List).map((e) => _ContainerInfo.fromJson(e)).whereNotNull(); + 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); @@ -282,7 +269,7 @@ class BaasClient { try { final response = await _get('groups/$_groupId/apps/$appId/sync/progress'); - Map progressInfo = response['progress']; + final progressInfo = response['progress'] as Map; for (final key in progressInfo.keys) { final namespaceComplete = progressInfo[key]['complete'] as bool; @@ -736,7 +723,7 @@ class _ContainerInfo { } final id = json['id'] as String; - final lastStatus = json['lastStatus']; + 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; 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 index 64a6802a4..9f7ad8974 100644 --- a/packages/realm_dart/lib/src/cli/atlas_apps/deleteapps_command.dart +++ b/packages/realm_dart/lib/src/cli/atlas_apps/deleteapps_command.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; 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 index 8e3b72414..8948c3945 100644 --- a/packages/realm_dart/lib/src/cli/atlas_apps/deployapps_command.dart +++ b/packages/realm_dart/lib/src/cli/atlas_apps/deployapps_command.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/atlas_apps/options.dart b/packages/realm_dart/lib/src/cli/atlas_apps/options.dart index b98658b83..74019898c 100644 --- a/packages/realm_dart/lib/src/cli/atlas_apps/options.dart +++ b/packages/realm_dart/lib/src/cli/atlas_apps/options.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:build_cli_annotations/build_cli_annotations.dart'; diff --git a/packages/realm_dart/lib/src/cli/common/archive.dart b/packages/realm_dart/lib/src/cli/common/archive.dart index 0fb412bd4..23ab1dcbb 100644 --- a/packages/realm_dart/lib/src/cli/common/archive.dart +++ b/packages/realm_dart/lib/src/cli/common/archive.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + /// import 'dart:io'; import 'package:tar/tar.dart'; diff --git a/packages/realm_dart/lib/src/cli/common/target_os_type.dart b/packages/realm_dart/lib/src/cli/common/target_os_type.dart index 8defefbe3..f87d958b6 100644 --- a/packages/realm_dart/lib/src/cli/common/target_os_type.dart +++ b/packages/realm_dart/lib/src/cli/common/target_os_type.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'utils.dart'; diff --git a/packages/realm_dart/lib/src/cli/common/utils.dart b/packages/realm_dart/lib/src/cli/common/utils.dart index 20e8ecc82..c7d5c0851 100644 --- a/packages/realm_dart/lib/src/cli/common/utils.dart +++ b/packages/realm_dart/lib/src/cli/common/utils.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/extract/extract_command.dart b/packages/realm_dart/lib/src/cli/extract/extract_command.dart index 2b8f2816d..a7dee75e5 100644 --- a/packages/realm_dart/lib/src/cli/extract/extract_command.dart +++ b/packages/realm_dart/lib/src/cli/extract/extract_command.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/extract/options.dart b/packages/realm_dart/lib/src/cli/extract/options.dart index 55dd75f7d..bb529f8b2 100644 --- a/packages/realm_dart/lib/src/cli/extract/options.dart +++ b/packages/realm_dart/lib/src/cli/extract/options.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:build_cli_annotations/build_cli_annotations.dart'; @@ -22,9 +7,9 @@ part 'options.g.dart'; @CliOptions() class Options { - @CliOption(help: "This option is required") + @CliOption(help: "This option is required") final String? outputDir; - @CliOption(help: "This option is required") + @CliOption(help: "This option is required") final String? sourceFile; Options({this.sourceFile, this.outputDir}); diff --git a/packages/realm_dart/lib/src/cli/generate/generate_command.dart b/packages/realm_dart/lib/src/cli/generate/generate_command.dart index 0ec86fe6d..9cdb91268 100644 --- a/packages/realm_dart/lib/src/cli/generate/generate_command.dart +++ b/packages/realm_dart/lib/src/cli/generate/generate_command.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/generate/options.dart b/packages/realm_dart/lib/src/cli/generate/options.dart index 8a460a3ca..a426bdf20 100644 --- a/packages/realm_dart/lib/src/cli/generate/options.dart +++ b/packages/realm_dart/lib/src/cli/generate/options.dart @@ -1,3 +1,6 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:build_cli_annotations/build_cli_annotations.dart'; part 'options.g.dart'; @@ -7,7 +10,10 @@ class Options { @CliOption(defaultsTo: false, help: "Optional. Cleans generator caches. Same as running 'dart run build_runner clean'") bool clean = false; - @CliOption(defaultsTo: false, help: "Optional. Watches for changes and generates RealmObjects classes on the background. Same as running 'dart run build_runner watch --delete-conflicting-outputs'") + @CliOption( + defaultsTo: false, + help: + "Optional. Watches for changes and generates RealmObjects classes on the background. Same as running 'dart run build_runner watch --delete-conflicting-outputs'") bool watch = false; } diff --git a/packages/realm_dart/lib/src/cli/install/install_command.dart b/packages/realm_dart/lib/src/cli/install/install_command.dart index f92407628..8c92a756b 100644 --- a/packages/realm_dart/lib/src/cli/install/install_command.dart +++ b/packages/realm_dart/lib/src/cli/install/install_command.dart @@ -1,24 +1,10 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; +import 'package:pub_semver/pub_semver.dart'; import 'package:pubspec_parse/pubspec_parse.dart'; import 'package:args/command_runner.dart'; import 'package:package_config/package_config.dart'; @@ -26,11 +12,10 @@ import 'package:path/path.dart' as path; import '../common/target_os_type.dart'; import '../common/archive.dart'; -import '../common/utils.dart'; import 'options.dart'; class InstallCommand extends Command { - static const versionFileName = "realm_version.txt"; + static const versionFileName = 'realm_version.txt'; @override final description = 'Download & install Realm native binaries into a Flutter or Dart project'; @@ -40,58 +25,26 @@ class InstallCommand extends Command { late Options options; - String get packageName => options.flavor.packageName; - - bool get isFlutter => options.flavor == Flavor.flutter; - bool get isDart => options.flavor == Flavor.dart; bool get debug => options.debug; InstallCommand() { populateOptionsParser(argParser); } - String getBinaryPath(String realmPackagePath) { + Directory getBinaryPath(Package realmPackage, {required bool isFlutter}) { + final realmPackagePath = realmPackage.root.toFilePath(); if (isFlutter) { - switch (options.targetOsType) { - case TargetOsType.android: - return path.join(realmPackagePath, "android", "src", "main", "cpp", "lib"); - case TargetOsType.ios: - return path.join(realmPackagePath, "ios"); - case TargetOsType.macos: - return path.join(realmPackagePath, "macos"); - case TargetOsType.linux: - return path.join(realmPackagePath, "linux", "binary", "linux"); - case TargetOsType.windows: - return path.join(realmPackagePath, "windows", "binary", "windows"); - default: - throw Exception("Unsupported target OS type for Flutter: ${options.targetOsType}"); - } - } - - if (isDart) { - return path.join(Directory.current.absolute.path, 'binary', options.targetOsType!.name); - } - - throw Exception("Unsupported package name: $packageName"); - } - - Future shouldSkipInstall(Pubspec realmPubspec) async { - final pubspecFile = await File("pubspec.yaml").readAsString(); - final projectPubspec = Pubspec.parse(pubspecFile); - - if (Flavor.values.map((f) => f.packageName).contains(projectPubspec.name)) { - print(// - 'Running install command inside ${projectPubspec.name} package which is the development package for Realm.\n' - 'Skipping download as it is expected that you build the packages manually.'); - return true; - } - - if (realmPubspec.publishTo == 'none' && !debug) { - print("Referencing $packageName@${realmPubspec.version} which hasn't been published (publish_to: none). Skipping download."); - return true; - } - - return false; + return Directory(switch (options.targetOsType) { + TargetOsType.android => path.join(realmPackagePath, 'android', 'src', 'main', 'cpp', 'lib'), + TargetOsType.ios => path.join(realmPackagePath, 'ios'), + TargetOsType.macos => path.join(realmPackagePath, 'macos'), + TargetOsType.linux => path.join(realmPackagePath, 'linux', 'binary', 'linux'), + TargetOsType.windows => path.join(realmPackagePath, 'windows', 'binary', 'windows'), + _ => throw Exception('Unsupported target OS type for Flutter: ${options.targetOsType}') + }); + } + // TODO: Should binaries not go into package also for Dart? + return Directory(path.join(Directory.current.absolute.path, 'binary', options.targetOsType!.name)); } Future shouldSkipDownload(String binariesPath, String expectedVersion) async { @@ -99,15 +52,15 @@ class InstallCommand extends Command { if (await versionsFile.exists()) { final existingVersion = await versionsFile.readAsString(); if (expectedVersion == existingVersion) { - print("Realm binaries for $packageName@$expectedVersion already downloaded"); + print('Realm binaries for $expectedVersion already downloaded'); return true; } } return false; } - Future downloadAndExtractBinaries(Directory destinationDir, Pubspec realmPubspec, String archiveName) async { - if (await shouldSkipDownload(destinationDir.absolute.path, realmPubspec.version.toString())) { + Future downloadAndExtractBinaries(Directory destinationDir, Version version, String archiveName) async { + if (await shouldSkipDownload(destinationDir.absolute.path, version.toString())) { return; } @@ -120,9 +73,9 @@ class InstallCommand extends Command { await destinationFile.parent.create(recursive: true); } - print("Downloading Realm binaries for $packageName@${realmPubspec.version} to ${destinationFile.absolute.path}"); + print('Downloading Realm binaries for $version to ${destinationFile.absolute.path}'); final client = HttpClient(); - var url = 'https://static.realm.io/downloads/dart/${Uri.encodeComponent(realmPubspec.version.toString())}/$archiveName'; + var url = 'https://static.realm.io/downloads/dart/${Uri.encodeComponent(version.toString())}/$archiveName'; if (debug) { url = 'http://localhost:8000/$archiveName'; } @@ -130,7 +83,7 @@ class InstallCommand extends Command { final request = await client.getUrl(Uri.parse(url)); final response = await request.close(); if (response.statusCode >= 400) { - throw Exception("Error downloading Realm binaries from $url. Error code: ${response.statusCode}"); + throw Exception('Error downloading Realm binaries from $url. Error code: ${response.statusCode}'); } await response.pipe(destinationFile.openWrite()); } @@ -139,77 +92,73 @@ class InstallCommand extends Command { client.close(force: true); } - print("Extracting Realm binaries to ${destinationDir.absolute.path}"); + print('Extracting Realm binaries to ${destinationDir.absolute.path}'); final archive = Archive(); await archive.extract(destinationFile, destinationDir); final versionFile = File(path.join(destinationDir.absolute.path, versionFileName)); - await versionFile.writeAsString("${realmPubspec.version}"); + await versionFile.writeAsString(version.toString()); } - Future getRealmPackagePath() async { + Future getPackage(String name) async { final packageConfig = await findPackageConfig(Directory.current); if (packageConfig == null) { - throw Exception("Package configuration not found. " - "Run the 'dart run $packageName install` command from the root directory of your application"); + abort('Run `dart pub get`'); } - - final package = packageConfig.packages.where((p) => p.name == Flavor.flutter.packageName || p.name == Flavor.dart.packageName).firstOrNull; + final package = packageConfig.packages.where((p) => p.name == name).singleOrNull; if (package == null) { - throw Exception("$packageName package not found in dependencies. Add $packageName package to your pubspec.yaml"); + abort('$name package not found in dependencies. Add $name package to your pubspec.yaml'); } - - if (package.root.scheme != 'file') { - throw Exception("$packageName package uri ${package.root} is not supported. Uri should start with file://"); - } - - final packagePath = path.join(package.root.toFilePath(), "pubspec.yaml"); - return packagePath; + return package; } - Future parsePubspec(String path) async { + Future parsePubspec(File file) async { try { - return Pubspec.parse(await File(path).readAsString()); + return Pubspec.parse(await file.readAsString(), sourceUrl: file.uri); } on Exception catch (e) { - throw Exception("Error parsing package pubspec at $path. Error $e"); + throw Exception('Error parsing package pubspec at ${file.parent}. Error $e'); } } @override FutureOr run() async { - options = parseOptionsResult(argResults!); - validateOptions(); + final pubspec = await parsePubspec(File('pubspec.yaml')); + final flavor = pubspec.dependencies['flutter'] == null ? Flavor.dart : Flavor.flutter; - final realmPackagePath = await getRealmPackagePath(); - final realmPubspec = await parsePubspec(realmPackagePath); + options = parseOptionsResult(argResults!); + validateOptions(flavor); - if (!options.force && await shouldSkipInstall(realmPubspec)) { + final flavorName = flavor.packageName; + final realmDependency = pubspec.dependencyOverrides[flavorName] ?? pubspec.dependencies[flavorName]; + if (realmDependency is PathDependency) { + print('Path dependency for $flavorName found. Skipping install of native lib (assuming local development)'); return; } + if (realmDependency == null) { + abort('Package $flavorName not found in dependencies. Add $flavorName package to your pubspec.yaml'); + // TODO: Should we just add it for them? What about the version? + } - final binaryPath = Directory(getBinaryPath(path.dirname(realmPackagePath))); - final archiveName = "${options.targetOsType!.name}.tar.gz"; - await downloadAndExtractBinaries(binaryPath, realmPubspec, archiveName); + final realmPackage = await getPackage(flavorName); + final realmPubspec = await parsePubspec(File.fromUri(realmPackage.root)); + final binaryPath = getBinaryPath(realmPackage, isFlutter: flavor == Flavor.flutter); + print(binaryPath); + final archiveName = '${options.targetOsType!.name}.tar.gz'; + await downloadAndExtractBinaries(binaryPath, realmPubspec.version!, archiveName); - print("Realm install command finished."); + print('Realm install command finished.'); } - void validateOptions() { - if (isFlutter) { - if (options.targetOsType == null) { - abort("Invalid target OS: null."); - } - } else { - options.targetOsType ??= getTargetOS(); - if ((options.targetOsType == TargetOsType.ios || options.targetOsType == TargetOsType.android) && isDart) { - throw Exception("Invalid package name $packageName for target OS ${options.targetOsType}"); - } + void validateOptions(Flavor flavor) { + final targetOs = flavor == Flavor.dart ? getTargetOS() : options.targetOsType; + if (targetOs == null) { + abort('Target OS not specified'); } } - TargetOsType getTargetOS() => Platform.operatingSystem.asTargetOsType ?? (throw UnsupportedError("Unsupported platform ${Platform.operatingSystem}")); + TargetOsType getTargetOS() => Platform.operatingSystem.asTargetOsType ?? (throw UnsupportedError('Unsupported platform ${Platform.operatingSystem}')); - void abort(String error) { + Never abort(String error) { print(error); print(usage); exit(64); //usage error diff --git a/packages/realm_dart/lib/src/cli/install/options.dart b/packages/realm_dart/lib/src/cli/install/options.dart index b67f4830f..f9c1440b6 100644 --- a/packages/realm_dart/lib/src/cli/install/options.dart +++ b/packages/realm_dart/lib/src/cli/install/options.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:build_cli_annotations/build_cli_annotations.dart'; import '../common/target_os_type.dart'; @@ -26,9 +11,6 @@ class Options { @CliOption(help: 'The target OS to install binaries for.', abbr: 't') TargetOsType? targetOsType; - @CliOption(help: 'The flavor to install binaries for.', abbr: 'f', defaultsTo: Flavor.dart) - Flavor flavor; - // use to debug install command @CliOption(hide: true, help: 'Download binary from http://localhost:8000/.', defaultsTo: false) bool debug; @@ -36,7 +18,7 @@ class Options { @CliOption(hide: true, help: 'Force install, even if we would normally skip it.', defaultsTo: false) bool force; - Options({this.targetOsType, this.flavor = Flavor.dart, this.force = false, this.debug = false}); + Options({this.targetOsType, this.force = false, this.debug = false}); } String get usage => _$parserForOptions.usage; diff --git a/packages/realm_dart/lib/src/cli/install/options.g.dart b/packages/realm_dart/lib/src/cli/install/options.g.dart index 0da5c69cf..f0a4e6e05 100644 --- a/packages/realm_dart/lib/src/cli/install/options.g.dart +++ b/packages/realm_dart/lib/src/cli/install/options.g.dart @@ -28,10 +28,6 @@ Options _$parseOptionsResult(ArgResults result) => Options( _$TargetOsTypeEnumMapBuildCli, result['target-os-type'] as String?, ), - flavor: _$enumValueHelper( - _$FlavorEnumMapBuildCli, - result['flavor'] as String, - ), force: result['force'] as bool, debug: result['debug'] as bool, ); @@ -44,11 +40,6 @@ const _$TargetOsTypeEnumMapBuildCli = { TargetOsType.windows: 'windows' }; -const _$FlavorEnumMapBuildCli = { - Flavor.flutter: 'flutter', - Flavor.dart: 'dart' -}; - ArgParser _$populateOptionsParser(ArgParser parser) => parser ..addOption( 'target-os-type', @@ -56,13 +47,6 @@ ArgParser _$populateOptionsParser(ArgParser parser) => parser help: 'The target OS to install binaries for.', allowed: ['android', 'ios', 'linux', 'macos', 'windows'], ) - ..addOption( - 'flavor', - abbr: 'f', - help: 'The flavor to install binaries for.', - defaultsTo: 'dart', - allowed: ['flutter', 'dart'], - ) ..addFlag( 'debug', help: 'Download binary from http://localhost:8000/.', diff --git a/packages/realm_dart/lib/src/cli/main.dart b/packages/realm_dart/lib/src/cli/main.dart index 9a5ac019c..002ff3a19 100644 --- a/packages/realm_dart/lib/src/cli/main.dart +++ b/packages/realm_dart/lib/src/cli/main.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart b/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart index ef26e18a7..47c6b58b3 100644 --- a/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart +++ b/packages/realm_dart/lib/src/cli/metrics/flutter_info.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:json_annotation/json_annotation.dart'; import 'package:pub_semver/pub_semver.dart'; diff --git a/packages/realm_dart/lib/src/cli/metrics/metrics.dart b/packages/realm_dart/lib/src/cli/metrics/metrics.dart index 5b3137a5d..a5a0465d2 100644 --- a/packages/realm_dart/lib/src/cli/metrics/metrics.dart +++ b/packages/realm_dart/lib/src/cli/metrics/metrics.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:convert'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart b/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart index b0d551df8..5f9b342b7 100644 --- a/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart +++ b/packages/realm_dart/lib/src/cli/metrics/metrics_command.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; import 'dart:convert'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/cli/metrics/options.dart b/packages/realm_dart/lib/src/cli/metrics/options.dart index 8cb528db6..99a9a0577 100644 --- a/packages/realm_dart/lib/src/cli/metrics/options.dart +++ b/packages/realm_dart/lib/src/cli/metrics/options.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// 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; diff --git a/packages/realm_dart/lib/src/collections.dart b/packages/realm_dart/lib/src/collections.dart index 73a29645a..d41d450a0 100644 --- a/packages/realm_dart/lib/src/collections.dart +++ b/packages/realm_dart/lib/src/collections.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:ffi'; import 'native/realm_core.dart'; diff --git a/packages/realm_dart/lib/src/configuration.dart b/packages/realm_dart/lib/src/configuration.dart index dc59c3ec2..1274c55a7 100644 --- a/packages/realm_dart/lib/src/configuration.dart +++ b/packages/realm_dart/lib/src/configuration.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:ffi'; @@ -646,7 +631,7 @@ class SyncError extends RealmError { /// The code that describes this error. final SyncErrorCode code; - SyncError._(String message, this.code, this.innerError) : super(message); + SyncError._(super.message, this.code, this.innerError); final Object? innerError; diff --git a/packages/realm_dart/lib/src/credentials.dart b/packages/realm_dart/lib/src/credentials.dart index ab6291c72..9519fee41 100644 --- a/packages/realm_dart/lib/src/credentials.dart +++ b/packages/realm_dart/lib/src/credentials.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:convert'; import 'dart:ffi'; diff --git a/packages/realm_dart/lib/src/init.dart b/packages/realm_dart/lib/src/init.dart index d554e7674..f354200a1 100644 --- a/packages/realm_dart/lib/src/init.dart +++ b/packages/realm_dart/lib/src/init.dart @@ -1,3 +1,6 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:ffi'; import 'dart:io'; diff --git a/packages/realm_dart/lib/src/list.dart b/packages/realm_dart/lib/src/list.dart index e97892538..de5257ae4 100644 --- a/packages/realm_dart/lib/src/list.dart +++ b/packages/realm_dart/lib/src/list.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:core'; import 'dart:async'; @@ -221,9 +206,7 @@ class UnmanagedRealmList extends collection.DelegatingList UnmanagedRealmList([Iterable? items]) : this._(List.from(items ?? [])); - UnmanagedRealmList._(List items) - : _base = items, - super(items); + UnmanagedRealmList._(super.items) : _base = items; @override RealmObjectMetadata? get _metadata => throw RealmException("Unmanaged lists don't have metadata associated with them."); diff --git a/packages/realm_dart/lib/src/map.dart b/packages/realm_dart/lib/src/map.dart index fc3c64bbc..c7b9f7208 100644 --- a/packages/realm_dart/lib/src/map.dart +++ b/packages/realm_dart/lib/src/map.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:collection'; @@ -53,9 +38,7 @@ class UnmanagedRealmMap extends collection.DelegatingMap? items]) : this._(Map.from(items ?? {})); - UnmanagedRealmMap._(Map items) - : _base = items, - super(items); + UnmanagedRealmMap._(super.items) : _base = items; @override bool get isValid => true; diff --git a/packages/realm_dart/lib/src/migration.dart b/packages/realm_dart/lib/src/migration.dart index e5e84aa12..7c02226a1 100644 --- a/packages/realm_dart/lib/src/migration.dart +++ b/packages/realm_dart/lib/src/migration.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'realm_class.dart'; import 'native/realm_core.dart'; diff --git a/packages/realm_dart/lib/src/native/decimal128.dart b/packages/realm_dart/lib/src/native/decimal128.dart index 834550100..9d0039bbf 100644 --- a/packages/realm_dart/lib/src/native/decimal128.dart +++ b/packages/realm_dart/lib/src/native/decimal128.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 part of 'realm_core.dart'; diff --git a/packages/realm_dart/lib/src/native/realm_core.dart b/packages/realm_dart/lib/src/native/realm_core.dart index fa300777e..513e1316f 100644 --- a/packages/realm_dart/lib/src/native/realm_core.dart +++ b/packages/realm_dart/lib/src/native/realm_core.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + // ignore_for_file: non_constant_identifier_names import 'dart:async'; @@ -114,7 +100,7 @@ class _RealmCore { // This disables creation of a second _RealmCore instance effectivelly making `realmCore` global variable readonly _instance = this; - // This prevents reentrancy if `realmCore` global variable is accessed during _RealmCore construction + // This prevents reentrance if `realmCore` global variable is accessed during _RealmCore construction realmCore = this; defaultRealmLogger = _initDefaultLogger(scheduler); } @@ -3177,13 +3163,13 @@ abstract class RootedHandleBase extends HandleBase { } abstract class CollectionHandleBase extends RootedHandleBase { - CollectionHandleBase(RealmHandle root, Pointer pointer, int size) : super(root, pointer, size); + CollectionHandleBase(super.root, super.pointer, super.size); } class SchemaHandle extends HandleBase { SchemaHandle._(Pointer pointer) : super(pointer, 24); - SchemaHandle.unowned(Pointer pointer) : super.unowned(pointer); + SchemaHandle.unowned(super.pointer) : super.unowned(); } class ConfigHandle extends HandleBase { @@ -3197,7 +3183,7 @@ class RealmHandle extends HandleBase { RealmHandle._(Pointer pointer) : super(pointer, 24); - RealmHandle._unowned(Pointer pointer) : super.unowned(pointer); + RealmHandle._unowned(super.pointer) : super.unowned(); int addChild(RootedHandleBase child) { final id = _counter++; diff --git a/packages/realm_dart/lib/src/realm_class.dart b/packages/realm_dart/lib/src/realm_class.dart index 6f33d1760..dee780af9 100644 --- a/packages/realm_dart/lib/src/realm_class.dart +++ b/packages/realm_dart/lib/src/realm_class.dart @@ -1,25 +1,9 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:ffi'; import 'dart:io'; -import 'dart:typed_data'; import 'package:cancellation_token/cancellation_token.dart'; import 'package:collection/collection.dart'; @@ -93,21 +77,7 @@ export "configuration.dart" SchemaObject, ShouldCompactCallback, SyncError, - SyncErrorHandler, - // ignore: deprecated_member_use_from_same_package - SyncClientError, - // ignore: deprecated_member_use_from_same_package - SyncConnectionError, - // ignore: deprecated_member_use_from_same_package - GeneralSyncError, - // ignore: deprecated_member_use_from_same_package - GeneralSyncErrorCode, - // ignore: deprecated_member_use_from_same_package - SyncResolveError, - // ignore: deprecated_member_use_from_same_package - SyncWebSocketError, - // ignore: deprecated_member_use_from_same_package - SyncSessionError; + SyncErrorHandler; export 'credentials.dart' show AuthProviderType, Credentials, EmailPasswordAuthProvider; export 'list.dart' show RealmList, RealmListOfObject, RealmListChanges, ListExtension; export 'set.dart' show RealmSet, RealmSetChanges, RealmSetOfObject; @@ -127,28 +97,7 @@ export 'realm_object.dart' 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, - // ignore: deprecated_member_use_from_same_package - SyncClientErrorCode, - // ignore: deprecated_member_use_from_same_package - SyncConnectionErrorCode, - // ignore: deprecated_member_use_from_same_package - SyncErrorCategory, - // ignore: deprecated_member_use_from_same_package - SyncResolveErrorCode, - // ignore: deprecated_member_use_from_same_package - SyncWebSocketErrorCode, - // ignore: deprecated_member_use_from_same_package - SyncSessionErrorCode; +export 'session.dart' show ConnectionStateChange, SyncProgress, ProgressDirection, ProgressMode, ConnectionState, Session, SessionState, SyncErrorCode; export 'subscription.dart' show Subscription, SubscriptionSet, SubscriptionSetState, MutableSubscriptionSet; export 'user.dart' show User, UserState, ApiKeyClient, UserIdentity, ApiKey, FunctionsClient, UserChanges; export 'native/realm_core.dart' show Decimal128; @@ -1021,7 +970,7 @@ class MigrationRealm extends DynamicRealm { /// the schema will be read from the file. RealmSchema get schema => _realm.schema; - MigrationRealm._(Realm realm) : super._(realm); + MigrationRealm._(super.realm) : super._(); } /// The signature of a callback that will be executed while the Realm is opened asynchronously with [Realm.open]. diff --git a/packages/realm_dart/lib/src/realm_dart.dart b/packages/realm_dart/lib/src/realm_dart.dart index 03e96830a..9de3c2278 100644 --- a/packages/realm_dart/lib/src/realm_dart.dart +++ b/packages/realm_dart/lib/src/realm_dart.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 export 'realm_class.dart' hide RealmInternal; diff --git a/packages/realm_dart/lib/src/realm_flutter.dart b/packages/realm_dart/lib/src/realm_flutter.dart index 821621def..cb7b7e9d6 100644 --- a/packages/realm_dart/lib/src/realm_flutter.dart +++ b/packages/realm_dart/lib/src/realm_flutter.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 export 'realm_class.dart' hide RealmInternal; diff --git a/packages/realm_dart/lib/src/realm_object.dart b/packages/realm_dart/lib/src/realm_object.dart index 41045f202..0ee26c800 100644 --- a/packages/realm_dart/lib/src/realm_object.dart +++ b/packages/realm_dart/lib/src/realm_object.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:ffi'; @@ -667,9 +652,8 @@ class RealmException implements Exception { /// An exception thrown when a Realm is opened with a different schema and a migration is required. /// See [LocalConfiguration.migrationCallback] for more details. class MigrationRequiredException extends RealmException { - MigrationRequiredException(String message) - : super(message, - helpLink: "https://www.mongodb.com/docs/realm/sdk/flutter/realm-database/model-data/update-realm-object-schema/#manually-migrate-schema"); + MigrationRequiredException(super.message) + : super(helpLink: "https://www.mongodb.com/docs/realm/sdk/flutter/realm-database/model-data/update-realm-object-schema/#manually-migrate-schema"); @override String toString() { diff --git a/packages/realm_dart/lib/src/realm_property.dart b/packages/realm_dart/lib/src/realm_property.dart index eaea2e7fb..27279501b 100644 --- a/packages/realm_dart/lib/src/realm_property.dart +++ b/packages/realm_dart/lib/src/realm_property.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'realm_class.dart'; diff --git a/packages/realm_dart/lib/src/results.dart b/packages/realm_dart/lib/src/results.dart index d754de2f3..df92d8ef9 100644 --- a/packages/realm_dart/lib/src/results.dart +++ b/packages/realm_dart/lib/src/results.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; import 'dart:ffi'; diff --git a/packages/realm_dart/lib/src/scheduler.dart b/packages/realm_dart/lib/src/scheduler.dart index 6918598c9..a7d282a45 100644 --- a/packages/realm_dart/lib/src/scheduler.dart +++ b/packages/realm_dart/lib/src/scheduler.dart @@ -1,19 +1,6 @@ -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:ffi'; import 'dart:isolate'; import 'native/realm_core.dart'; diff --git a/packages/realm_dart/lib/src/session.dart b/packages/realm_dart/lib/src/session.dart index 0664c1183..e8da07a88 100644 --- a/packages/realm_dart/lib/src/session.dart +++ b/packages/realm_dart/lib/src/session.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:ffi'; diff --git a/packages/realm_dart/lib/src/set.dart b/packages/realm_dart/lib/src/set.dart index b1e9c0826..bcfe9d3f3 100644 --- a/packages/realm_dart/lib/src/set.dart +++ b/packages/realm_dart/lib/src/set.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:core'; import 'dart:async'; diff --git a/packages/realm_dart/lib/src/subscription.dart b/packages/realm_dart/lib/src/subscription.dart index 2f095c32e..48dd9f0ec 100644 --- a/packages/realm_dart/lib/src/subscription.dart +++ b/packages/realm_dart/lib/src/subscription.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:core'; import 'dart:collection'; diff --git a/packages/realm_dart/lib/src/user.dart b/packages/realm_dart/lib/src/user.dart index c622410b6..05e1c0bca 100644 --- a/packages/realm_dart/lib/src/user.dart +++ b/packages/realm_dart/lib/src/user.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:convert'; diff --git a/packages/realm_dart/pubspec.yaml b/packages/realm_dart/pubspec.yaml index 07f44ac95..9eca10cc0 100644 --- a/packages/realm_dart/pubspec.yaml +++ b/packages/realm_dart/pubspec.yaml @@ -6,8 +6,6 @@ homepage: https://www.realm.io repository: https://github.com/realm/realm-dart issue_tracker: https://github.com/realm/realm-dart/issues -publish_to: none - environment: sdk: ^3.0.0 @@ -16,6 +14,7 @@ dependencies: build_cli_annotations: ^2.0.0 collection: ^1.16.0 crypto: ^3.0.0 + ejson: ^0.1.0 ffi: ^2.0.1 json_annotation: ^4.7.0 logging: ^1.2.0 @@ -24,10 +23,8 @@ dependencies: path: ^1.0.0 pubspec_parse: ^1.0.0 pub_semver: ^2.1.0 - realm_common: - path: ../realm_common - realm_generator: - path: ../realm_generator + realm_common: ^1.8.0 + realm_generator: ^1.8.0 tar: ^1.0.1 build_runner: ^2.1.0 http: ^1.0.0 @@ -37,6 +34,6 @@ dev_dependencies: build_cli: ^2.2.2 json_serializable: ^6.3.1 lints: ^3.0.0 + mason_logger: ^0.2.12 test: ^1.14.3 timezone: ^0.9.0 - diff --git a/packages/realm_dart/scripts/build-ios.sh b/packages/realm_dart/scripts/build-ios.sh index 730ba1b95..22fb3e303 100755 --- a/packages/realm_dart/scripts/build-ios.sh +++ b/packages/realm_dart/scripts/build-ios.sh @@ -21,7 +21,7 @@ function usage { } CONFIGURATION=Release -SUPPORT_PLATFORMS=(catalyst ios simulator) +SUPPORT_PLATFORMS=(ios simulator) # flutter doesn't support maccatalyst function is_supported_platform(){ for platform in "${SUPPORT_PLATFORMS[@]}"; do @@ -42,8 +42,8 @@ shift $((OPTIND-1)) PLATFORMS=($@) if [ -z ${PLATFORMS} ]; then - echo "No platform given. building all platforms..."; - PLATFORMS=(ios catalyst simulator) + echo "No platform given. building for all supported platforms..."; + PLATFORMS=(ios simulator) else echo "Building for..."; for check_platform in "${PLATFORMS[@]}"; do diff --git a/packages/realm_dart/src/realm-core b/packages/realm_dart/src/realm-core index 677c9c28e..2bfd5e9ba 160000 --- a/packages/realm_dart/src/realm-core +++ b/packages/realm_dart/src/realm-core @@ -1 +1 @@ -Subproject commit 677c9c28e29b3a0899dc46b0054f2354cd47a0d1 +Subproject commit 2bfd5e9ba74ed2620657bf968d2931f6ceab6785 diff --git a/packages/realm_dart/test/app_test.dart b/packages/realm_dart/test/app_test.dart index 222d7bf3a..1f29a6039 100644 --- a/packages/realm_dart/test/app_test.dart +++ b/packages/realm_dart/test/app_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:convert'; import 'dart:io'; diff --git a/packages/realm_dart/test/asymmetric_test.dart b/packages/realm_dart/test/asymmetric_test.dart index 21fd85f04..8bd4d5841 100644 --- a/packages/realm_dart/test/asymmetric_test.dart +++ b/packages/realm_dart/test/asymmetric_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:test/expect.dart' hide throws; diff --git a/packages/realm_dart/test/baas_helper.dart b/packages/realm_dart/test/baas_helper.dart index 5c812adde..cf7f31336 100644 --- a/packages/realm_dart/test/baas_helper.dart +++ b/packages/realm_dart/test/baas_helper.dart @@ -1,3 +1,6 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:io'; import 'package:test/test.dart' as testing; diff --git a/packages/realm_dart/test/backlinks_test.dart b/packages/realm_dart/test/backlinks_test.dart index e1c949ecb..ce99e885e 100644 --- a/packages/realm_dart/test/backlinks_test.dart +++ b/packages/realm_dart/test/backlinks_test.dart @@ -1,24 +1,9 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 +import 'package:realm_dart/realm.dart'; import 'package:test/test.dart' hide test, throws; -import 'package:realm_dart/realm.dart'; import 'test.dart'; part 'backlinks_test.realm.dart'; diff --git a/packages/realm_dart/test/backlinks_test.realm.dart b/packages/realm_dart/test/backlinks_test.realm.dart index d8f144ad3..523961454 100644 --- a/packages/realm_dart/test/backlinks_test.realm.dart +++ b/packages/realm_dart/test/backlinks_test.realm.dart @@ -74,10 +74,38 @@ class Source extends _Source with RealmEntity, RealmObjectBase, RealmObject { @override Source freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'et mål': oneTarget.toEJson(), + 'manyTargets': manyTargets.toEJson(), + 'dynamisk mål': dynamicTarget.toEJson(), + 'dynamicManyTargets': dynamicManyTargets.toEJson(), + }; + } + + static EJsonValue _toEJson(Source value) => value.toEJson(); + static Source _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'et mål': EJsonValue oneTarget, + 'manyTargets': EJsonValue manyTargets, + 'dynamisk mål': EJsonValue dynamicTarget, + 'dynamicManyTargets': EJsonValue dynamicManyTargets, + } => + Source( + name: fromEJson(name), + oneTarget: fromEJson(oneTarget), + dynamicTarget: fromEJson(dynamicTarget), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Source._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Source, 'Source', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('oneTarget', RealmPropertyType.object, @@ -89,7 +117,7 @@ class Source extends _Source with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('dynamicManyTargets', RealmPropertyType.object, linkTarget: 'Target', collectionType: RealmCollectionType.list), ]); - } + }(); } class Target extends _Target with RealmEntity, RealmObjectBase, RealmObject { @@ -154,10 +182,35 @@ class Target extends _Target with RealmEntity, RealmObjectBase, RealmObject { @override Target freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'source': source.toEJson(), + 'oneToMany': oneToMany.toEJson(), + 'manyToMany': manyToMany.toEJson(), + }; + } + + static EJsonValue _toEJson(Target value) => value.toEJson(); + static Target _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'source': EJsonValue source, + 'oneToMany': EJsonValue oneToMany, + 'manyToMany': EJsonValue manyToMany, + } => + Target( + name: fromEJson(name), + source: fromEJson(source), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Target._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Target, 'Target', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('source', RealmPropertyType.object, @@ -171,5 +224,5 @@ class Target extends _Target with RealmEntity, RealmObjectBase, RealmObject { collectionType: RealmCollectionType.list, linkTarget: 'Source'), ]); - } + }(); } diff --git a/packages/realm_dart/test/client_reset_test.dart b/packages/realm_dart/test/client_reset_test.dart index 6dba46375..319cb0b25 100644 --- a/packages/realm_dart/test/client_reset_test.dart +++ b/packages/realm_dart/test/client_reset_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/test/configuration_test.dart b/packages/realm_dart/test/configuration_test.dart index 6b4487bf6..141eeaaeb 100644 --- a/packages/realm_dart/test/configuration_test.dart +++ b/packages/realm_dart/test/configuration_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:io'; import 'dart:math'; @@ -212,15 +197,13 @@ void main() { test('Configuration - disableFormatUpgrade=true throws error', () async { var config = Configuration.local([Car.schema], disableFormatUpgrade: true); await copyFile('test/data/realm_files/old-format.realm', config.path); - expect(() { - getRealm(config); - }, throws("Database upgrade required but prohibited.")); + expect(() => getRealm(config), throws("Database upgrade required but prohibited.")); }); test('Configuration - disableFormatUpgrade=false', () async { var config = Configuration.local([Car.schema], disableFormatUpgrade: false); await copyFile('test/data/realm_files/old-format.realm', config.path); - final realm = getRealm(config); + expect(() => getRealm(config), isNot(throwsException)); }); test('Configuration.initialDataCallback invoked', () { @@ -441,7 +424,7 @@ void main() { }); const dummyDataSize = 100; - _addDummyData(Realm realm) { + addDummyData(Realm realm) { for (var i = 0; i < dummyDataSize; i++) { realm.write(() { realm.add(Person(generateRandomString(1000))); @@ -463,7 +446,7 @@ void main() { var config = Configuration.local([Person.schema]); final populateRealm = Realm(config); - _addDummyData(populateRealm); + addDummyData(populateRealm); populateRealm.close(); final oldSize = File(config.path).lengthSync(); diff --git a/packages/realm_dart/test/credentials_test.dart b/packages/realm_dart/test/credentials_test.dart index a2b31e3ec..4a32554fd 100644 --- a/packages/realm_dart/test/credentials_test.dart +++ b/packages/realm_dart/test/credentials_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:test/test.dart' hide test, throws; import 'package:realm_dart/realm.dart'; diff --git a/packages/realm_dart/test/decimal128_test.dart b/packages/realm_dart/test/decimal128_test.dart index 477fdf9db..ef6d76111 100644 --- a/packages/realm_dart/test/decimal128_test.dart +++ b/packages/realm_dart/test/decimal128_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:math'; diff --git a/packages/realm_dart/test/dynamic_realm_test.dart b/packages/realm_dart/test/dynamic_realm_test.dart index 119e7a199..9086fcbd6 100644 --- a/packages/realm_dart/test/dynamic_realm_test.dart +++ b/packages/realm_dart/test/dynamic_realm_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: avoid_relative_lib_imports diff --git a/packages/realm_dart/test/embedded_test.dart b/packages/realm_dart/test/embedded_test.dart index 67ada317d..53074840d 100644 --- a/packages/realm_dart/test/embedded_test.dart +++ b/packages/realm_dart/test/embedded_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:test/test.dart' hide test, throws; diff --git a/packages/realm_dart/test/geospatial_test.dart b/packages/realm_dart/test/geospatial_test.dart index 9e5286490..b1a4b01f9 100644 --- a/packages/realm_dart/test/geospatial_test.dart +++ b/packages/realm_dart/test/geospatial_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:math'; diff --git a/packages/realm_dart/test/geospatial_test.realm.dart b/packages/realm_dart/test/geospatial_test.realm.dart index e2e336e19..d893ca96a 100644 --- a/packages/realm_dart/test/geospatial_test.realm.dart +++ b/packages/realm_dart/test/geospatial_test.realm.dart @@ -44,16 +44,36 @@ class Location extends _Location @override Location freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'type': type.toEJson(), + 'coordinates': coordinates.toEJson(), + }; + } + + static EJsonValue _toEJson(Location value) => value.toEJson(); + static Location _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'type': EJsonValue type, + 'coordinates': EJsonValue coordinates, + } => + Location( + type: fromEJson(type), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Location._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.embeddedObject, Location, 'Location', [ SchemaProperty('type', RealmPropertyType.string), SchemaProperty('coordinates', RealmPropertyType.double, collectionType: RealmCollectionType.list), ]); - } + }(); } class Restaurant extends _Restaurant @@ -87,17 +107,38 @@ class Restaurant extends _Restaurant @override Restaurant freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'location': location.toEJson(), + }; + } + + static EJsonValue _toEJson(Restaurant value) => value.toEJson(); + static Restaurant _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'location': EJsonValue location, + } => + Restaurant( + fromEJson(name), + location: fromEJson(location), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Restaurant._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, Restaurant, 'Restaurant', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('location', RealmPropertyType.object, optional: true, linkTarget: 'Location'), ]); - } + }(); } class LocationList extends _LocationList @@ -125,14 +166,30 @@ class LocationList extends _LocationList @override LocationList freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'locations': locations.toEJson(), + }; + } + + static EJsonValue _toEJson(LocationList value) => value.toEJson(); + static LocationList _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'locations': EJsonValue locations, + } => + LocationList(), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(LocationList._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, LocationList, 'LocationList', [ SchemaProperty('locations', RealmPropertyType.object, linkTarget: 'Location', collectionType: RealmCollectionType.list), ]); - } + }(); } diff --git a/packages/realm_dart/test/indexed_test.dart b/packages/realm_dart/test/indexed_test.dart index edf8d6417..cc1083570 100644 --- a/packages/realm_dart/test/indexed_test.dart +++ b/packages/realm_dart/test/indexed_test.dart @@ -1,26 +1,9 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:math'; import 'dart:typed_data'; -import 'package:collection/collection.dart'; - import 'package:test/test.dart' hide test, throws; import 'test.dart'; diff --git a/packages/realm_dart/test/indexed_test.realm.dart b/packages/realm_dart/test/indexed_test.realm.dart index 79787b278..3de4917fd 100644 --- a/packages/realm_dart/test/indexed_test.realm.dart +++ b/packages/realm_dart/test/indexed_test.realm.dart @@ -67,10 +67,43 @@ class WithIndexes extends _WithIndexes @override WithIndexes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'anInt': anInt.toEJson(), + 'aBool': aBool.toEJson(), + 'string': string.toEJson(), + 'timestamp': timestamp.toEJson(), + 'objectId': objectId.toEJson(), + 'uuid': uuid.toEJson(), + }; + } + + static EJsonValue _toEJson(WithIndexes value) => value.toEJson(); + static WithIndexes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'anInt': EJsonValue anInt, + 'aBool': EJsonValue aBool, + 'string': EJsonValue string, + 'timestamp': EJsonValue timestamp, + 'objectId': EJsonValue objectId, + 'uuid': EJsonValue uuid, + } => + WithIndexes( + fromEJson(anInt), + fromEJson(aBool), + fromEJson(string), + fromEJson(timestamp), + fromEJson(objectId), + fromEJson(uuid), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(WithIndexes._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, WithIndexes, 'WithIndexes', [ SchemaProperty('anInt', RealmPropertyType.int, @@ -86,7 +119,7 @@ class WithIndexes extends _WithIndexes SchemaProperty('uuid', RealmPropertyType.uuid, indexType: RealmIndexType.regular), ]); - } + }(); } class NoIndexes extends _NoIndexes @@ -149,10 +182,43 @@ class NoIndexes extends _NoIndexes @override NoIndexes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'anInt': anInt.toEJson(), + 'aBool': aBool.toEJson(), + 'string': string.toEJson(), + 'timestamp': timestamp.toEJson(), + 'objectId': objectId.toEJson(), + 'uuid': uuid.toEJson(), + }; + } + + static EJsonValue _toEJson(NoIndexes value) => value.toEJson(); + static NoIndexes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'anInt': EJsonValue anInt, + 'aBool': EJsonValue aBool, + 'string': EJsonValue string, + 'timestamp': EJsonValue timestamp, + 'objectId': EJsonValue objectId, + 'uuid': EJsonValue uuid, + } => + NoIndexes( + fromEJson(anInt), + fromEJson(aBool), + fromEJson(string), + fromEJson(timestamp), + fromEJson(objectId), + fromEJson(uuid), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NoIndexes._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, NoIndexes, 'NoIndexes', [ SchemaProperty('anInt', RealmPropertyType.int), SchemaProperty('aBool', RealmPropertyType.bool), @@ -161,7 +227,7 @@ class NoIndexes extends _NoIndexes SchemaProperty('objectId', RealmPropertyType.objectid), SchemaProperty('uuid', RealmPropertyType.uuid), ]); - } + }(); } class ObjectWithFTSIndex extends _ObjectWithFTSIndex @@ -203,10 +269,34 @@ class ObjectWithFTSIndex extends _ObjectWithFTSIndex ObjectWithFTSIndex freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'title': title.toEJson(), + 'summary': summary.toEJson(), + 'nullableSummary': nullableSummary.toEJson(), + }; + } + + static EJsonValue _toEJson(ObjectWithFTSIndex value) => value.toEJson(); + static ObjectWithFTSIndex _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'title': EJsonValue title, + 'summary': EJsonValue summary, + 'nullableSummary': EJsonValue nullableSummary, + } => + ObjectWithFTSIndex( + fromEJson(title), + fromEJson(summary), + nullableSummary: fromEJson(nullableSummary), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(ObjectWithFTSIndex._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, ObjectWithFTSIndex, 'ObjectWithFTSIndex', [ SchemaProperty('title', RealmPropertyType.string), @@ -215,5 +305,5 @@ class ObjectWithFTSIndex extends _ObjectWithFTSIndex SchemaProperty('nullableSummary', RealmPropertyType.string, optional: true, indexType: RealmIndexType.fullText), ]); - } + }(); } diff --git a/packages/realm_dart/test/list_test.dart b/packages/realm_dart/test/list_test.dart index f074dc3b3..e6634e2c2 100644 --- a/packages/realm_dart/test/list_test.dart +++ b/packages/realm_dart/test/list_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: unused_local_variable diff --git a/packages/realm_dart/test/manual_test.dart b/packages/realm_dart/test/manual_test.dart index d528a59d3..5f588d1ab 100644 --- a/packages/realm_dart/test/manual_test.dart +++ b/packages/realm_dart/test/manual_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 @TestOn('browser') // This file only contain manual tests diff --git a/packages/realm_dart/test/migration_test.dart b/packages/realm_dart/test/migration_test.dart index 9c26de0ac..8154ccf2e 100644 --- a/packages/realm_dart/test/migration_test.dart +++ b/packages/realm_dart/test/migration_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: unused_local_variable diff --git a/packages/realm_dart/test/migration_test.realm.dart b/packages/realm_dart/test/migration_test.realm.dart index f38fa5703..5a073d939 100644 --- a/packages/realm_dart/test/migration_test.realm.dart +++ b/packages/realm_dart/test/migration_test.realm.dart @@ -29,14 +29,32 @@ class PersonIntName extends _PersonIntName @override PersonIntName freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(PersonIntName value) => value.toEJson(); + static PersonIntName _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + PersonIntName( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(PersonIntName._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, PersonIntName, 'Person', [ SchemaProperty('name', RealmPropertyType.int), ]); - } + }(); } class StudentV1 extends _StudentV1 @@ -69,15 +87,36 @@ class StudentV1 extends _StudentV1 @override StudentV1 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'yearOfBirth': yearOfBirth.toEJson(), + }; + } + + static EJsonValue _toEJson(StudentV1 value) => value.toEJson(); + static StudentV1 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'yearOfBirth': EJsonValue yearOfBirth, + } => + StudentV1( + fromEJson(name), + yearOfBirth: fromEJson(yearOfBirth), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(StudentV1._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, StudentV1, 'Student', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('yearOfBirth', RealmPropertyType.int, optional: true), ]); - } + }(); } class MyObjectWithTypo extends _MyObjectWithTypo @@ -110,16 +149,37 @@ class MyObjectWithTypo extends _MyObjectWithTypo MyObjectWithTypo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'nmae': nmae.toEJson(), + 'vlaue': vlaue.toEJson(), + }; + } + + static EJsonValue _toEJson(MyObjectWithTypo value) => value.toEJson(); + static MyObjectWithTypo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'nmae': EJsonValue nmae, + 'vlaue': EJsonValue vlaue, + } => + MyObjectWithTypo( + fromEJson(nmae), + fromEJson(vlaue), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(MyObjectWithTypo._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, MyObjectWithTypo, 'MyObject', [ SchemaProperty('nmae', RealmPropertyType.string), SchemaProperty('vlaue', RealmPropertyType.int), ]); - } + }(); } class MyObjectWithoutTypo extends _MyObjectWithoutTypo @@ -152,16 +212,37 @@ class MyObjectWithoutTypo extends _MyObjectWithoutTypo MyObjectWithoutTypo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'value': value.toEJson(), + }; + } + + static EJsonValue _toEJson(MyObjectWithoutTypo value) => value.toEJson(); + static MyObjectWithoutTypo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'value': EJsonValue value, + } => + MyObjectWithoutTypo( + fromEJson(name), + fromEJson(value), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(MyObjectWithoutTypo._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, MyObjectWithoutTypo, 'MyObject', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('value', RealmPropertyType.int), ]); - } + }(); } class MyObjectWithoutValue extends _MyObjectWithoutValue @@ -187,13 +268,31 @@ class MyObjectWithoutValue extends _MyObjectWithoutValue MyObjectWithoutValue freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(MyObjectWithoutValue value) => value.toEJson(); + static MyObjectWithoutValue _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + MyObjectWithoutValue( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(MyObjectWithoutValue._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, MyObjectWithoutValue, 'MyObject', [ SchemaProperty('name', RealmPropertyType.string), ]); - } + }(); } diff --git a/packages/realm_dart/test/realm_logger_test.dart b/packages/realm_dart/test/realm_logger_test.dart index cd83da239..dfa1afc3d 100644 --- a/packages/realm_dart/test/realm_logger_test.dart +++ b/packages/realm_dart/test/realm_logger_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: unused_local_variable, avoid_relative_lib_imports @@ -73,6 +58,7 @@ void main() { final completer = Completer(); Realm.logger.level = level; + await Future.delayed(const Duration(milliseconds: 10)); Realm.logger.onRecord.listen((event) { completer.complete(LoggedMessage(event.level, event.message)); }); diff --git a/packages/realm_dart/test/realm_map_test.dart b/packages/realm_dart/test/realm_map_test.dart index 32aeac8e5..032cc18de 100644 --- a/packages/realm_dart/test/realm_map_test.dart +++ b/packages/realm_dart/test/realm_map_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:io'; diff --git a/packages/realm_dart/test/realm_map_test.realm.dart b/packages/realm_dart/test/realm_map_test.realm.dart index 3acadf1f7..de72a8226 100644 --- a/packages/realm_dart/test/realm_map_test.realm.dart +++ b/packages/realm_dart/test/realm_map_test.realm.dart @@ -35,15 +35,36 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + 'color': color.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + 'color': EJsonValue color, + } => + Car( + fromEJson(make), + color: fromEJson(color), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string, primaryKey: true), SchemaProperty('color', RealmPropertyType.string, optional: true), ]); - } + }(); } class EmbeddedValue extends _EmbeddedValue @@ -68,15 +89,33 @@ class EmbeddedValue extends _EmbeddedValue @override EmbeddedValue freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'intValue': intValue.toEJson(), + }; + } + + static EJsonValue _toEJson(EmbeddedValue value) => value.toEJson(); + static EmbeddedValue _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'intValue': EJsonValue intValue, + } => + EmbeddedValue( + fromEJson(intValue), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(EmbeddedValue._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.embeddedObject, EmbeddedValue, 'EmbeddedValue', [ SchemaProperty('intValue', RealmPropertyType.int), ]); - } + }(); } class TestRealmMaps extends _TestRealmMaps @@ -317,10 +356,70 @@ class TestRealmMaps extends _TestRealmMaps @override TestRealmMaps freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'key': key.toEJson(), + 'boolMap': boolMap.toEJson(), + 'intMap': intMap.toEJson(), + 'stringMap': stringMap.toEJson(), + 'doubleMap': doubleMap.toEJson(), + 'dateTimeMap': dateTimeMap.toEJson(), + 'objectIdMap': objectIdMap.toEJson(), + 'uuidMap': uuidMap.toEJson(), + 'binaryMap': binaryMap.toEJson(), + 'decimalMap': decimalMap.toEJson(), + 'nullableBoolMap': nullableBoolMap.toEJson(), + 'nullableIntMap': nullableIntMap.toEJson(), + 'nullableStringMap': nullableStringMap.toEJson(), + 'nullableDoubleMap': nullableDoubleMap.toEJson(), + 'nullableDateTimeMap': nullableDateTimeMap.toEJson(), + 'nullableObjectIdMap': nullableObjectIdMap.toEJson(), + 'nullableUuidMap': nullableUuidMap.toEJson(), + 'nullableBinaryMap': nullableBinaryMap.toEJson(), + 'nullableDecimalMap': nullableDecimalMap.toEJson(), + 'objectsMap': objectsMap.toEJson(), + 'embeddedMap': embeddedMap.toEJson(), + 'mixedMap': mixedMap.toEJson(), + }; + } + + static EJsonValue _toEJson(TestRealmMaps value) => value.toEJson(); + static TestRealmMaps _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'key': EJsonValue key, + 'boolMap': EJsonValue boolMap, + 'intMap': EJsonValue intMap, + 'stringMap': EJsonValue stringMap, + 'doubleMap': EJsonValue doubleMap, + 'dateTimeMap': EJsonValue dateTimeMap, + 'objectIdMap': EJsonValue objectIdMap, + 'uuidMap': EJsonValue uuidMap, + 'binaryMap': EJsonValue binaryMap, + 'decimalMap': EJsonValue decimalMap, + 'nullableBoolMap': EJsonValue nullableBoolMap, + 'nullableIntMap': EJsonValue nullableIntMap, + 'nullableStringMap': EJsonValue nullableStringMap, + 'nullableDoubleMap': EJsonValue nullableDoubleMap, + 'nullableDateTimeMap': EJsonValue nullableDateTimeMap, + 'nullableObjectIdMap': EJsonValue nullableObjectIdMap, + 'nullableUuidMap': EJsonValue nullableUuidMap, + 'nullableBinaryMap': EJsonValue nullableBinaryMap, + 'nullableDecimalMap': EJsonValue nullableDecimalMap, + 'objectsMap': EJsonValue objectsMap, + 'embeddedMap': EJsonValue embeddedMap, + 'mixedMap': EJsonValue mixedMap, + } => + TestRealmMaps( + fromEJson(key), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(TestRealmMaps._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, TestRealmMaps, 'TestRealmMaps', [ SchemaProperty('key', RealmPropertyType.int, primaryKey: true), @@ -371,5 +470,5 @@ class TestRealmMaps extends _TestRealmMaps SchemaProperty('mixedMap', RealmPropertyType.mixed, optional: true, collectionType: RealmCollectionType.map), ]); - } + }(); } diff --git a/packages/realm_dart/test/realm_object_test.dart b/packages/realm_dart/test/realm_object_test.dart index e384ff361..14e624327 100644 --- a/packages/realm_dart/test/realm_object_test.dart +++ b/packages/realm_dart/test/realm_object_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: unused_local_variable, avoid_relative_lib_imports diff --git a/packages/realm_dart/test/realm_object_test.realm.dart b/packages/realm_dart/test/realm_object_test.realm.dart index a49ff88c5..1a5d90c55 100644 --- a/packages/realm_dart/test/realm_object_test.realm.dart +++ b/packages/realm_dart/test/realm_object_test.realm.dart @@ -30,15 +30,33 @@ class ObjectIdPrimaryKey extends _ObjectIdPrimaryKey ObjectIdPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(ObjectIdPrimaryKey value) => value.toEJson(); + static ObjectIdPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + ObjectIdPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(ObjectIdPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, ObjectIdPrimaryKey, 'ObjectIdPrimaryKey', [ SchemaProperty('id', RealmPropertyType.objectid, primaryKey: true), ]); - } + }(); } class NullableObjectIdPrimaryKey extends _NullableObjectIdPrimaryKey @@ -64,16 +82,35 @@ class NullableObjectIdPrimaryKey extends _NullableObjectIdPrimaryKey NullableObjectIdPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableObjectIdPrimaryKey value) => + value.toEJson(); + static NullableObjectIdPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableObjectIdPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableObjectIdPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, NullableObjectIdPrimaryKey, 'NullableObjectIdPrimaryKey', [ SchemaProperty('id', RealmPropertyType.objectid, optional: true, primaryKey: true), ]); - } + }(); } class IntPrimaryKey extends _IntPrimaryKey @@ -98,15 +135,33 @@ class IntPrimaryKey extends _IntPrimaryKey @override IntPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(IntPrimaryKey value) => value.toEJson(); + static IntPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + IntPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(IntPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, IntPrimaryKey, 'IntPrimaryKey', [ SchemaProperty('id', RealmPropertyType.int, primaryKey: true), ]); - } + }(); } class NullableIntPrimaryKey extends _NullableIntPrimaryKey @@ -132,16 +187,34 @@ class NullableIntPrimaryKey extends _NullableIntPrimaryKey NullableIntPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableIntPrimaryKey value) => value.toEJson(); + static NullableIntPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableIntPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableIntPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, NullableIntPrimaryKey, 'NullableIntPrimaryKey', [ SchemaProperty('id', RealmPropertyType.int, optional: true, primaryKey: true), ]); - } + }(); } class StringPrimaryKey extends _StringPrimaryKey @@ -167,15 +240,33 @@ class StringPrimaryKey extends _StringPrimaryKey StringPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(StringPrimaryKey value) => value.toEJson(); + static StringPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + StringPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(StringPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, StringPrimaryKey, 'StringPrimaryKey', [ SchemaProperty('id', RealmPropertyType.string, primaryKey: true), ]); - } + }(); } class NullableStringPrimaryKey extends _NullableStringPrimaryKey @@ -201,16 +292,34 @@ class NullableStringPrimaryKey extends _NullableStringPrimaryKey NullableStringPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableStringPrimaryKey value) => value.toEJson(); + static NullableStringPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableStringPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableStringPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, NullableStringPrimaryKey, 'NullableStringPrimaryKey', [ SchemaProperty('id', RealmPropertyType.string, optional: true, primaryKey: true), ]); - } + }(); } class UuidPrimaryKey extends _UuidPrimaryKey @@ -235,15 +344,33 @@ class UuidPrimaryKey extends _UuidPrimaryKey @override UuidPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(UuidPrimaryKey value) => value.toEJson(); + static UuidPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + UuidPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(UuidPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, UuidPrimaryKey, 'UuidPrimaryKey', [ SchemaProperty('id', RealmPropertyType.uuid, primaryKey: true), ]); - } + }(); } class NullableUuidPrimaryKey extends _NullableUuidPrimaryKey @@ -269,16 +396,34 @@ class NullableUuidPrimaryKey extends _NullableUuidPrimaryKey NullableUuidPrimaryKey freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableUuidPrimaryKey value) => value.toEJson(); + static NullableUuidPrimaryKey _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableUuidPrimaryKey( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableUuidPrimaryKey._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, NullableUuidPrimaryKey, 'NullableUuidPrimaryKey', [ SchemaProperty('id', RealmPropertyType.uuid, optional: true, primaryKey: true), ]); - } + }(); } class RemappedFromAnotherFile extends _RemappedFromAnotherFile @@ -307,10 +452,28 @@ class RemappedFromAnotherFile extends _RemappedFromAnotherFile RemappedFromAnotherFile freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'property with spaces': linkToAnotherClass.toEJson(), + }; + } + + static EJsonValue _toEJson(RemappedFromAnotherFile value) => value.toEJson(); + static RemappedFromAnotherFile _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'property with spaces': EJsonValue linkToAnotherClass, + } => + RemappedFromAnotherFile( + linkToAnotherClass: fromEJson(linkToAnotherClass), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RemappedFromAnotherFile._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, RemappedFromAnotherFile, 'class with spaces', [ SchemaProperty('linkToAnotherClass', RealmPropertyType.object, @@ -318,7 +481,7 @@ class RemappedFromAnotherFile extends _RemappedFromAnotherFile optional: true, linkTarget: 'myRemappedClass'), ]); - } + }(); } class BoolValue extends _BoolValue @@ -350,13 +513,34 @@ class BoolValue extends _BoolValue @override BoolValue freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'key': key.toEJson(), + 'value': value.toEJson(), + }; + } + + static EJsonValue _toEJson(BoolValue value) => value.toEJson(); + static BoolValue _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'key': EJsonValue key, + 'value': EJsonValue value, + } => + BoolValue( + fromEJson(key), + fromEJson(value), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(BoolValue._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, BoolValue, 'BoolValue', [ SchemaProperty('key', RealmPropertyType.int, primaryKey: true), SchemaProperty('value', RealmPropertyType.bool), ]); - } + }(); } diff --git a/packages/realm_dart/test/realm_set_test.dart b/packages/realm_dart/test/realm_set_test.dart index 43eb5a9d1..ffb420814 100644 --- a/packages/realm_dart/test/realm_set_test.dart +++ b/packages/realm_dart/test/realm_set_test.dart @@ -1,26 +1,11 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2023 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2023 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:typed_data'; import 'package:collection/collection.dart'; -import 'package:test/test.dart' hide test, throws; import 'package:realm_dart/realm.dart'; +import 'package:test/test.dart' hide test, throws; import 'test.dart'; diff --git a/packages/realm_dart/test/realm_set_test.realm.dart b/packages/realm_dart/test/realm_set_test.realm.dart index ba17d309c..09bb778e6 100644 --- a/packages/realm_dart/test/realm_set_test.realm.dart +++ b/packages/realm_dart/test/realm_set_test.realm.dart @@ -35,15 +35,36 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + 'color': color.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + 'color': EJsonValue color, + } => + Car( + fromEJson(make), + color: fromEJson(color), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string, primaryKey: true), SchemaProperty('color', RealmPropertyType.string, optional: true), ]); - } + }(); } class TestRealmSets extends _TestRealmSets @@ -251,10 +272,64 @@ class TestRealmSets extends _TestRealmSets @override TestRealmSets freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'key': key.toEJson(), + 'boolSet': boolSet.toEJson(), + 'intSet': intSet.toEJson(), + 'stringSet': stringSet.toEJson(), + 'doubleSet': doubleSet.toEJson(), + 'dateTimeSet': dateTimeSet.toEJson(), + 'objectIdSet': objectIdSet.toEJson(), + 'uuidSet': uuidSet.toEJson(), + 'mixedSet': mixedSet.toEJson(), + 'objectsSet': objectsSet.toEJson(), + 'binarySet': binarySet.toEJson(), + 'nullableBoolSet': nullableBoolSet.toEJson(), + 'nullableIntSet': nullableIntSet.toEJson(), + 'nullableStringSet': nullableStringSet.toEJson(), + 'nullableDoubleSet': nullableDoubleSet.toEJson(), + 'nullableDateTimeSet': nullableDateTimeSet.toEJson(), + 'nullableObjectIdSet': nullableObjectIdSet.toEJson(), + 'nullableUuidSet': nullableUuidSet.toEJson(), + 'nullableBinarySet': nullableBinarySet.toEJson(), + }; + } + + static EJsonValue _toEJson(TestRealmSets value) => value.toEJson(); + static TestRealmSets _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'key': EJsonValue key, + 'boolSet': EJsonValue boolSet, + 'intSet': EJsonValue intSet, + 'stringSet': EJsonValue stringSet, + 'doubleSet': EJsonValue doubleSet, + 'dateTimeSet': EJsonValue dateTimeSet, + 'objectIdSet': EJsonValue objectIdSet, + 'uuidSet': EJsonValue uuidSet, + 'mixedSet': EJsonValue mixedSet, + 'objectsSet': EJsonValue objectsSet, + 'binarySet': EJsonValue binarySet, + 'nullableBoolSet': EJsonValue nullableBoolSet, + 'nullableIntSet': EJsonValue nullableIntSet, + 'nullableStringSet': EJsonValue nullableStringSet, + 'nullableDoubleSet': EJsonValue nullableDoubleSet, + 'nullableDateTimeSet': EJsonValue nullableDateTimeSet, + 'nullableObjectIdSet': EJsonValue nullableObjectIdSet, + 'nullableUuidSet': EJsonValue nullableUuidSet, + 'nullableBinarySet': EJsonValue nullableBinarySet, + } => + TestRealmSets( + fromEJson(key), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(TestRealmSets._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, TestRealmSets, 'TestRealmSets', [ SchemaProperty('key', RealmPropertyType.int, primaryKey: true), @@ -295,5 +370,5 @@ class TestRealmSets extends _TestRealmSets SchemaProperty('nullableBinarySet', RealmPropertyType.binary, optional: true, collectionType: RealmCollectionType.set), ]); - } + }(); } diff --git a/packages/realm_dart/test/realm_test.dart b/packages/realm_dart/test/realm_test.dart index 136de401a..188b59696 100644 --- a/packages/realm_dart/test/realm_test.dart +++ b/packages/realm_dart/test/realm_test.dart @@ -1,34 +1,19 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// - -// ignore_for_file: unused_local_variable, avoid_relative_lib_imports +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:isolate'; -import 'package:test/test.dart' hide test, throws; -import 'package:timezone/timezone.dart' as tz; -import 'package:timezone/data/latest.dart' as tz; + import 'package:path/path.dart' as p; import 'package:realm_dart/realm.dart'; -import 'test.dart'; import 'package:realm_dart/src/native/realm_core.dart'; +import 'package:test/test.dart' hide test, throws; +import 'package:timezone/data/latest.dart' as tz; +import 'package:timezone/timezone.dart' as tz; + +import 'test.dart'; void main() { setupTests(); diff --git a/packages/realm_dart/test/realm_value_test.dart b/packages/realm_dart/test/realm_value_test.dart index c7a24f9e7..bb5a7ec3d 100644 --- a/packages/realm_dart/test/realm_value_test.dart +++ b/packages/realm_dart/test/realm_value_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:typed_data'; @@ -329,7 +314,7 @@ void main() { case RealmCollectionType.map: expect(expected, isMap); final actualMap = actual.asMap(); - final expectedMap = expected as Map; + final expectedMap = expected as Map; expect(actualMap, hasLength(expectedMap.length)); for (String key in expectedMap.keys) { expect(actualMap.containsKey(key), true, reason: "Didn't find $key in the actual map"); diff --git a/packages/realm_dart/test/realm_value_test.realm.dart b/packages/realm_dart/test/realm_value_test.realm.dart index 53c9c96de..0a011da86 100644 --- a/packages/realm_dart/test/realm_value_test.realm.dart +++ b/packages/realm_dart/test/realm_value_test.realm.dart @@ -36,14 +36,32 @@ class TuckedIn extends _TuckedIn @override TuckedIn freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'x': x.toEJson(), + }; + } + + static EJsonValue _toEJson(TuckedIn value) => value.toEJson(); + static TuckedIn _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'x': EJsonValue x, + } => + TuckedIn( + x: fromEJson(x), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(TuckedIn._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.embeddedObject, TuckedIn, 'TuckedIn', [ SchemaProperty('x', RealmPropertyType.int), ]); - } + }(); } class AnythingGoes extends _AnythingGoes @@ -100,10 +118,34 @@ class AnythingGoes extends _AnythingGoes @override AnythingGoes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'oneAny': oneAny.toEJson(), + 'manyAny': manyAny.toEJson(), + 'dictOfAny': dictOfAny.toEJson(), + 'setOfAny': setOfAny.toEJson(), + }; + } + + static EJsonValue _toEJson(AnythingGoes value) => value.toEJson(); + static AnythingGoes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'oneAny': EJsonValue oneAny, + 'manyAny': EJsonValue manyAny, + 'dictOfAny': EJsonValue dictOfAny, + 'setOfAny': EJsonValue setOfAny, + } => + AnythingGoes( + oneAny: fromEJson(oneAny), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(AnythingGoes._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, AnythingGoes, 'AnythingGoes', [ SchemaProperty('oneAny', RealmPropertyType.mixed, @@ -115,7 +157,7 @@ class AnythingGoes extends _AnythingGoes SchemaProperty('setOfAny', RealmPropertyType.mixed, optional: true, collectionType: RealmCollectionType.set), ]); - } + }(); } class Stuff extends _Stuff with RealmEntity, RealmObjectBase, RealmObject { @@ -146,12 +188,30 @@ class Stuff extends _Stuff with RealmEntity, RealmObjectBase, RealmObject { @override Stuff freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'i': i.toEJson(), + }; + } + + static EJsonValue _toEJson(Stuff value) => value.toEJson(); + static Stuff _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'i': EJsonValue i, + } => + Stuff( + i: fromEJson(i), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Stuff._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Stuff, 'Stuff', [ SchemaProperty('i', RealmPropertyType.int), ]); - } + }(); } diff --git a/packages/realm_dart/test/results_test.dart b/packages/realm_dart/test/results_test.dart index 8c0cd0873..ab69c67c5 100644 --- a/packages/realm_dart/test/results_test.dart +++ b/packages/realm_dart/test/results_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 // ignore_for_file: unused_local_variable diff --git a/packages/realm_dart/test/session_test.dart b/packages/realm_dart/test/session_test.dart index 20b8d7f2c..3a585490d 100644 --- a/packages/realm_dart/test/session_test.dart +++ b/packages/realm_dart/test/session_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'package:test/test.dart' hide test, throws; diff --git a/packages/realm_dart/test/subscription_test.dart b/packages/realm_dart/test/subscription_test.dart index 7262bdb80..9cd90d311 100644 --- a/packages/realm_dart/test/subscription_test.dart +++ b/packages/realm_dart/test/subscription_test.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; import 'dart:io'; import 'dart:math'; diff --git a/packages/realm_dart/test/test.dart b/packages/realm_dart/test/test.dart index 134ea76fe..3c3e71641 100644 --- a/packages/realm_dart/test/test.dart +++ b/packages/realm_dart/test/test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:collection'; diff --git a/packages/realm_dart/test/test.realm.dart b/packages/realm_dart/test/test.realm.dart index cb62a1106..1a9c2cfa6 100644 --- a/packages/realm_dart/test/test.realm.dart +++ b/packages/realm_dart/test/test.realm.dart @@ -28,14 +28,32 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + } => + Car( + fromEJson(make), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string, primaryKey: true), ]); - } + }(); } class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @@ -59,14 +77,32 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + Person( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string), ]); - } + }(); } class Dog extends _Dog with RealmEntity, RealmObjectBase, RealmObject { @@ -105,17 +141,41 @@ class Dog extends _Dog with RealmEntity, RealmObjectBase, RealmObject { @override Dog freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'age': age.toEJson(), + 'owner': owner.toEJson(), + }; + } + + static EJsonValue _toEJson(Dog value) => value.toEJson(); + static Dog _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'age': EJsonValue age, + 'owner': EJsonValue owner, + } => + Dog( + fromEJson(name), + age: fromEJson(age), + owner: fromEJson(owner), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Dog._); + register(_toEJson, _fromEJson); 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'), ]); - } + }(); } class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { @@ -158,10 +218,32 @@ class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { @override Team freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'players': players.toEJson(), + 'scores': scores.toEJson(), + }; + } + + static EJsonValue _toEJson(Team value) => value.toEJson(); + static Team _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'players': EJsonValue players, + 'scores': EJsonValue scores, + } => + Team( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Team._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Team, 'Team', [ SchemaProperty('name', RealmPropertyType.string), SchemaProperty('players', RealmPropertyType.object, @@ -169,7 +251,7 @@ class Team extends _Team with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('scores', RealmPropertyType.int, collectionType: RealmCollectionType.list), ]); - } + }(); } class Student extends _Student with RealmEntity, RealmObjectBase, RealmObject { @@ -216,10 +298,37 @@ class Student extends _Student with RealmEntity, RealmObjectBase, RealmObject { @override Student freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'number': number.toEJson(), + 'name': name.toEJson(), + 'yearOfBirth': yearOfBirth.toEJson(), + 'school': school.toEJson(), + }; + } + + static EJsonValue _toEJson(Student value) => value.toEJson(); + static Student _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'number': EJsonValue number, + 'name': EJsonValue name, + 'yearOfBirth': EJsonValue yearOfBirth, + 'school': EJsonValue school, + } => + Student( + fromEJson(number), + name: fromEJson(name), + yearOfBirth: fromEJson(yearOfBirth), + school: fromEJson(school), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Student._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Student, 'Student', [ SchemaProperty('number', RealmPropertyType.int, primaryKey: true), SchemaProperty('name', RealmPropertyType.string, optional: true), @@ -227,7 +336,7 @@ class Student extends _Student with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('school', RealmPropertyType.object, optional: true, linkTarget: 'School'), ]); - } + }(); } class School extends _School with RealmEntity, RealmObjectBase, RealmObject { @@ -287,10 +396,38 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { @override School freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'city': city.toEJson(), + 'students': students.toEJson(), + 'branchOfSchool': branchOfSchool.toEJson(), + 'branches': branches.toEJson(), + }; + } + + static EJsonValue _toEJson(School value) => value.toEJson(); + static School _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'city': EJsonValue city, + 'students': EJsonValue students, + 'branchOfSchool': EJsonValue branchOfSchool, + 'branches': EJsonValue branches, + } => + School( + fromEJson(name), + city: fromEJson(city), + branchOfSchool: fromEJson(branchOfSchool), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(School._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, School, 'School', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('city', RealmPropertyType.string, optional: true), @@ -301,7 +438,7 @@ class School extends _School with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('branches', RealmPropertyType.object, linkTarget: 'School', collectionType: RealmCollectionType.list), ]); - } + }(); } class RemappedClass extends $RemappedClass @@ -339,10 +476,30 @@ class RemappedClass extends $RemappedClass @override RemappedClass freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'primitive_property': remappedProperty.toEJson(), + 'list-with-dashes': listProperty.toEJson(), + }; + } + + static EJsonValue _toEJson(RemappedClass value) => value.toEJson(); + static RemappedClass _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'primitive_property': EJsonValue remappedProperty, + 'list-with-dashes': EJsonValue listProperty, + } => + RemappedClass( + fromEJson(remappedProperty), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RemappedClass._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, RemappedClass, 'myRemappedClass', [ SchemaProperty('remappedProperty', RealmPropertyType.string, @@ -352,7 +509,7 @@ class RemappedClass extends $RemappedClass linkTarget: 'myRemappedClass', collectionType: RealmCollectionType.list), ]); - } + }(); } class Task extends _Task with RealmEntity, RealmObjectBase, RealmObject { @@ -376,15 +533,33 @@ class Task extends _Task with RealmEntity, RealmObjectBase, RealmObject { @override Task freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(Task value) => value.toEJson(); + static Task _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + } => + Task( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Task._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Task, 'Task', [ SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), ]); - } + }(); } class Product extends _Product with RealmEntity, RealmObjectBase, RealmObject { @@ -417,17 +592,38 @@ class Product extends _Product with RealmEntity, RealmObjectBase, RealmObject { @override Product freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'stringQueryField': name.toEJson(), + }; + } + + static EJsonValue _toEJson(Product value) => value.toEJson(); + static Product _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'stringQueryField': EJsonValue name, + } => + Product( + fromEJson(id), + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { 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'), ]); - } + }(); } class Schedule extends _Schedule @@ -461,17 +657,37 @@ class Schedule extends _Schedule @override Schedule freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'tasks': tasks.toEJson(), + }; + } + + static EJsonValue _toEJson(Schedule value) => value.toEJson(); + static Schedule _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'tasks': EJsonValue tasks, + } => + Schedule( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { 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), ]); - } + }(); } class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { @@ -517,17 +733,41 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { @override Foo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'requiredBinaryProp': requiredBinaryProp.toEJson(), + 'defaultValueBinaryProp': defaultValueBinaryProp.toEJson(), + 'nullableBinaryProp': nullableBinaryProp.toEJson(), + }; + } + + static EJsonValue _toEJson(Foo value) => value.toEJson(); + static Foo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'requiredBinaryProp': EJsonValue requiredBinaryProp, + 'defaultValueBinaryProp': EJsonValue defaultValueBinaryProp, + 'nullableBinaryProp': EJsonValue nullableBinaryProp, + } => + Foo( + fromEJson(requiredBinaryProp), + defaultValueBinaryProp: fromEJson(defaultValueBinaryProp), + nullableBinaryProp: fromEJson(nullableBinaryProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Foo._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Foo, 'Foo', [ SchemaProperty('requiredBinaryProp', RealmPropertyType.binary), SchemaProperty('defaultValueBinaryProp', RealmPropertyType.binary), SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, optional: true), ]); - } + }(); } class AllTypes extends _AllTypes @@ -701,10 +941,79 @@ class AllTypes extends _AllTypes @override AllTypes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'stringProp': stringProp.toEJson(), + 'boolProp': boolProp.toEJson(), + 'dateProp': dateProp.toEJson(), + 'doubleProp': doubleProp.toEJson(), + 'objectIdProp': objectIdProp.toEJson(), + 'uuidProp': uuidProp.toEJson(), + 'intProp': intProp.toEJson(), + 'decimalProp': decimalProp.toEJson(), + 'binaryProp': binaryProp.toEJson(), + 'nullableStringProp': nullableStringProp.toEJson(), + 'nullableBoolProp': nullableBoolProp.toEJson(), + 'nullableDateProp': nullableDateProp.toEJson(), + 'nullableDoubleProp': nullableDoubleProp.toEJson(), + 'nullableObjectIdProp': nullableObjectIdProp.toEJson(), + 'nullableUuidProp': nullableUuidProp.toEJson(), + 'nullableIntProp': nullableIntProp.toEJson(), + 'nullableDecimalProp': nullableDecimalProp.toEJson(), + 'nullableBinaryProp': nullableBinaryProp.toEJson(), + }; + } + + static EJsonValue _toEJson(AllTypes value) => value.toEJson(); + static AllTypes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'stringProp': EJsonValue stringProp, + 'boolProp': EJsonValue boolProp, + 'dateProp': EJsonValue dateProp, + 'doubleProp': EJsonValue doubleProp, + 'objectIdProp': EJsonValue objectIdProp, + 'uuidProp': EJsonValue uuidProp, + 'intProp': EJsonValue intProp, + 'decimalProp': EJsonValue decimalProp, + 'binaryProp': EJsonValue binaryProp, + 'nullableStringProp': EJsonValue nullableStringProp, + 'nullableBoolProp': EJsonValue nullableBoolProp, + 'nullableDateProp': EJsonValue nullableDateProp, + 'nullableDoubleProp': EJsonValue nullableDoubleProp, + 'nullableObjectIdProp': EJsonValue nullableObjectIdProp, + 'nullableUuidProp': EJsonValue nullableUuidProp, + 'nullableIntProp': EJsonValue nullableIntProp, + 'nullableDecimalProp': EJsonValue nullableDecimalProp, + 'nullableBinaryProp': EJsonValue nullableBinaryProp, + } => + AllTypes( + fromEJson(stringProp), + fromEJson(boolProp), + fromEJson(dateProp), + fromEJson(doubleProp), + fromEJson(objectIdProp), + fromEJson(uuidProp), + fromEJson(intProp), + fromEJson(decimalProp), + binaryProp: fromEJson(binaryProp), + nullableStringProp: fromEJson(nullableStringProp), + nullableBoolProp: fromEJson(nullableBoolProp), + nullableDateProp: fromEJson(nullableDateProp), + nullableDoubleProp: fromEJson(nullableDoubleProp), + nullableObjectIdProp: fromEJson(nullableObjectIdProp), + nullableUuidProp: fromEJson(nullableUuidProp), + nullableIntProp: fromEJson(nullableIntProp), + nullableDecimalProp: fromEJson(nullableDecimalProp), + nullableBinaryProp: fromEJson(nullableBinaryProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(AllTypes._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, AllTypes, 'AllTypes', [ SchemaProperty('stringProp', RealmPropertyType.string), SchemaProperty('boolProp', RealmPropertyType.bool), @@ -733,7 +1042,7 @@ class AllTypes extends _AllTypes SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, optional: true), ]); - } + }(); } class LinksClass extends _LinksClass @@ -797,10 +1106,37 @@ class LinksClass extends _LinksClass @override LinksClass freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + 'link': link.toEJson(), + 'list': list.toEJson(), + 'linksSet': linksSet.toEJson(), + 'map': map.toEJson(), + }; + } + + static EJsonValue _toEJson(LinksClass value) => value.toEJson(); + static LinksClass _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + 'link': EJsonValue link, + 'list': EJsonValue list, + 'linksSet': EJsonValue linksSet, + 'map': EJsonValue map, + } => + LinksClass( + fromEJson(id), + link: fromEJson(link), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(LinksClass._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, LinksClass, 'LinksClass', [ SchemaProperty('id', RealmPropertyType.uuid, primaryKey: true), @@ -815,7 +1151,7 @@ class LinksClass extends _LinksClass linkTarget: 'LinksClass', collectionType: RealmCollectionType.map), ]); - } + }(); } class AllCollections extends _AllCollections @@ -1328,10 +1664,120 @@ class AllCollections extends _AllCollections @override AllCollections freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'stringList': stringList.toEJson(), + 'boolList': boolList.toEJson(), + 'dateList': dateList.toEJson(), + 'doubleList': doubleList.toEJson(), + 'objectIdList': objectIdList.toEJson(), + 'uuidList': uuidList.toEJson(), + 'intList': intList.toEJson(), + 'decimalList': decimalList.toEJson(), + 'nullableStringList': nullableStringList.toEJson(), + 'nullableBoolList': nullableBoolList.toEJson(), + 'nullableDateList': nullableDateList.toEJson(), + 'nullableDoubleList': nullableDoubleList.toEJson(), + 'nullableObjectIdList': nullableObjectIdList.toEJson(), + 'nullableUuidList': nullableUuidList.toEJson(), + 'nullableIntList': nullableIntList.toEJson(), + 'nullableDecimalList': nullableDecimalList.toEJson(), + 'stringSet': stringSet.toEJson(), + 'boolSet': boolSet.toEJson(), + 'dateSet': dateSet.toEJson(), + 'doubleSet': doubleSet.toEJson(), + 'objectIdSet': objectIdSet.toEJson(), + 'uuidSet': uuidSet.toEJson(), + 'intSet': intSet.toEJson(), + 'decimalSet': decimalSet.toEJson(), + 'nullableStringSet': nullableStringSet.toEJson(), + 'nullableBoolSet': nullableBoolSet.toEJson(), + 'nullableDateSet': nullableDateSet.toEJson(), + 'nullableDoubleSet': nullableDoubleSet.toEJson(), + 'nullableObjectIdSet': nullableObjectIdSet.toEJson(), + 'nullableUuidSet': nullableUuidSet.toEJson(), + 'nullableIntSet': nullableIntSet.toEJson(), + 'nullableDecimalSet': nullableDecimalSet.toEJson(), + 'stringMap': stringMap.toEJson(), + 'boolMap': boolMap.toEJson(), + 'dateMap': dateMap.toEJson(), + 'doubleMap': doubleMap.toEJson(), + 'objectIdMap': objectIdMap.toEJson(), + 'uuidMap': uuidMap.toEJson(), + 'intMap': intMap.toEJson(), + 'decimalMap': decimalMap.toEJson(), + 'nullableStringMap': nullableStringMap.toEJson(), + 'nullableBoolMap': nullableBoolMap.toEJson(), + 'nullableDateMap': nullableDateMap.toEJson(), + 'nullableDoubleMap': nullableDoubleMap.toEJson(), + 'nullableObjectIdMap': nullableObjectIdMap.toEJson(), + 'nullableUuidMap': nullableUuidMap.toEJson(), + 'nullableIntMap': nullableIntMap.toEJson(), + 'nullableDecimalMap': nullableDecimalMap.toEJson(), + }; + } + + static EJsonValue _toEJson(AllCollections value) => value.toEJson(); + static AllCollections _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'stringList': EJsonValue stringList, + 'boolList': EJsonValue boolList, + 'dateList': EJsonValue dateList, + 'doubleList': EJsonValue doubleList, + 'objectIdList': EJsonValue objectIdList, + 'uuidList': EJsonValue uuidList, + 'intList': EJsonValue intList, + 'decimalList': EJsonValue decimalList, + 'nullableStringList': EJsonValue nullableStringList, + 'nullableBoolList': EJsonValue nullableBoolList, + 'nullableDateList': EJsonValue nullableDateList, + 'nullableDoubleList': EJsonValue nullableDoubleList, + 'nullableObjectIdList': EJsonValue nullableObjectIdList, + 'nullableUuidList': EJsonValue nullableUuidList, + 'nullableIntList': EJsonValue nullableIntList, + 'nullableDecimalList': EJsonValue nullableDecimalList, + 'stringSet': EJsonValue stringSet, + 'boolSet': EJsonValue boolSet, + 'dateSet': EJsonValue dateSet, + 'doubleSet': EJsonValue doubleSet, + 'objectIdSet': EJsonValue objectIdSet, + 'uuidSet': EJsonValue uuidSet, + 'intSet': EJsonValue intSet, + 'decimalSet': EJsonValue decimalSet, + 'nullableStringSet': EJsonValue nullableStringSet, + 'nullableBoolSet': EJsonValue nullableBoolSet, + 'nullableDateSet': EJsonValue nullableDateSet, + 'nullableDoubleSet': EJsonValue nullableDoubleSet, + 'nullableObjectIdSet': EJsonValue nullableObjectIdSet, + 'nullableUuidSet': EJsonValue nullableUuidSet, + 'nullableIntSet': EJsonValue nullableIntSet, + 'nullableDecimalSet': EJsonValue nullableDecimalSet, + 'stringMap': EJsonValue stringMap, + 'boolMap': EJsonValue boolMap, + 'dateMap': EJsonValue dateMap, + 'doubleMap': EJsonValue doubleMap, + 'objectIdMap': EJsonValue objectIdMap, + 'uuidMap': EJsonValue uuidMap, + 'intMap': EJsonValue intMap, + 'decimalMap': EJsonValue decimalMap, + 'nullableStringMap': EJsonValue nullableStringMap, + 'nullableBoolMap': EJsonValue nullableBoolMap, + 'nullableDateMap': EJsonValue nullableDateMap, + 'nullableDoubleMap': EJsonValue nullableDoubleMap, + 'nullableObjectIdMap': EJsonValue nullableObjectIdMap, + 'nullableUuidMap': EJsonValue nullableUuidMap, + 'nullableIntMap': EJsonValue nullableIntMap, + 'nullableDecimalMap': EJsonValue nullableDecimalMap, + } => + AllCollections(), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(AllCollections._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, AllCollections, 'AllCollections', [ SchemaProperty('stringList', RealmPropertyType.string, @@ -1431,7 +1877,7 @@ class AllCollections extends _AllCollections SchemaProperty('nullableDecimalMap', RealmPropertyType.decimal128, optional: true, collectionType: RealmCollectionType.map), ]); - } + }(); } class NullableTypes extends _NullableTypes @@ -1530,10 +1976,55 @@ class NullableTypes extends _NullableTypes @override NullableTypes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'differentiator': differentiator.toEJson(), + 'stringProp': stringProp.toEJson(), + 'boolProp': boolProp.toEJson(), + 'dateProp': dateProp.toEJson(), + 'doubleProp': doubleProp.toEJson(), + 'objectIdProp': objectIdProp.toEJson(), + 'uuidProp': uuidProp.toEJson(), + 'intProp': intProp.toEJson(), + 'decimalProp': decimalProp.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableTypes value) => value.toEJson(); + static NullableTypes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'differentiator': EJsonValue differentiator, + 'stringProp': EJsonValue stringProp, + 'boolProp': EJsonValue boolProp, + 'dateProp': EJsonValue dateProp, + 'doubleProp': EJsonValue doubleProp, + 'objectIdProp': EJsonValue objectIdProp, + 'uuidProp': EJsonValue uuidProp, + 'intProp': EJsonValue intProp, + 'decimalProp': EJsonValue decimalProp, + } => + NullableTypes( + fromEJson(id), + fromEJson(differentiator), + stringProp: fromEJson(stringProp), + boolProp: fromEJson(boolProp), + dateProp: fromEJson(dateProp), + doubleProp: fromEJson(doubleProp), + objectIdProp: fromEJson(objectIdProp), + uuidProp: fromEJson(uuidProp), + intProp: fromEJson(intProp), + decimalProp: fromEJson(decimalProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableTypes._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, NullableTypes, 'NullableTypes', [ SchemaProperty('id', RealmPropertyType.objectid, @@ -1550,7 +2041,7 @@ class NullableTypes extends _NullableTypes SchemaProperty('decimalProp', RealmPropertyType.decimal128, optional: true), ]); - } + }(); } class Event extends _Event with RealmEntity, RealmObjectBase, RealmObject { @@ -1610,10 +2101,40 @@ class Event extends _Event with RealmEntity, RealmObjectBase, RealmObject { @override Event freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'stringQueryField': name.toEJson(), + 'boolQueryField': isCompleted.toEJson(), + 'intQueryField': durationInMinutes.toEJson(), + 'assignedTo': assignedTo.toEJson(), + }; + } + + static EJsonValue _toEJson(Event value) => value.toEJson(); + static Event _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'stringQueryField': EJsonValue name, + 'boolQueryField': EJsonValue isCompleted, + 'intQueryField': EJsonValue durationInMinutes, + 'assignedTo': EJsonValue assignedTo, + } => + Event( + fromEJson(id), + name: fromEJson(name), + isCompleted: fromEJson(isCompleted), + durationInMinutes: fromEJson(durationInMinutes), + assignedTo: fromEJson(assignedTo), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Event._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Event, 'Event', [ SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), @@ -1625,7 +2146,7 @@ class Event extends _Event with RealmEntity, RealmObjectBase, RealmObject { mapTo: 'intQueryField', optional: true), SchemaProperty('assignedTo', RealmPropertyType.string, optional: true), ]); - } + }(); } class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { @@ -1674,10 +2195,36 @@ class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { @override Party freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'host': host.toEJson(), + 'year': year.toEJson(), + 'guests': guests.toEJson(), + 'previous': previous.toEJson(), + }; + } + + static EJsonValue _toEJson(Party value) => value.toEJson(); + static Party _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'host': EJsonValue host, + 'year': EJsonValue year, + 'guests': EJsonValue guests, + 'previous': EJsonValue previous, + } => + Party( + fromEJson(year), + host: fromEJson(host), + previous: fromEJson(previous), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Party._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Party, 'Party', [ SchemaProperty('host', RealmPropertyType.object, optional: true, linkTarget: 'Friend'), @@ -1687,7 +2234,7 @@ class Party extends _Party with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('previous', RealmPropertyType.object, optional: true, linkTarget: 'Party'), ]); - } + }(); } class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { @@ -1744,10 +2291,36 @@ class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { @override Friend freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'age': age.toEJson(), + 'bestFriend': bestFriend.toEJson(), + 'friends': friends.toEJson(), + }; + } + + static EJsonValue _toEJson(Friend value) => value.toEJson(); + static Friend _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'age': EJsonValue age, + 'bestFriend': EJsonValue bestFriend, + 'friends': EJsonValue friends, + } => + Friend( + fromEJson(name), + age: fromEJson(age), + bestFriend: fromEJson(bestFriend), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Friend._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Friend, 'Friend', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('age', RealmPropertyType.int), @@ -1756,7 +2329,7 @@ class Friend extends _Friend with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('friends', RealmPropertyType.object, linkTarget: 'Friend', collectionType: RealmCollectionType.list), ]); - } + }(); } class When extends _When with RealmEntity, RealmObjectBase, RealmObject { @@ -1791,15 +2364,36 @@ class When extends _When with RealmEntity, RealmObjectBase, RealmObject { @override When freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'dateTimeUtc': dateTimeUtc.toEJson(), + 'locationName': locationName.toEJson(), + }; + } + + static EJsonValue _toEJson(When value) => value.toEJson(); + static When _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'dateTimeUtc': EJsonValue dateTimeUtc, + 'locationName': EJsonValue locationName, + } => + When( + fromEJson(dateTimeUtc), + fromEJson(locationName), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(When._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, When, 'When', [ SchemaProperty('dateTimeUtc', RealmPropertyType.timestamp), SchemaProperty('locationName', RealmPropertyType.string), ]); - } + }(); } class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { @@ -1840,10 +2434,33 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { @override Player freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'game': game.toEJson(), + 'scoresByRound': scoresByRound.toEJson(), + }; + } + + static EJsonValue _toEJson(Player value) => value.toEJson(); + static Player _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'game': EJsonValue game, + 'scoresByRound': EJsonValue scoresByRound, + } => + Player( + fromEJson(name), + game: fromEJson(game), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Player._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Player, 'Player', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), SchemaProperty('game', RealmPropertyType.object, @@ -1851,7 +2468,7 @@ class Player extends _Player with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('scoresByRound', RealmPropertyType.int, optional: true, collectionType: RealmCollectionType.list), ]); - } + }(); } class Game extends _Game with RealmEntity, RealmObjectBase, RealmObject { @@ -1878,15 +2495,31 @@ class Game extends _Game with RealmEntity, RealmObjectBase, RealmObject { @override Game freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'winnerByRound': winnerByRound.toEJson(), + }; + } + + static EJsonValue _toEJson(Game value) => value.toEJson(); + static Game _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'winnerByRound': EJsonValue winnerByRound, + } => + Game(), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Game._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Game, 'Game', [ SchemaProperty('winnerByRound', RealmPropertyType.object, linkTarget: 'Player', collectionType: RealmCollectionType.list), ]); - } + }(); } class AllTypesEmbedded extends _AllTypesEmbedded @@ -2120,10 +2753,89 @@ class AllTypesEmbedded extends _AllTypesEmbedded AllTypesEmbedded freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'stringProp': stringProp.toEJson(), + 'boolProp': boolProp.toEJson(), + 'dateProp': dateProp.toEJson(), + 'doubleProp': doubleProp.toEJson(), + 'objectIdProp': objectIdProp.toEJson(), + 'uuidProp': uuidProp.toEJson(), + 'intProp': intProp.toEJson(), + 'decimalProp': decimalProp.toEJson(), + 'nullableStringProp': nullableStringProp.toEJson(), + 'nullableBoolProp': nullableBoolProp.toEJson(), + 'nullableDateProp': nullableDateProp.toEJson(), + 'nullableDoubleProp': nullableDoubleProp.toEJson(), + 'nullableObjectIdProp': nullableObjectIdProp.toEJson(), + 'nullableUuidProp': nullableUuidProp.toEJson(), + 'nullableIntProp': nullableIntProp.toEJson(), + 'nullableDecimalProp': nullableDecimalProp.toEJson(), + 'strings': strings.toEJson(), + 'bools': bools.toEJson(), + 'dates': dates.toEJson(), + 'doubles': doubles.toEJson(), + 'objectIds': objectIds.toEJson(), + 'uuids': uuids.toEJson(), + 'ints': ints.toEJson(), + 'decimals': decimals.toEJson(), + }; + } + + static EJsonValue _toEJson(AllTypesEmbedded value) => value.toEJson(); + static AllTypesEmbedded _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'stringProp': EJsonValue stringProp, + 'boolProp': EJsonValue boolProp, + 'dateProp': EJsonValue dateProp, + 'doubleProp': EJsonValue doubleProp, + 'objectIdProp': EJsonValue objectIdProp, + 'uuidProp': EJsonValue uuidProp, + 'intProp': EJsonValue intProp, + 'decimalProp': EJsonValue decimalProp, + 'nullableStringProp': EJsonValue nullableStringProp, + 'nullableBoolProp': EJsonValue nullableBoolProp, + 'nullableDateProp': EJsonValue nullableDateProp, + 'nullableDoubleProp': EJsonValue nullableDoubleProp, + 'nullableObjectIdProp': EJsonValue nullableObjectIdProp, + 'nullableUuidProp': EJsonValue nullableUuidProp, + 'nullableIntProp': EJsonValue nullableIntProp, + 'nullableDecimalProp': EJsonValue nullableDecimalProp, + 'strings': EJsonValue strings, + 'bools': EJsonValue bools, + 'dates': EJsonValue dates, + 'doubles': EJsonValue doubles, + 'objectIds': EJsonValue objectIds, + 'uuids': EJsonValue uuids, + 'ints': EJsonValue ints, + 'decimals': EJsonValue decimals, + } => + AllTypesEmbedded( + fromEJson(stringProp), + fromEJson(boolProp), + fromEJson(dateProp), + fromEJson(doubleProp), + fromEJson(objectIdProp), + fromEJson(uuidProp), + fromEJson(intProp), + fromEJson(decimalProp), + nullableStringProp: fromEJson(nullableStringProp), + nullableBoolProp: fromEJson(nullableBoolProp), + nullableDateProp: fromEJson(nullableDateProp), + nullableDoubleProp: fromEJson(nullableDoubleProp), + nullableObjectIdProp: fromEJson(nullableObjectIdProp), + nullableUuidProp: fromEJson(nullableUuidProp), + nullableIntProp: fromEJson(nullableIntProp), + nullableDecimalProp: fromEJson(nullableDecimalProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(AllTypesEmbedded._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.embeddedObject, AllTypesEmbedded, 'AllTypesEmbedded', [ SchemaProperty('stringProp', RealmPropertyType.string), @@ -2166,7 +2878,7 @@ class AllTypesEmbedded extends _AllTypesEmbedded SchemaProperty('decimals', RealmPropertyType.decimal128, collectionType: RealmCollectionType.list), ]); - } + }(); } class ObjectWithEmbedded extends _ObjectWithEmbedded @@ -2243,10 +2955,41 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded ObjectWithEmbedded freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'differentiator': differentiator.toEJson(), + 'singleObject': singleObject.toEJson(), + 'list': list.toEJson(), + 'recursiveObject': recursiveObject.toEJson(), + 'recursiveList': recursiveList.toEJson(), + }; + } + + static EJsonValue _toEJson(ObjectWithEmbedded value) => value.toEJson(); + static ObjectWithEmbedded _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'differentiator': EJsonValue differentiator, + 'singleObject': EJsonValue singleObject, + 'list': EJsonValue list, + 'recursiveObject': EJsonValue recursiveObject, + 'recursiveList': EJsonValue recursiveList, + } => + ObjectWithEmbedded( + fromEJson(id), + differentiator: fromEJson(differentiator), + singleObject: fromEJson(singleObject), + recursiveObject: fromEJson(recursiveObject), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(ObjectWithEmbedded._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, ObjectWithEmbedded, 'ObjectWithEmbedded', [ SchemaProperty('id', RealmPropertyType.string, @@ -2263,7 +3006,7 @@ class ObjectWithEmbedded extends _ObjectWithEmbedded linkTarget: 'RecursiveEmbedded1', collectionType: RealmCollectionType.list), ]); - } + }(); } class RecursiveEmbedded1 extends _RecursiveEmbedded1 @@ -2320,10 +3063,36 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 RecursiveEmbedded1 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'value': value.toEJson(), + 'child': child.toEJson(), + 'children': children.toEJson(), + 'realmObject': realmObject.toEJson(), + }; + } + + static EJsonValue _toEJson(RecursiveEmbedded1 value) => value.toEJson(); + static RecursiveEmbedded1 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'value': EJsonValue value, + 'child': EJsonValue child, + 'children': EJsonValue children, + 'realmObject': EJsonValue realmObject, + } => + RecursiveEmbedded1( + fromEJson(value), + child: fromEJson(child), + realmObject: fromEJson(realmObject), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded1._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.embeddedObject, RecursiveEmbedded1, 'RecursiveEmbedded1', [ SchemaProperty('value', RealmPropertyType.string), @@ -2335,7 +3104,7 @@ class RecursiveEmbedded1 extends _RecursiveEmbedded1 SchemaProperty('realmObject', RealmPropertyType.object, optional: true, linkTarget: 'ObjectWithEmbedded'), ]); - } + }(); } class RecursiveEmbedded2 extends _RecursiveEmbedded2 @@ -2392,10 +3161,36 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 RecursiveEmbedded2 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'value': value.toEJson(), + 'child': child.toEJson(), + 'children': children.toEJson(), + 'realmObject': realmObject.toEJson(), + }; + } + + static EJsonValue _toEJson(RecursiveEmbedded2 value) => value.toEJson(); + static RecursiveEmbedded2 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'value': EJsonValue value, + 'child': EJsonValue child, + 'children': EJsonValue children, + 'realmObject': EJsonValue realmObject, + } => + RecursiveEmbedded2( + fromEJson(value), + child: fromEJson(child), + realmObject: fromEJson(realmObject), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded2._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.embeddedObject, RecursiveEmbedded2, 'RecursiveEmbedded2', [ SchemaProperty('value', RealmPropertyType.string), @@ -2407,7 +3202,7 @@ class RecursiveEmbedded2 extends _RecursiveEmbedded2 SchemaProperty('realmObject', RealmPropertyType.object, optional: true, linkTarget: 'ObjectWithEmbedded'), ]); - } + }(); } class RecursiveEmbedded3 extends _RecursiveEmbedded3 @@ -2433,15 +3228,33 @@ class RecursiveEmbedded3 extends _RecursiveEmbedded3 RecursiveEmbedded3 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'value': value.toEJson(), + }; + } + + static EJsonValue _toEJson(RecursiveEmbedded3 value) => value.toEJson(); + static RecursiveEmbedded3 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'value': EJsonValue value, + } => + RecursiveEmbedded3( + fromEJson(value), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RecursiveEmbedded3._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.embeddedObject, RecursiveEmbedded3, 'RecursiveEmbedded3', [ SchemaProperty('value', RealmPropertyType.string), ]); - } + }(); } class ObjectWithDecimal extends _ObjectWithDecimal @@ -2477,17 +3290,38 @@ class ObjectWithDecimal extends _ObjectWithDecimal ObjectWithDecimal freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'decimal': decimal.toEJson(), + 'nullableDecimal': nullableDecimal.toEJson(), + }; + } + + static EJsonValue _toEJson(ObjectWithDecimal value) => value.toEJson(); + static ObjectWithDecimal _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'decimal': EJsonValue decimal, + 'nullableDecimal': EJsonValue nullableDecimal, + } => + ObjectWithDecimal( + fromEJson(decimal), + nullableDecimal: fromEJson(nullableDecimal), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(ObjectWithDecimal._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, ObjectWithDecimal, 'ObjectWithDecimal', [ SchemaProperty('decimal', RealmPropertyType.decimal128), SchemaProperty('nullableDecimal', RealmPropertyType.decimal128, optional: true), ]); - } + }(); } class Asymmetric extends _Asymmetric @@ -2532,10 +3366,33 @@ class Asymmetric extends _Asymmetric @override Asymmetric freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + 'symmetric': symmetric.toEJson(), + 'embeddedObjects': embeddedObjects.toEJson(), + }; + } + + static EJsonValue _toEJson(Asymmetric value) => value.toEJson(); + static Asymmetric _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'symmetric': EJsonValue symmetric, + 'embeddedObjects': EJsonValue embeddedObjects, + } => + Asymmetric( + fromEJson(id), + symmetric: fromEJson(symmetric), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Asymmetric._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.asymmetricObject, Asymmetric, 'Asymmetric', [ SchemaProperty('id', RealmPropertyType.objectid, @@ -2545,7 +3402,7 @@ class Asymmetric extends _Asymmetric SchemaProperty('embeddedObjects', RealmPropertyType.object, linkTarget: 'Embedded', collectionType: RealmCollectionType.list), ]); - } + }(); } class Embedded extends _Embedded @@ -2587,17 +3444,41 @@ class Embedded extends _Embedded @override Embedded freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'value': value.toEJson(), + 'any': any.toEJson(), + 'symmetric': symmetric.toEJson(), + }; + } + + static EJsonValue _toEJson(Embedded value) => value.toEJson(); + static Embedded _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'value': EJsonValue value, + 'any': EJsonValue any, + 'symmetric': EJsonValue symmetric, + } => + Embedded( + fromEJson(value), + any: fromEJson(any), + symmetric: fromEJson(symmetric), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Embedded._); + register(_toEJson, _fromEJson); 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'), ]); - } + }(); } class Symmetric extends _Symmetric @@ -2622,13 +3503,31 @@ class Symmetric extends _Symmetric @override Symmetric freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(Symmetric value) => value.toEJson(); + static Symmetric _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_id': EJsonValue id, + } => + Symmetric( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Symmetric._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Symmetric, 'Symmetric', [ SchemaProperty('id', RealmPropertyType.objectid, mapTo: '_id', primaryKey: true), ]); - } + }(); } diff --git a/packages/realm_dart/test/user_test.dart b/packages/realm_dart/test/user_test.dart index d12d16c48..c4c9ff1d7 100644 --- a/packages/realm_dart/test/user_test.dart +++ b/packages/realm_dart/test/user_test.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2022 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; import 'dart:isolate'; diff --git a/packages/realm_dart/tool/build.dart b/packages/realm_dart/tool/build.dart new file mode 100644 index 000000000..85b890c1d --- /dev/null +++ b/packages/realm_dart/tool/build.dart @@ -0,0 +1,285 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + +// This is a simple command-line tool to build native assets for realm_dart +// It is a precursor to the upcoming `native_assets` feature. +import 'dart:async'; +import 'dart:io' as io; +import 'package:args/command_runner.dart'; +import 'package:collection/collection.dart'; +import 'package:mason_logger/mason_logger.dart'; +import 'package:async/async.dart'; + +extension on Iterable { + T? firstEqualIgnoreCase(String? value) => value == null ? null : where((e) => equalsIgnoreAsciiCase(e.name, value)).firstOrNull; + Iterable get names => map((e) => e.name); +} + +// This enum is based on `Architecture` class from the upcoming `native_assets_cli` package +enum Architecture { + arm('armeabi-v7a'), + arm64('arm64-v8a'), + ia32('x86'), + riscv32, + riscv64, + x64('x86_64'), + ; + + final String? _cmakeName; + String get cmakeName => _cmakeName ?? name; + + const Architecture([this._cmakeName]); + + static Architecture? from(String name) => Architecture.values.firstEqualIgnoreCase(name); +} + +// This enum is based on `iOSSdk` class from the upcoming `native_assets_cli` package +// ignore: camel_case_types +enum iOSSdk { + iPhoneOS('device'), + iPhoneSimulator('simulator'), + ; // flutter doesn't support maccatalyst (yet?) + + final String? _cmakeName; + String get cmakeName => _cmakeName ?? name; + + const iOSSdk([this._cmakeName]); + + static iOSSdk? from(String? name) => iOSSdk.values.firstEqualIgnoreCase(name); +} + +// This enum is based on `OS` class from the upcoming `native_assets_cli` package +enum OS { + android, + iOS, + macOS, + windows, + linux, + ; + + String get cmakeName => name.toLowerCase(); + + static OS? from(String? name) => OS.values.firstEqualIgnoreCase(name); + static OS get current => from(io.Platform.operatingSystem) ?? (throw UnsupportedError('Unsupported OS: ${io.Platform.operatingSystem}')); +} + +// Currently supported targets +// This enum is based on `Target` class from the upcoming `native_assets_cli` package +enum Target { + androidArm(Architecture.arm, OS.android), + androidArm64(Architecture.arm64, OS.android), + androidIA32(Architecture.ia32, OS.android), + androidX64(Architecture.x64, OS.android), // only for emulator + // androidRiscv64, // not supported by realm currently + // fuchsiaArm64, // -"- etc. + // fuchsiaX64, + // iOSArm(Architecture.arm, OS.iOS), // <-- pre ios11, not even supported by flutter?!? + iOSArm64(Architecture.arm64, OS.iOS), + iOSX64(Architecture.x64, OS.iOS), // only for simulator + // linuxArm, + // linuxArm64, + // linuxIA32, + // linuxRiscv32, + // linuxRiscv64, + linuxX64(Architecture.x64, OS.linux), + macOSArm64(Architecture.arm64, OS.macOS), + macOSX64(Architecture.x64, OS.macOS), + // windowsArm64, + // windowsIA32, + windowsX64(Architecture.x64, OS.windows), + ; + + final Architecture architecture; + final OS os; + + const Target(this.architecture, this.os); + + static Target? from(String? name) => Target.values.firstEqualIgnoreCase(name); +} + +enum BuildMode { + debug('Debug'), + release('Release'), + ; + + final String cmakeName; + + const BuildMode(this.cmakeName); + + static BuildMode? from(String? name) => BuildMode.values.firstEqualIgnoreCase(name); +} + +abstract class _BaseCommand extends Command { + @override + final String name; + @override + final String description; + + _BaseCommand(this.name, this.description); + + late final verbose = globalResults!['verbose'] as bool; // don't access before run + + OS get os; + // currently target must match the host OS, or be an android platform + Iterable get possibleTargets => Target.values.where((t) => t.os == os || t.os == OS.android || (os == OS.macOS && t.os == OS.iOS)); +} + +class _BuildNativeCommand extends _BaseCommand { + _BuildNativeCommand() + : super( + 'native', + 'Build native assets for realm_dart', + ) { + argParser + ..addMultiOption( + 'target', + abbr: 't', + help: 'The target platform to build for. Defaults to all possible targets', + allowed: [...possibleTargets.names, 'all'], + defaultsTo: ['all'], + ) + ..addOption( + 'build-mode', + abbr: 'm', + allowed: BuildMode.values.names, + defaultsTo: BuildMode.release.name, + ) + ..addMultiOption( + 'ios-sdk', + abbr: 's', + help: 'The iOS SDK to build for. Ignored for non-iOS platforms. Defaults to all available SDKs.', + allowed: [...iOSSdk.values.names, 'all'], + defaultsTo: ['all'], + ); + } + + @override + OS get os => OS.current; + + Future runProc(List args, {required Logger logger, String? message}) async { + final p = await io.Process.start(args.first, args.skip(1).toList()); + Progress? progress; + if (verbose) { + await Future.wait([io.stdout.addStream(p.stdout), io.stderr.addStream(p.stderr)]); + } else { + message ??= args.join(' '); + final width = io.stdout.hasTerminal ? io.stdout.terminalColumns - 12 : 80; + message = message.padRight(width).substring(0, width); + progress = logger.progress(message); + await for (final _ in StreamGroup.merge([p.stdout, p.stderr])) { + progress.update(message); + } + } + final exitCode = await p.exitCode; + if (exitCode < 0) { + progress?.fail(message); + logger.err('Error: "$message}" exited with code $exitCode'); + return exitCode; + } else { + progress?.complete(message); + return null; // return null if successful + } + } + + @override + Future run() async { + final argResults = this.argResults!; + final targetOptions = argResults['target'] as List; + + final targets = targetOptions.contains('all') // if 'all' is specified, build for all possible targets + ? possibleTargets + : targetOptions.map((o) => Target.from(o) ?? (throw ArgumentError.value(o, 'target', 'Invalid target'))); + + final buildMode = + BuildMode.from(argResults['build-mode'] as String?) ?? (throw ArgumentError.value(argResults['build-mode'], 'build-mode', 'Invalid build mode')); + + final iosSdkOptions = argResults['ios-sdk'] as List; + final iosSdks = iosSdkOptions.contains('all') // if 'all' is specified, build for all available SDKs + ? iOSSdk.values + : iosSdkOptions.map((o) => iOSSdk.from(o)).whereNotNull(); + + int? exitCode; + for (final target in targets) { + logger.info('Building for ${target.name} in ${buildMode.name} mode'); + switch (target.os) { + case OS.iOS: + for (final sdk in iosSdks) { + exitCode ??= await runProc(['cmake', '--preset=ios'], logger: logger); + exitCode ??= await runProc(['cmake', '--build', '--preset=ios-${sdk.cmakeName}', '--config=${buildMode.cmakeName}'], logger: logger); + } + exitCode ??= await runProc( + [ + 'xcodebuild', + '-create-xcframework', + for (final s in iosSdks) '-framework ./binary/ios/${buildMode.cmakeName}-${s.name.toLowerCase()}/realm_dart.framework', + '-output ./binary/ios/realm_dart.xcframework', + ], + logger: logger, + ); + break; + + case OS.android: + case OS.linux: + case OS.macOS: + case OS.windows: + final preset = '${target.os.cmakeName}${target.os == OS.android ? "-${target.architecture.cmakeName}" : ""}'; + exitCode ??= await runProc(['cmake', '--preset=$preset'], logger: logger); + exitCode ??= await runProc( + [ + 'cmake', + '--build', + '--preset=$preset', + '--config=${buildMode.cmakeName}', + if (target.os == OS.macOS) '-- -destination "generic/platform=macOS', + if (target.os == OS.android) '--target=strip', + ], + logger: logger, + ); + break; + } + io.stdout.writeln(); + } + return exitCode ?? 0; + } +} + +class _PossibleTargets extends _BaseCommand { + _PossibleTargets() + : super( + 'targets', + 'List possible targets for building native assets', + ) { + argParser.addOption( + 'os', + abbr: 'o', + allowed: OS.values.names, + defaultsTo: OS.current.name, + ); + } + + late final _osOption = argResults?['os'] as String?; + @override + OS get os => OS.from(_osOption) ?? (throw ArgumentError.value(_osOption, 'os', 'Invalid OS')); + + @override + int run() { + print(possibleTargets.names.join('\n')); + return 0; + } +} + +final logger = Logger(progressOptions: ProgressOptions(trailing: '')); + +Future main(List arguments) async { + final runner = CommandRunner('build', 'Helper tool for building realm_dart') + ..addCommand(_BuildNativeCommand()) + ..addCommand(_PossibleTargets()) + ..argParser.addFlag('verbose', abbr: 'v', help: 'Print verbose output', defaultsTo: false); + try { + final exitCode = await runner.run(arguments); + io.exit(exitCode!); + } on UsageException catch (error) { + logger.err('$error'); + io.exit(64); // Exit code 64 indicates a usage error. + } +} diff --git a/packages/realm_generator/build.yaml b/packages/realm_generator/build.yaml index d44a193d7..c7d6e8002 100644 --- a/packages/realm_generator/build.yaml +++ b/packages/realm_generator/build.yaml @@ -1,3 +1,12 @@ +targets: + $default: + builders: + realm_generator: + enabled: true + generate_for: + include: + - test/good_test_data/**.dart + builders: realm_generator: import: "package:realm_generator/realm_generator.dart" diff --git a/packages/realm_generator/lib/realm_generator.dart b/packages/realm_generator/lib/realm_generator.dart index 0f4fd9e63..4dff21063 100644 --- a/packages/realm_generator/lib/realm_generator.dart +++ b/packages/realm_generator/lib/realm_generator.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 /// Usage /// diff --git a/packages/realm_generator/lib/src/annotation_value.dart b/packages/realm_generator/lib/src/annotation_value.dart index 4ddf08415..88fade01d 100644 --- a/packages/realm_generator/lib/src/annotation_value.dart +++ b/packages/realm_generator/lib/src/annotation_value.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/constant/value.dart'; diff --git a/packages/realm_generator/lib/src/class_element_ex.dart b/packages/realm_generator/lib/src/class_element_ex.dart index d1e098ba6..00c8fd0e4 100644 --- a/packages/realm_generator/lib/src/class_element_ex.dart +++ b/packages/realm_generator/lib/src/class_element_ex.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:analyzer/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; diff --git a/packages/realm_generator/lib/src/dart_type_ex.dart b/packages/realm_generator/lib/src/dart_type_ex.dart index 744149334..2cdf2a179 100644 --- a/packages/realm_generator/lib/src/dart_type_ex.dart +++ b/packages/realm_generator/lib/src/dart_type_ex.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:typed_data'; diff --git a/packages/realm_generator/lib/src/element.dart b/packages/realm_generator/lib/src/element.dart index bc40feb0f..6ffd79f10 100644 --- a/packages/realm_generator/lib/src/element.dart +++ b/packages/realm_generator/lib/src/element.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:math'; diff --git a/packages/realm_generator/lib/src/error.dart b/packages/realm_generator/lib/src/error.dart index 6e95367fa..f5c399d20 100644 --- a/packages/realm_generator/lib/src/error.dart +++ b/packages/realm_generator/lib/src/error.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:analyzer/dart/element/element.dart'; import 'package:source_gen/source_gen.dart'; import 'package:source_span/source_span.dart'; @@ -31,8 +17,8 @@ class RealmInvalidGenerationSourceError extends InvalidGenerationSourceError { bool color; RealmInvalidGenerationSourceError( - String message, { - required String todo, + super.message, { + required super.todo, required Element element, FileSpan? primarySpan, bool? color, @@ -41,7 +27,7 @@ class RealmInvalidGenerationSourceError extends InvalidGenerationSourceError { }) : primarySpan = primarySpan ?? element.span, secondarySpans = {...secondarySpans}, color = color ?? session.color, - super(message, todo: todo, element: element) { + super(element: element) { if (element is FieldElement || element is ConstructorElement) { final classElement = element.enclosingElement!; this.secondarySpans.addAll({ diff --git a/packages/realm_generator/lib/src/expanded_context_span.dart b/packages/realm_generator/lib/src/expanded_context_span.dart index 47b1c538d..16e7b9348 100644 --- a/packages/realm_generator/lib/src/expanded_context_span.dart +++ b/packages/realm_generator/lib/src/expanded_context_span.dart @@ -1,31 +1,15 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:source_span/source_span.dart'; class ExpandedContextSpan with SourceSpanMixin implements FileSpan { final FileSpan _span, _contextSpan; - ExpandedContextSpan(this._span, Iterable contextSpans) : - _contextSpan = contextSpans.fold(_span, (acc, c) => acc.expand(c)); + ExpandedContextSpan(this._span, Iterable contextSpans) : _contextSpan = contextSpans.fold(_span, (acc, c) => acc.expand(c)); @override - String get context => _contextSpan.context; + String get context => _contextSpan.context; @override FileLocation get end => _span.end; @@ -46,5 +30,5 @@ class ExpandedContextSpan with SourceSpanMixin implements FileSpan { FileLocation get start => _span.start; @override - String get text => _span.text; -} \ No newline at end of file + String get text => _span.text; +} diff --git a/packages/realm_generator/lib/src/field_element_ex.dart b/packages/realm_generator/lib/src/field_element_ex.dart index 4567c3fe0..f44947e96 100644 --- a/packages/realm_generator/lib/src/field_element_ex.dart +++ b/packages/realm_generator/lib/src/field_element_ex.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:analyzer/src/dart/ast/ast.dart'; import 'package:analyzer/dart/element/element.dart'; diff --git a/packages/realm_generator/lib/src/format_spans.dart b/packages/realm_generator/lib/src/format_spans.dart index 4473cfb04..4736b5c91 100644 --- a/packages/realm_generator/lib/src/format_spans.dart +++ b/packages/realm_generator/lib/src/format_spans.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:analyzer/dart/element/element.dart'; import 'package:source_span/source_span.dart'; diff --git a/packages/realm_generator/lib/src/measure.dart b/packages/realm_generator/lib/src/measure.dart index 5b3179877..60f3e7337 100644 --- a/packages/realm_generator/lib/src/measure.dart +++ b/packages/realm_generator/lib/src/measure.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'dart:async'; import 'package:build/build.dart'; // for shared logging instance log diff --git a/packages/realm_generator/lib/src/pseudo_type.dart b/packages/realm_generator/lib/src/pseudo_type.dart index 8ad2067b3..61e5a8160 100644 --- a/packages/realm_generator/lib/src/pseudo_type.dart +++ b/packages/realm_generator/lib/src/pseudo_type.dart @@ -1,3 +1,6 @@ +// Copyright 2024 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + // ignore_for_file: implementation_imports import 'dart:mirrors'; diff --git a/packages/realm_generator/lib/src/realm_field_info.dart b/packages/realm_generator/lib/src/realm_field_info.dart index 1a5fc0616..68c7202a6 100644 --- a/packages/realm_generator/lib/src/realm_field_info.dart +++ b/packages/realm_generator/lib/src/realm_field_info.dart @@ -1,20 +1,6 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 + import 'package:analyzer/dart/element/element.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:realm_common/realm_common.dart'; diff --git a/packages/realm_generator/lib/src/realm_model_info.dart b/packages/realm_generator/lib/src/realm_model_info.dart index 21f64e57f..0866c2d5f 100644 --- a/packages/realm_generator/lib/src/realm_model_info.dart +++ b/packages/realm_generator/lib/src/realm_model_info.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:realm_common/realm_common.dart'; @@ -43,16 +28,16 @@ class RealmModelInfo { yield ''; } + final required = allSettable.where((f) => f.isRequired || f.isPrimaryKey); + final notRequired = allSettable.where((f) => !f.isRequired && !f.isPrimaryKey); + final lists = fields.where((f) => f.isDartCoreList).toList(); + final sets = fields.where((f) => f.isDartCoreSet).toList(); + final maps = fields.where((f) => f.isDartCoreMap).toList(); + // Constructor yield '$name('; { - final required = allSettable.where((f) => f.isRequired || f.isPrimaryKey); yield* required.map((f) => '${f.mappedTypeName} ${f.name},'); - - final notRequired = allSettable.where((f) => !f.isRequired && !f.isPrimaryKey); - final lists = fields.where((f) => f.isDartCoreList).toList(); - final sets = fields.where((f) => f.isDartCoreSet).toList(); - final maps = fields.where((f) => f.isDartCoreMap).toList(); if (notRequired.isNotEmpty || lists.isNotEmpty || sets.isNotEmpty || maps.isNotEmpty) { yield '{'; yield* notRequired.map((f) { @@ -118,12 +103,49 @@ class RealmModelInfo { yield '$name freeze() => RealmObjectBase.freezeObject<$name>(this);'; yield ''; + // Encode + yield 'EJsonValue toEJson() {'; + { + yield 'return {'; + { + yield* fields.map((f) { + return "'${f.realmName}': ${f.name}.toEJson(),"; + }); + } + yield '};'; + } + yield '}'; + + yield 'static EJsonValue _toEJson($name value) => value.toEJson();'; + + // Decode + yield 'static $name _fromEJson(EJsonValue ejson) {'; + { + yield 'return switch (ejson) {'; + { + yield '{'; + { + yield* fields.map((f) { + return "'${f.realmName}': EJsonValue ${f.name},"; + }); + } + yield '} => $name('; + { + yield* required.map((f) => 'fromEJson(${f.name}),'); + yield* notRequired.map((f) => '${f.name}: fromEJson(${f.name}),'); + } + yield '),'; + yield '_ => raiseInvalidEJson(ejson),'; + } + yield '};'; + } + yield '}'; + // Schema - yield 'static SchemaObject get schema => _schema ??= _initSchema();'; - yield 'static SchemaObject? _schema;'; - yield 'static SchemaObject _initSchema() {'; + yield 'static final schema = () {'; { yield 'RealmObjectBase.registerFactory($name._);'; + yield 'register(_toEJson, _fromEJson);'; yield "return const SchemaObject(ObjectType.${baseType.name}, $name, '$realmName', ["; { yield* fields.map((f) { @@ -145,7 +167,7 @@ class RealmModelInfo { } yield ']);'; } - yield '}'; + yield '}();'; } yield '}'; } diff --git a/packages/realm_generator/lib/src/realm_object_generator.dart b/packages/realm_generator/lib/src/realm_object_generator.dart index 8c7a33b17..67b58b77e 100644 --- a/packages/realm_generator/lib/src/realm_object_generator.dart +++ b/packages/realm_generator/lib/src/realm_object_generator.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 library realm_generator; diff --git a/packages/realm_generator/lib/src/session.dart b/packages/realm_generator/lib/src/session.dart index 438b42b0a..0e09cca18 100644 --- a/packages/realm_generator/lib/src/session.dart +++ b/packages/realm_generator/lib/src/session.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'dart:async'; diff --git a/packages/realm_generator/lib/src/type_checkers.dart b/packages/realm_generator/lib/src/type_checkers.dart index 96890c087..600513b22 100644 --- a/packages/realm_generator/lib/src/type_checkers.dart +++ b/packages/realm_generator/lib/src/type_checkers.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 import 'package:realm_common/realm_common.dart'; import 'package:source_gen/source_gen.dart'; diff --git a/packages/realm_generator/lib/src/utils.dart b/packages/realm_generator/lib/src/utils.dart index dd11b776a..14bb0fd5b 100644 --- a/packages/realm_generator/lib/src/utils.dart +++ b/packages/realm_generator/lib/src/utils.dart @@ -1,20 +1,5 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright 2021 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. -// -//////////////////////////////////////////////////////////////////////////////// +// Copyright 2021 MongoDB, Inc. +// SPDX-License-Identifier: Apache-2.0 String anOrA(String text) => 'aeiouy'.contains(text[0]) ? 'an' : 'a'; diff --git a/packages/realm_generator/pubspec.yaml b/packages/realm_generator/pubspec.yaml index 57f0f578f..71fc05291 100644 --- a/packages/realm_generator/pubspec.yaml +++ b/packages/realm_generator/pubspec.yaml @@ -9,8 +9,6 @@ homepage: https://www.realm.io repository: https://github.com/realm/realm-dart issue_tracker: https://github.com/realm/realm-dart/issues -publish_to: none - environment: sdk: ^3.0.0 @@ -19,8 +17,7 @@ dependencies: build_resolvers: ^2.0.9 build: ^2.0.0 dart_style: ^2.2.0 - realm_common: - path: ../realm_common + realm_common: ^1.8.0 source_gen: ^1.1.0 source_span: ^1.8.0 diff --git a/packages/realm_generator/test/error_test_data/realm_object_reference_default_values.dart b/packages/realm_generator/test/error_test_data/realm_object_reference_default_values.dart index b77305892..5da4b2c31 100644 --- a/packages/realm_generator/test/error_test_data/realm_object_reference_default_values.dart +++ b/packages/realm_generator/test/error_test_data/realm_object_reference_default_values.dart @@ -8,4 +8,4 @@ class _Person { late _Person? parent = Person(); } -class Person extends _Person {} // mock class for testing \ No newline at end of file +class Person extends _Person {} // mock class for testing diff --git a/packages/realm_generator/test/good_test_data/all_types.expected b/packages/realm_generator/test/good_test_data/all_types.expected index 779210119..bdd5e45c0 100644 --- a/packages/realm_generator/test/good_test_data/all_types.expected +++ b/packages/realm_generator/test/good_test_data/all_types.expected @@ -42,16 +42,38 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { @override Foo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'x': x.toEJson(), + 'bar': bar.toEJson(), + }; + } + + static EJsonValue _toEJson(Foo value) => value.toEJson(); + static Foo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'x': EJsonValue x, + 'bar': EJsonValue bar, + } => + Foo( + x: fromEJson(x), + bar: fromEJson(bar), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Foo._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Foo, 'MyFoo', [ - SchemaProperty('x', RealmPropertyType.int, indexType: RealmIndexType.regular), + SchemaProperty('x', RealmPropertyType.int, + indexType: RealmIndexType.regular), SchemaProperty('bar', RealmPropertyType.object, optional: true, linkTarget: 'Bar'), ]); - } + }(); } class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { @@ -94,10 +116,10 @@ class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { RealmObjectBase.set(this, 'any', any); RealmObjectBase.set(this, 'decimal', decimal); RealmObjectBase.set>(this, 'list', RealmList(list)); - RealmObjectBase.set>(this, 'manyAny', RealmList(manyAny)); + RealmObjectBase.set>( + this, 'manyAny', RealmList(manyAny)); RealmObjectBase.set>(this, 'set', RealmSet(set)); - RealmObjectBase.set>( - this, 'map', RealmMap(map)); + RealmObjectBase.set>(this, 'map', RealmMap(map)); } Bar._(); @@ -167,8 +189,7 @@ class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { 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 String? get anOptionalString => @@ -199,8 +220,7 @@ class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { @override RealmResults get foos { if (!isManaged) { - throw RealmError( - 'Using backlinks is only possible for managed objects.'); + throw RealmError('Using backlinks is only possible for managed objects.'); } return RealmObjectBase.get(this, 'foos') as RealmResults; } @@ -216,22 +236,87 @@ class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { @override Bar freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'aBool': aBool.toEJson(), + 'another': another.toEJson(), + 'data': data.toEJson(), + 'tidspunkt': timestamp.toEJson(), + 'aDouble': aDouble.toEJson(), + 'foo': foo.toEJson(), + 'objectId': objectId.toEJson(), + 'uuid': uuid.toEJson(), + 'list': list.toEJson(), + 'set': set.toEJson(), + 'map': map.toEJson(), + 'anOptionalString': anOptionalString.toEJson(), + 'any': any.toEJson(), + 'manyAny': manyAny.toEJson(), + 'decimal': decimal.toEJson(), + 'foos': foos.toEJson(), + }; + } + + static EJsonValue _toEJson(Bar value) => value.toEJson(); + static Bar _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + 'aBool': EJsonValue aBool, + 'another': EJsonValue another, + 'data': EJsonValue data, + 'tidspunkt': EJsonValue timestamp, + 'aDouble': EJsonValue aDouble, + 'foo': EJsonValue foo, + 'objectId': EJsonValue objectId, + 'uuid': EJsonValue uuid, + 'list': EJsonValue list, + 'set': EJsonValue set, + 'map': EJsonValue map, + 'anOptionalString': EJsonValue anOptionalString, + 'any': EJsonValue any, + 'manyAny': EJsonValue manyAny, + 'decimal': EJsonValue decimal, + 'foos': EJsonValue foos, + } => + Bar( + fromEJson(name), + fromEJson(aBool), + fromEJson(another), + fromEJson(objectId), + fromEJson(uuid), + fromEJson(decimal), + data: fromEJson(data), + timestamp: fromEJson(timestamp), + aDouble: fromEJson(aDouble), + foo: fromEJson(foo), + anOptionalString: fromEJson(anOptionalString), + any: fromEJson(any), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Bar._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Bar, 'Bar', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), - SchemaProperty('aBool', RealmPropertyType.bool, indexType: RealmIndexType.regular), - SchemaProperty('another', RealmPropertyType.bool, indexType: RealmIndexType.regular), + SchemaProperty('aBool', RealmPropertyType.bool, + indexType: RealmIndexType.regular), + SchemaProperty('another', RealmPropertyType.bool, + indexType: RealmIndexType.regular), SchemaProperty('data', RealmPropertyType.binary), SchemaProperty('timestamp', RealmPropertyType.timestamp, mapTo: 'tidspunkt', indexType: RealmIndexType.regular), SchemaProperty('aDouble', RealmPropertyType.double), SchemaProperty('foo', RealmPropertyType.object, optional: true, linkTarget: 'MyFoo'), - SchemaProperty('objectId', RealmPropertyType.objectid, indexType: RealmIndexType.regular), - SchemaProperty('uuid', RealmPropertyType.uuid, indexType: RealmIndexType.regular), + SchemaProperty('objectId', RealmPropertyType.objectid, + indexType: RealmIndexType.regular), + SchemaProperty('uuid', RealmPropertyType.uuid, + indexType: RealmIndexType.regular), SchemaProperty('list', RealmPropertyType.int, collectionType: RealmCollectionType.list), SchemaProperty('set', RealmPropertyType.int, @@ -249,7 +334,7 @@ class Bar extends _Bar with RealmEntity, RealmObjectBase, RealmObject { collectionType: RealmCollectionType.list, linkTarget: 'MyFoo'), ]); - } + }(); } class PrimitiveTypes extends _PrimitiveTypes @@ -309,10 +394,40 @@ class PrimitiveTypes extends _PrimitiveTypes @override PrimitiveTypes freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'stringProp': stringProp.toEJson(), + 'boolProp': boolProp.toEJson(), + 'dateProp': dateProp.toEJson(), + 'doubleProp': doubleProp.toEJson(), + 'objectIdProp': objectIdProp.toEJson(), + }; + } + + static EJsonValue _toEJson(PrimitiveTypes value) => value.toEJson(); + static PrimitiveTypes _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'stringProp': EJsonValue stringProp, + 'boolProp': EJsonValue boolProp, + 'dateProp': EJsonValue dateProp, + 'doubleProp': EJsonValue doubleProp, + 'objectIdProp': EJsonValue objectIdProp, + } => + PrimitiveTypes( + fromEJson(stringProp), + fromEJson(boolProp), + fromEJson(dateProp), + fromEJson(doubleProp), + fromEJson(objectIdProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(PrimitiveTypes._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, PrimitiveTypes, 'PrimitiveTypes', [ SchemaProperty('stringProp', RealmPropertyType.string), @@ -321,5 +436,5 @@ class PrimitiveTypes extends _PrimitiveTypes SchemaProperty('doubleProp', RealmPropertyType.double), SchemaProperty('objectIdProp', RealmPropertyType.objectid), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/another_mapto.expected_multi b/packages/realm_generator/test/good_test_data/another_mapto.expected_multi index e3ac37b43..0379a2c6a 100644 --- a/packages/realm_generator/test/good_test_data/another_mapto.expected_multi +++ b/packages/realm_generator/test/good_test_data/another_mapto.expected_multi @@ -41,10 +41,30 @@ class MappedToo extends _MappedToo @override MappedToo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'singleLink': singleLink.toEJson(), + 'listLink': listLink.toEJson(), + }; + } + + static EJsonValue _toEJson(MappedToo value) => value.toEJson(); + static MappedToo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'singleLink': EJsonValue singleLink, + 'listLink': EJsonValue listLink, + } => + MappedToo( + singleLink: fromEJson(singleLink), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(MappedToo._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, MappedToo, 'this is also mapped', [ SchemaProperty('singleLink', RealmPropertyType.object, @@ -52,5 +72,5 @@ class MappedToo extends _MappedToo SchemaProperty('listLink', RealmPropertyType.object, linkTarget: 'another type', collectionType: RealmCollectionType.list), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/asymmetric_object.expected b/packages/realm_generator/test/good_test_data/asymmetric_object.expected index d8d8497f3..e6830bb76 100644 --- a/packages/realm_generator/test/good_test_data/asymmetric_object.expected +++ b/packages/realm_generator/test/good_test_data/asymmetric_object.expected @@ -57,10 +57,36 @@ class Asymmetric extends _Asymmetric @override Asymmetric freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + 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) { + return switch (ejson) { + { + '_id': EJsonValue id, + 'children': EJsonValue children, + 'father': EJsonValue father, + 'mother': EJsonValue mother, + } => + Asymmetric( + fromEJson(id), + father: fromEJson(father), + mother: fromEJson(mother), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Asymmetric._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, Asymmetric, 'Asymmetric', [ SchemaProperty('id', RealmPropertyType.objectid, @@ -72,7 +98,7 @@ class Asymmetric extends _Asymmetric SchemaProperty('mother', RealmPropertyType.object, optional: true, linkTarget: 'Embedded'), ]); - } + }(); } class Embedded extends _Embedded @@ -104,14 +130,34 @@ class Embedded extends _Embedded @override Embedded freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + 'age': age.toEJson(), + }; + } + + static EJsonValue _toEJson(Embedded value) => value.toEJson(); + static Embedded _fromEJson(EJsonValue 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), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/binary_type.expected b/packages/realm_generator/test/good_test_data/binary_type.expected index 0595981ae..12818f4f7 100644 --- a/packages/realm_generator/test/good_test_data/binary_type.expected +++ b/packages/realm_generator/test/good_test_data/binary_type.expected @@ -14,7 +14,8 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { Uint8List? nullableBinaryProp, }) { RealmObjectBase.set(this, 'requiredBinaryProp', requiredBinaryProp); - RealmObjectBase.set(this, 'defaultValueBinaryProp', defaultValueBinaryProp ?? Uint8List(8)); + RealmObjectBase.set( + this, 'defaultValueBinaryProp', defaultValueBinaryProp ?? Uint8List(8)); RealmObjectBase.set(this, 'nullableBinaryProp', nullableBinaryProp); } @@ -49,15 +50,39 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { @override Foo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'requiredBinaryProp': requiredBinaryProp.toEJson(), + 'defaultValueBinaryProp': defaultValueBinaryProp.toEJson(), + 'nullableBinaryProp': nullableBinaryProp.toEJson(), + }; + } + + static EJsonValue _toEJson(Foo value) => value.toEJson(); + static Foo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'requiredBinaryProp': EJsonValue requiredBinaryProp, + 'defaultValueBinaryProp': EJsonValue defaultValueBinaryProp, + 'nullableBinaryProp': EJsonValue nullableBinaryProp, + } => + Foo( + fromEJson(requiredBinaryProp), + defaultValueBinaryProp: fromEJson(defaultValueBinaryProp), + nullableBinaryProp: fromEJson(nullableBinaryProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Foo._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Foo, 'Foo', [ SchemaProperty('requiredBinaryProp', RealmPropertyType.binary), SchemaProperty('defaultValueBinaryProp', RealmPropertyType.binary), SchemaProperty('nullableBinaryProp', RealmPropertyType.binary, optional: true), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/embedded_annotations.expected b/packages/realm_generator/test/good_test_data/embedded_annotations.expected index a50484e9c..0c2bf60ff 100644 --- a/packages/realm_generator/test/good_test_data/embedded_annotations.expected +++ b/packages/realm_generator/test/good_test_data/embedded_annotations.expected @@ -40,10 +40,30 @@ class Parent extends _Parent with RealmEntity, RealmObjectBase, RealmObject { @override Parent freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'single child': child.toEJson(), + 'CHILDREN': children.toEJson(), + }; + } + + static EJsonValue _toEJson(Parent value) => value.toEJson(); + static Parent _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'single child': EJsonValue child, + 'CHILDREN': EJsonValue children, + } => + Parent( + child: fromEJson(child), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Parent._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Parent, 'Parent', [ SchemaProperty('child', RealmPropertyType.object, mapTo: 'single child', optional: true, linkTarget: 'MySuperChild'), @@ -52,7 +72,7 @@ class Parent extends _Parent with RealmEntity, RealmObjectBase, RealmObject { linkTarget: 'MySuperChild', collectionType: RealmCollectionType.list), ]); - } + }(); } class Child1 extends _Child1 with RealmEntity, RealmObjectBase, EmbeddedObject { @@ -94,16 +114,41 @@ class Child1 extends _Child1 with RealmEntity, RealmObjectBase, EmbeddedObject { @override Child1 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + '_value': value.toEJson(), + '_parent': linkToParent.toEJson(), + 'indexedString': indexedString.toEJson(), + }; + } + + static EJsonValue _toEJson(Child1 value) => value.toEJson(); + static Child1 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + '_value': EJsonValue value, + '_parent': EJsonValue linkToParent, + 'indexedString': EJsonValue indexedString, + } => + Child1( + fromEJson(value), + fromEJson(indexedString), + linkToParent: fromEJson(linkToParent), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Child1._); - return const SchemaObject(ObjectType.embeddedObject, Child1, 'MySuperChild', [ + register(_toEJson, _fromEJson); + return const SchemaObject( + ObjectType.embeddedObject, Child1, 'MySuperChild', [ SchemaProperty('value', RealmPropertyType.string, mapTo: '_value'), SchemaProperty('linkToParent', RealmPropertyType.object, mapTo: '_parent', optional: true, linkTarget: 'Parent'), - SchemaProperty('indexedString', RealmPropertyType.string, indexType: RealmIndexType.regular), + SchemaProperty('indexedString', RealmPropertyType.string, + indexType: RealmIndexType.regular), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/embedded_objects.expected b/packages/realm_generator/test/good_test_data/embedded_objects.expected index 3d5376c48..fee06000e 100644 --- a/packages/realm_generator/test/good_test_data/embedded_objects.expected +++ b/packages/realm_generator/test/good_test_data/embedded_objects.expected @@ -39,17 +39,37 @@ class Parent extends _Parent with RealmEntity, RealmObjectBase, RealmObject { @override Parent freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'child': child.toEJson(), + 'children': children.toEJson(), + }; + } + + static EJsonValue _toEJson(Parent value) => value.toEJson(); + static Parent _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'child': EJsonValue child, + 'children': EJsonValue children, + } => + Parent( + child: fromEJson(child), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Parent._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Parent, 'Parent', [ SchemaProperty('child', RealmPropertyType.object, optional: true, linkTarget: 'Child1'), SchemaProperty('children', RealmPropertyType.object, linkTarget: 'Child1', collectionType: RealmCollectionType.list), ]); - } + }(); } class Child1 extends _Child1 with RealmEntity, RealmObjectBase, EmbeddedObject { @@ -100,10 +120,36 @@ class Child1 extends _Child1 with RealmEntity, RealmObjectBase, EmbeddedObject { @override Child1 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'value': value.toEJson(), + 'child': child.toEJson(), + 'children': children.toEJson(), + 'linkToParent': linkToParent.toEJson(), + }; + } + + static EJsonValue _toEJson(Child1 value) => value.toEJson(); + static Child1 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'value': EJsonValue value, + 'child': EJsonValue child, + 'children': EJsonValue children, + 'linkToParent': EJsonValue linkToParent, + } => + Child1( + fromEJson(value), + child: fromEJson(child), + linkToParent: fromEJson(linkToParent), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Child1._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.embeddedObject, Child1, 'Child1', [ SchemaProperty('value', RealmPropertyType.string), SchemaProperty('child', RealmPropertyType.object, @@ -113,7 +159,7 @@ class Child1 extends _Child1 with RealmEntity, RealmObjectBase, EmbeddedObject { SchemaProperty('linkToParent', RealmPropertyType.object, optional: true, linkTarget: 'Parent'), ]); - } + }(); } class Child2 extends _Child2 with RealmEntity, RealmObjectBase, EmbeddedObject { @@ -249,10 +295,67 @@ class Child2 extends _Child2 with RealmEntity, RealmObjectBase, EmbeddedObject { @override Child2 freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'boolProp': boolProp.toEJson(), + 'intProp': intProp.toEJson(), + 'doubleProp': doubleProp.toEJson(), + 'stringProp': stringProp.toEJson(), + 'dateProp': dateProp.toEJson(), + 'objectIdProp': objectIdProp.toEJson(), + 'uuidProp': uuidProp.toEJson(), + 'nullableBoolProp': nullableBoolProp.toEJson(), + 'nullableIntProp': nullableIntProp.toEJson(), + 'nullableDoubleProp': nullableDoubleProp.toEJson(), + 'nullableStringProp': nullableStringProp.toEJson(), + 'nullableDateProp': nullableDateProp.toEJson(), + 'nullableObjectIdProp': nullableObjectIdProp.toEJson(), + 'nullableUuidProp': nullableUuidProp.toEJson(), + }; + } + + static EJsonValue _toEJson(Child2 value) => value.toEJson(); + static Child2 _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'boolProp': EJsonValue boolProp, + 'intProp': EJsonValue intProp, + 'doubleProp': EJsonValue doubleProp, + 'stringProp': EJsonValue stringProp, + 'dateProp': EJsonValue dateProp, + 'objectIdProp': EJsonValue objectIdProp, + 'uuidProp': EJsonValue uuidProp, + 'nullableBoolProp': EJsonValue nullableBoolProp, + 'nullableIntProp': EJsonValue nullableIntProp, + 'nullableDoubleProp': EJsonValue nullableDoubleProp, + 'nullableStringProp': EJsonValue nullableStringProp, + 'nullableDateProp': EJsonValue nullableDateProp, + 'nullableObjectIdProp': EJsonValue nullableObjectIdProp, + 'nullableUuidProp': EJsonValue nullableUuidProp, + } => + Child2( + fromEJson(boolProp), + fromEJson(intProp), + fromEJson(doubleProp), + fromEJson(stringProp), + fromEJson(dateProp), + fromEJson(objectIdProp), + fromEJson(uuidProp), + nullableBoolProp: fromEJson(nullableBoolProp), + nullableIntProp: fromEJson(nullableIntProp), + nullableDoubleProp: fromEJson(nullableDoubleProp), + nullableStringProp: fromEJson(nullableStringProp), + nullableDateProp: fromEJson(nullableDateProp), + nullableObjectIdProp: fromEJson(nullableObjectIdProp), + nullableUuidProp: fromEJson(nullableUuidProp), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Child2._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.embeddedObject, Child2, 'Child2', [ SchemaProperty('boolProp', RealmPropertyType.bool), SchemaProperty('intProp', RealmPropertyType.int), @@ -275,6 +378,5 @@ class Child2 extends _Child2 with RealmEntity, RealmObjectBase, EmbeddedObject { SchemaProperty('nullableUuidProp', RealmPropertyType.uuid, optional: true), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/indexable_types.expected b/packages/realm_generator/test/good_test_data/indexable_types.expected index 32ad89839..827e459b4 100644 --- a/packages/realm_generator/test/good_test_data/indexable_types.expected +++ b/packages/realm_generator/test/good_test_data/indexable_types.expected @@ -158,10 +158,73 @@ class Indexable extends _Indexable @override Indexable freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'aBool': aBool.toEJson(), + 'aNullableBool': aNullableBool.toEJson(), + 'anInt': anInt.toEJson(), + 'aNullableInt': aNullableInt.toEJson(), + 'aString': aString.toEJson(), + 'aNullableString': aNullableString.toEJson(), + 'anObjectId': anObjectId.toEJson(), + 'aNullableObjectId': aNullableObjectId.toEJson(), + 'anUuid': anUuid.toEJson(), + 'aNullableUuid': aNullableUuid.toEJson(), + 'aDateTime': aDateTime.toEJson(), + 'aNullableDateTime': aNullableDateTime.toEJson(), + 'aRealmValue': aRealmValue.toEJson(), + 'generalStringIndex': generalStringIndex.toEJson(), + 'ftsStringValue': ftsStringValue.toEJson(), + 'nullableFtsStringValue': nullableFtsStringValue.toEJson(), + }; + } + + static EJsonValue _toEJson(Indexable value) => value.toEJson(); + static Indexable _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'aBool': EJsonValue aBool, + 'aNullableBool': EJsonValue aNullableBool, + 'anInt': EJsonValue anInt, + 'aNullableInt': EJsonValue aNullableInt, + 'aString': EJsonValue aString, + 'aNullableString': EJsonValue aNullableString, + 'anObjectId': EJsonValue anObjectId, + 'aNullableObjectId': EJsonValue aNullableObjectId, + 'anUuid': EJsonValue anUuid, + 'aNullableUuid': EJsonValue aNullableUuid, + 'aDateTime': EJsonValue aDateTime, + 'aNullableDateTime': EJsonValue aNullableDateTime, + 'aRealmValue': EJsonValue aRealmValue, + 'generalStringIndex': EJsonValue generalStringIndex, + 'ftsStringValue': EJsonValue ftsStringValue, + 'nullableFtsStringValue': EJsonValue nullableFtsStringValue, + } => + Indexable( + fromEJson(aBool), + fromEJson(anInt), + fromEJson(aString), + fromEJson(anObjectId), + fromEJson(anUuid), + fromEJson(aDateTime), + fromEJson(generalStringIndex), + fromEJson(ftsStringValue), + aNullableBool: fromEJson(aNullableBool), + aNullableInt: fromEJson(aNullableInt), + aNullableString: fromEJson(aNullableString), + aNullableObjectId: fromEJson(aNullableObjectId), + aNullableUuid: fromEJson(aNullableUuid), + aNullableDateTime: fromEJson(aNullableDateTime), + aRealmValue: fromEJson(aRealmValue), + nullableFtsStringValue: fromEJson(nullableFtsStringValue), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Indexable._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Indexable, 'Indexable', [ SchemaProperty('aBool', RealmPropertyType.bool, indexType: RealmIndexType.regular), @@ -196,5 +259,5 @@ class Indexable extends _Indexable SchemaProperty('nullableFtsStringValue', RealmPropertyType.string, optional: true, indexType: RealmIndexType.fullText), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/list_initialization.expected b/packages/realm_generator/test/good_test_data/list_initialization.expected index 622ff45c2..9edcfccee 100644 --- a/packages/realm_generator/test/good_test_data/list_initialization.expected +++ b/packages/realm_generator/test/good_test_data/list_initialization.expected @@ -33,8 +33,7 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { this, 'initSetWithType', RealmSet(initSetWithType)); RealmObjectBase.set>( this, 'initSetConst', RealmSet(initSetConst)); - RealmObjectBase.set>( - this, 'initMap', RealmMap(initMap)); + RealmObjectBase.set>(this, 'initMap', RealmMap(initMap)); RealmObjectBase.set>( this, 'initMapWithType', RealmMap(initMapWithType)); RealmObjectBase.set>( @@ -101,8 +100,7 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override RealmMap get initMapWithType => - RealmObjectBase.get(this, 'initMapWithType') - as RealmMap; + RealmObjectBase.get(this, 'initMapWithType') as RealmMap; @override set initMapWithType(covariant RealmMap value) => throw RealmUnsupportedSetError(); @@ -121,10 +119,44 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'children': children.toEJson(), + 'initList': initList.toEJson(), + 'initListWithType': initListWithType.toEJson(), + 'initListConst': initListConst.toEJson(), + 'initSet': initSet.toEJson(), + 'initSetWithType': initSetWithType.toEJson(), + 'initSetConst': initSetConst.toEJson(), + 'initMap': initMap.toEJson(), + 'initMapWithType': initMapWithType.toEJson(), + 'initMapConst': initMapConst.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'children': EJsonValue children, + 'initList': EJsonValue initList, + 'initListWithType': EJsonValue initListWithType, + 'initListConst': EJsonValue initListConst, + 'initSet': EJsonValue initSet, + 'initSetWithType': EJsonValue initSetWithType, + 'initSetConst': EJsonValue initSetConst, + 'initMap': EJsonValue initMap, + 'initMapWithType': EJsonValue initMapWithType, + 'initMapConst': EJsonValue initMapConst, + } => + Person(), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('children', RealmPropertyType.object, linkTarget: 'Person', collectionType: RealmCollectionType.list), @@ -147,5 +179,5 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { SchemaProperty('initMapConst', RealmPropertyType.int, collectionType: RealmCollectionType.map), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/map.expected b/packages/realm_generator/test/good_test_data/map.expected index 386c33cc1..ee0bebbe1 100644 --- a/packages/realm_generator/test/good_test_data/map.expected +++ b/packages/realm_generator/test/good_test_data/map.expected @@ -24,16 +24,14 @@ class LotsOfMaps extends _LotsOfMaps }) { RealmObjectBase.set>( this, 'persons', RealmMap(persons)); - RealmObjectBase.set>( - this, 'bools', RealmMap(bools)); + RealmObjectBase.set>(this, 'bools', RealmMap(bools)); RealmObjectBase.set>( this, 'dateTimes', RealmMap(dateTimes)); RealmObjectBase.set>( this, 'decimals', RealmMap(decimals)); RealmObjectBase.set>( this, 'doubles', RealmMap(doubles)); - RealmObjectBase.set>( - this, 'ints', RealmMap(ints)); + RealmObjectBase.set>(this, 'ints', RealmMap(ints)); RealmObjectBase.set>( this, 'objectIds', RealmMap(objectIds)); RealmObjectBase.set>( @@ -42,8 +40,7 @@ class LotsOfMaps extends _LotsOfMaps this, 'strings', RealmMap(strings)); RealmObjectBase.set>( this, 'binary', RealmMap(binary)); - RealmObjectBase.set>( - this, 'uuids', RealmMap(uuids)); + RealmObjectBase.set>(this, 'uuids', RealmMap(uuids)); } LotsOfMaps._(); @@ -59,21 +56,18 @@ class LotsOfMaps extends _LotsOfMaps RealmMap get bools => RealmObjectBase.get(this, 'bools') as RealmMap; @override - set bools(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set bools(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override RealmMap get dateTimes => - RealmObjectBase.get(this, 'dateTimes') - as RealmMap; + RealmObjectBase.get(this, 'dateTimes') as RealmMap; @override set dateTimes(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override RealmMap get decimals => - RealmObjectBase.get(this, 'decimals') - as RealmMap; + RealmObjectBase.get(this, 'decimals') as RealmMap; @override set decimals(covariant RealmMap value) => throw RealmUnsupportedSetError(); @@ -89,21 +83,18 @@ class LotsOfMaps extends _LotsOfMaps RealmMap get ints => RealmObjectBase.get(this, 'ints') as RealmMap; @override - set ints(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set ints(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override RealmMap get objectIds => - RealmObjectBase.get(this, 'objectIds') - as RealmMap; + RealmObjectBase.get(this, 'objectIds') as RealmMap; @override set objectIds(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override RealmMap get any => - RealmObjectBase.get(this, 'any') - as RealmMap; + RealmObjectBase.get(this, 'any') as RealmMap; @override set any(covariant RealmMap value) => throw RealmUnsupportedSetError(); @@ -117,8 +108,7 @@ class LotsOfMaps extends _LotsOfMaps @override RealmMap get binary => - RealmObjectBase.get(this, 'binary') - as RealmMap; + RealmObjectBase.get(this, 'binary') as RealmMap; @override set binary(covariant RealmMap value) => throw RealmUnsupportedSetError(); @@ -127,8 +117,7 @@ class LotsOfMaps extends _LotsOfMaps RealmMap get uuids => RealmObjectBase.get(this, 'uuids') as RealmMap; @override - set uuids(covariant RealmMap value) => - throw RealmUnsupportedSetError(); + set uuids(covariant RealmMap value) => throw RealmUnsupportedSetError(); @override Stream> get changes => @@ -137,14 +126,52 @@ class LotsOfMaps extends _LotsOfMaps @override LotsOfMaps freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'persons': persons.toEJson(), + 'bools': bools.toEJson(), + 'dateTimes': dateTimes.toEJson(), + 'decimals': decimals.toEJson(), + 'doubles': doubles.toEJson(), + 'ints': ints.toEJson(), + 'objectIds': objectIds.toEJson(), + 'any': any.toEJson(), + 'strings': strings.toEJson(), + 'binary': binary.toEJson(), + 'uuids': uuids.toEJson(), + }; + } + + static EJsonValue _toEJson(LotsOfMaps value) => value.toEJson(); + static LotsOfMaps _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'persons': EJsonValue persons, + 'bools': EJsonValue bools, + 'dateTimes': EJsonValue dateTimes, + 'decimals': EJsonValue decimals, + 'doubles': EJsonValue doubles, + 'ints': EJsonValue ints, + 'objectIds': EJsonValue objectIds, + 'any': EJsonValue any, + 'strings': EJsonValue strings, + 'binary': EJsonValue binary, + 'uuids': EJsonValue uuids, + } => + LotsOfMaps(), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(LotsOfMaps._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, LotsOfMaps, 'LotsOfMaps', [ SchemaProperty('persons', RealmPropertyType.object, - optional: true, linkTarget: 'Person', collectionType: RealmCollectionType.map), + optional: true, + linkTarget: 'Person', + collectionType: RealmCollectionType.map), SchemaProperty('bools', RealmPropertyType.bool, collectionType: RealmCollectionType.map), SchemaProperty('dateTimes', RealmPropertyType.timestamp, @@ -166,7 +193,7 @@ class LotsOfMaps extends _LotsOfMaps SchemaProperty('uuids', RealmPropertyType.uuid, collectionType: RealmCollectionType.map), ]); - } + }(); } class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @@ -190,12 +217,30 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + Person( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string), ]); - } + }(); } diff --git a/packages/realm_generator/test/good_test_data/mapto.expected b/packages/realm_generator/test/good_test_data/mapto.expected index 649809162..fa9998f32 100644 --- a/packages/realm_generator/test/good_test_data/mapto.expected +++ b/packages/realm_generator/test/good_test_data/mapto.expected @@ -58,10 +58,33 @@ class Original extends $Original @override Original freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'remapped primitive': primitiveProperty.toEJson(), + 'remapped object': objectProperty.toEJson(), + 'remapped list': listProperty.toEJson(), + }; + } + + static EJsonValue _toEJson(Original value) => value.toEJson(); + static Original _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'remapped primitive': EJsonValue primitiveProperty, + 'remapped object': EJsonValue objectProperty, + 'remapped list': EJsonValue listProperty, + } => + Original( + primitiveProperty: fromEJson(primitiveProperty), + objectProperty: fromEJson(objectProperty), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Original._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, Original, 'another type', [ SchemaProperty('primitiveProperty', RealmPropertyType.int, @@ -73,6 +96,5 @@ class Original extends $Original linkTarget: 'another type', collectionType: RealmCollectionType.list), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/optional_argument.expected b/packages/realm_generator/test/good_test_data/optional_argument.expected index 53c28c92b..f496b59f0 100644 --- a/packages/realm_generator/test/good_test_data/optional_argument.expected +++ b/packages/realm_generator/test/good_test_data/optional_argument.expected @@ -29,14 +29,31 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'spouse': spouse.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'spouse': EJsonValue spouse, + } => + Person( + spouse: fromEJson(spouse), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('spouse', RealmPropertyType.object, optional: true, linkTarget: 'Person'), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/pinhole.expected b/packages/realm_generator/test/good_test_data/pinhole.expected index a69faf50d..83bb19c62 100644 --- a/packages/realm_generator/test/good_test_data/pinhole.expected +++ b/packages/realm_generator/test/good_test_data/pinhole.expected @@ -35,13 +35,30 @@ class Foo extends _Foo with RealmEntity, RealmObjectBase, RealmObject { @override Foo freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'x': x.toEJson(), + }; + } + + static EJsonValue _toEJson(Foo value) => value.toEJson(); + static Foo _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'x': EJsonValue x, + } => + Foo( + x: fromEJson(x), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Foo._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Foo, 'Foo', [ SchemaProperty('x', RealmPropertyType.int), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/primary_key.expected b/packages/realm_generator/test/good_test_data/primary_key.expected index 607a97f41..6b29508a5 100644 --- a/packages/realm_generator/test/good_test_data/primary_key.expected +++ b/packages/realm_generator/test/good_test_data/primary_key.expected @@ -28,14 +28,32 @@ class IntPK extends _IntPK with RealmEntity, RealmObjectBase, RealmObject { @override IntPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(IntPK value) => value.toEJson(); + static IntPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + IntPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(IntPK._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, IntPK, 'IntPK', [ SchemaProperty('id', RealmPropertyType.int, primaryKey: true), ]); - } + }(); } class NullableIntPK extends _NullableIntPK @@ -60,19 +78,36 @@ class NullableIntPK extends _NullableIntPK @override NullableIntPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableIntPK value) => value.toEJson(); + static NullableIntPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableIntPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableIntPK._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, NullableIntPK, 'NullableIntPK', [ SchemaProperty('id', RealmPropertyType.int, optional: true, primaryKey: true), ]); - } + }(); } - class StringPK extends _StringPK with RealmEntity, RealmObjectBase, RealmObject { StringPK( @@ -95,14 +130,32 @@ class StringPK extends _StringPK @override StringPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(StringPK value) => value.toEJson(); + static StringPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + StringPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(StringPK._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, StringPK, 'StringPK', [ SchemaProperty('id', RealmPropertyType.string, primaryKey: true), ]); - } + }(); } class NullableStringPK extends _NullableStringPK @@ -128,16 +181,34 @@ class NullableStringPK extends _NullableStringPK NullableStringPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableStringPK value) => value.toEJson(); + static NullableStringPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableStringPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableStringPK._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, NullableStringPK, 'NullableStringPK', [ SchemaProperty('id', RealmPropertyType.string, optional: true, primaryKey: true), ]); - } + }(); } class ObjectIdPK extends _ObjectIdPK @@ -162,14 +233,33 @@ class ObjectIdPK extends _ObjectIdPK @override ObjectIdPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(ObjectIdPK value) => value.toEJson(); + static ObjectIdPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + ObjectIdPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(ObjectIdPK._); - return const SchemaObject(ObjectType.realmObject, ObjectIdPK, 'ObjectIdPK', [ + register(_toEJson, _fromEJson); + return const SchemaObject( + ObjectType.realmObject, ObjectIdPK, 'ObjectIdPK', [ SchemaProperty('id', RealmPropertyType.objectid, primaryKey: true), ]); - } + }(); } class NullableObjectIdPK extends _NullableObjectIdPK @@ -195,16 +285,34 @@ class NullableObjectIdPK extends _NullableObjectIdPK NullableObjectIdPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableObjectIdPK value) => value.toEJson(); + static NullableObjectIdPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableObjectIdPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableObjectIdPK._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, NullableObjectIdPK, 'NullableObjectIdPK', [ SchemaProperty('id', RealmPropertyType.objectid, optional: true, primaryKey: true), ]); - } + }(); } class UuidPK extends _UuidPK with RealmEntity, RealmObjectBase, RealmObject { @@ -228,14 +336,32 @@ class UuidPK extends _UuidPK with RealmEntity, RealmObjectBase, RealmObject { @override UuidPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(UuidPK value) => value.toEJson(); + static UuidPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + UuidPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(UuidPK._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, UuidPK, 'UuidPK', [ SchemaProperty('id', RealmPropertyType.uuid, primaryKey: true), ]); - } + }(); } class NullableUuidPK extends _NullableUuidPK @@ -260,15 +386,32 @@ class NullableUuidPK extends _NullableUuidPK @override NullableUuidPK freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'id': id.toEJson(), + }; + } + + static EJsonValue _toEJson(NullableUuidPK value) => value.toEJson(); + static NullableUuidPK _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'id': EJsonValue id, + } => + NullableUuidPK( + fromEJson(id), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(NullableUuidPK._); + register(_toEJson, _fromEJson); return const SchemaObject( ObjectType.realmObject, NullableUuidPK, 'NullableUuidPK', [ SchemaProperty('id', RealmPropertyType.uuid, optional: true, primaryKey: true), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/realm_set.expected b/packages/realm_generator/test/good_test_data/realm_set.expected index 5dcb6c94b..f387b3bb5 100644 --- a/packages/realm_generator/test/good_test_data/realm_set.expected +++ b/packages/realm_generator/test/good_test_data/realm_set.expected @@ -28,14 +28,32 @@ class Car extends _Car with RealmEntity, RealmObjectBase, RealmObject { @override Car freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'make': make.toEJson(), + }; + } + + static EJsonValue _toEJson(Car value) => value.toEJson(); + static Car _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'make': EJsonValue make, + } => + Car( + fromEJson(make), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Car._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Car, 'Car', [ SchemaProperty('make', RealmPropertyType.string, primaryKey: true), ]); - } + }(); } class RealmSets extends _RealmSets @@ -223,10 +241,60 @@ class RealmSets extends _RealmSets @override RealmSets freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'key': key.toEJson(), + 'boolSet': boolSet.toEJson(), + 'nullableBoolSet': nullableBoolSet.toEJson(), + 'intSet': intSet.toEJson(), + 'nullableintSet': nullableintSet.toEJson(), + 'stringSet': stringSet.toEJson(), + 'nullablestringSet': nullablestringSet.toEJson(), + 'doubleSet': doubleSet.toEJson(), + 'nullabledoubleSet': nullabledoubleSet.toEJson(), + 'dateTimeSet': dateTimeSet.toEJson(), + 'nullabledateTimeSet': nullabledateTimeSet.toEJson(), + 'objectIdSet': objectIdSet.toEJson(), + 'nullableobjectIdSet': nullableobjectIdSet.toEJson(), + 'uuidSet': uuidSet.toEJson(), + 'nullableuuidSet': nullableuuidSet.toEJson(), + 'realmValueSet': realmValueSet.toEJson(), + 'realmObjectsSet': realmObjectsSet.toEJson(), + }; + } + + static EJsonValue _toEJson(RealmSets value) => value.toEJson(); + static RealmSets _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'key': EJsonValue key, + 'boolSet': EJsonValue boolSet, + 'nullableBoolSet': EJsonValue nullableBoolSet, + 'intSet': EJsonValue intSet, + 'nullableintSet': EJsonValue nullableintSet, + 'stringSet': EJsonValue stringSet, + 'nullablestringSet': EJsonValue nullablestringSet, + 'doubleSet': EJsonValue doubleSet, + 'nullabledoubleSet': EJsonValue nullabledoubleSet, + 'dateTimeSet': EJsonValue dateTimeSet, + 'nullabledateTimeSet': EJsonValue nullabledateTimeSet, + 'objectIdSet': EJsonValue objectIdSet, + 'nullableobjectIdSet': EJsonValue nullableobjectIdSet, + 'uuidSet': EJsonValue uuidSet, + 'nullableuuidSet': EJsonValue nullableuuidSet, + 'realmValueSet': EJsonValue realmValueSet, + 'realmObjectsSet': EJsonValue realmObjectsSet, + } => + RealmSets( + fromEJson(key), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(RealmSets._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, RealmSets, 'RealmSets', [ SchemaProperty('key', RealmPropertyType.int, primaryKey: true), SchemaProperty('boolSet', RealmPropertyType.bool, @@ -262,5 +330,5 @@ class RealmSets extends _RealmSets SchemaProperty('realmObjectsSet', RealmPropertyType.object, linkTarget: 'Car', collectionType: RealmCollectionType.set), ]); - } -} \ No newline at end of file + }(); +} diff --git a/packages/realm_generator/test/good_test_data/required_argument.expected b/packages/realm_generator/test/good_test_data/required_argument.expected index d17468e22..7849d093e 100644 --- a/packages/realm_generator/test/good_test_data/required_argument.expected +++ b/packages/realm_generator/test/good_test_data/required_argument.expected @@ -28,13 +28,30 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + Person( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string, primaryKey: true), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/required_argument_with_default_value.expected b/packages/realm_generator/test/good_test_data/required_argument_with_default_value.expected index e1d4a5e25..dde6c5c1c 100644 --- a/packages/realm_generator/test/good_test_data/required_argument_with_default_value.expected +++ b/packages/realm_generator/test/good_test_data/required_argument_with_default_value.expected @@ -35,13 +35,30 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'age': age.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'age': EJsonValue age, + } => + Person( + age: fromEJson(age), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('age', RealmPropertyType.int), ]); - } + }(); } - diff --git a/packages/realm_generator/test/good_test_data/user_defined_getter.expected b/packages/realm_generator/test/good_test_data/user_defined_getter.expected index d29f0ae58..9aab3d61b 100644 --- a/packages/realm_generator/test/good_test_data/user_defined_getter.expected +++ b/packages/realm_generator/test/good_test_data/user_defined_getter.expected @@ -28,13 +28,30 @@ class Person extends _Person with RealmEntity, RealmObjectBase, RealmObject { @override Person freeze() => RealmObjectBase.freezeObject(this); - static SchemaObject get schema => _schema ??= _initSchema(); - static SchemaObject? _schema; - static SchemaObject _initSchema() { + EJsonValue toEJson() { + return { + 'name': name.toEJson(), + }; + } + + static EJsonValue _toEJson(Person value) => value.toEJson(); + static Person _fromEJson(EJsonValue ejson) { + return switch (ejson) { + { + 'name': EJsonValue name, + } => + Person( + fromEJson(name), + ), + _ => raiseInvalidEJson(ejson), + }; + } + + static final schema = () { RealmObjectBase.registerFactory(Person._); + register(_toEJson, _fromEJson); return const SchemaObject(ObjectType.realmObject, Person, 'Person', [ SchemaProperty('name', RealmPropertyType.string), ]); - } + }(); } - diff --git a/packages/realm_generator/test/info_test.dart b/packages/realm_generator/test/info_test.dart index dab0cb1e7..3c85f3146 100644 --- a/packages/realm_generator/test/info_test.dart +++ b/packages/realm_generator/test/info_test.dart @@ -1,4 +1,3 @@ -import 'dart:async'; import 'dart:io'; import 'package:term_glyph/term_glyph.dart'; diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 000000000..23e781959 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,7 @@ +name: my_project_workspace + +environment: + sdk: '>=3.0.0 <4.0.0' +dev_dependencies: + melos: ^4.1.0 +