├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── analysis_options.yaml ├── pubspec.yaml ├── sqflite ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── analysis_options.yaml ├── android │ ├── .gitignore │ ├── build.gradle │ ├── gradle.properties │ ├── settings.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ └── java │ │ └── com │ │ └── davidmartos96 │ │ └── sqflite_sqlcipher │ │ ├── Constant.java │ │ ├── Database.java │ │ ├── LogLevel.java │ │ ├── SqfliteSqlCipherPlugin.java │ │ ├── SqlCommand.java │ │ ├── dev │ │ └── Debug.java │ │ └── operation │ │ ├── BaseOperation.java │ │ ├── BaseReadOperation.java │ │ ├── BatchOperation.java │ │ ├── ExecuteOperation.java │ │ ├── MethodCallOperation.java │ │ ├── Operation.java │ │ ├── OperationResult.java │ │ └── SqlErrorInfo.java ├── example │ ├── .gitignore │ ├── README.md │ ├── analysis_options.yaml │ ├── android │ │ ├── .gitignore │ │ ├── app │ │ │ ├── build.gradle │ │ │ ├── proguard-rules.pro │ │ │ └── src │ │ │ │ ├── debug │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── main │ │ │ │ ├── AndroidManifest.xml │ │ │ │ ├── kotlin │ │ │ │ │ └── com │ │ │ │ │ │ └── davidmartos96 │ │ │ │ │ │ └── example │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ └── res │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── values-night │ │ │ │ │ └── styles.xml │ │ │ │ │ └── values │ │ │ │ │ └── styles.xml │ │ │ │ └── profile │ │ │ │ └── AndroidManifest.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ └── settings.gradle │ ├── assets │ │ ├── example.db │ │ ├── example_pass_1234.db │ │ ├── issue_64.db │ │ └── sqlcipher-3.0-testkey.db │ ├── ios │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── AppFrameworkInfo.plist │ │ │ ├── Debug.xcconfig │ │ │ └── Release.xcconfig │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ │ ├── AppIcon.appiconset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ └── Icon-App-83.5x83.5@2x.png │ │ │ │ └── LaunchImage.imageset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ └── README.md │ │ │ ├── Base.lproj │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ └── Runner-Bridging-Header.h │ │ └── RunnerTests │ │ │ └── RunnerTests.swift │ ├── lib │ │ ├── batch_test_page.dart │ │ ├── database │ │ │ └── database.dart │ │ ├── deprecated_test_page.dart │ │ ├── exception_test_page.dart │ │ ├── exp_test_page.dart │ │ ├── main.dart │ │ ├── manual_test_page.dart │ │ ├── model │ │ │ ├── item.dart │ │ │ ├── main_item.dart │ │ │ └── test.dart │ │ ├── open_test_page.dart │ │ ├── raw_test_page.dart │ │ ├── slow_test_page.dart │ │ ├── sqlcipher_test_page.dart │ │ ├── src │ │ │ ├── common_import.dart │ │ │ ├── dev_utils.dart │ │ │ ├── expect.dart │ │ │ ├── item_widget.dart │ │ │ └── main_item_widget.dart │ │ ├── test_page.dart │ │ ├── todo_test_page.dart │ │ ├── type_test_page.dart │ │ └── utils.dart │ ├── macos │ │ ├── .gitignore │ │ ├── Flutter │ │ │ ├── Flutter-Debug.xcconfig │ │ │ ├── Flutter-Release.xcconfig │ │ │ └── GeneratedPluginRegistrant.swift │ │ ├── Runner.xcodeproj │ │ │ ├── project.pbxproj │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Contents.json │ │ │ │ │ ├── app_icon_1024.png │ │ │ │ │ ├── app_icon_128.png │ │ │ │ │ ├── app_icon_16.png │ │ │ │ │ ├── app_icon_256.png │ │ │ │ │ ├── app_icon_32.png │ │ │ │ │ ├── app_icon_512.png │ │ │ │ │ └── app_icon_64.png │ │ │ ├── Base.lproj │ │ │ │ └── MainMenu.xib │ │ │ ├── Configs │ │ │ │ ├── AppInfo.xcconfig │ │ │ │ ├── Debug.xcconfig │ │ │ │ ├── Release.xcconfig │ │ │ │ └── Warnings.xcconfig │ │ │ ├── DebugProfile.entitlements │ │ │ ├── Info.plist │ │ │ ├── MainFlutterWindow.swift │ │ │ └── Release.entitlements │ │ └── RunnerTests │ │ │ └── RunnerTests.swift │ ├── pubspec.yaml │ ├── test │ │ ├── database_test.dart │ │ ├── main │ │ │ └── test_main.dart │ │ ├── model_test.dart │ │ └── sqflite_e2e.dart │ ├── test_driver │ │ ├── main.dart │ │ ├── main_test.dart │ │ ├── sqflite_e2e.dart │ │ ├── sqflite_e2e_test.dart │ │ ├── sqflite_impl_test.dart │ │ └── sqflite_test.dart │ └── tool │ │ ├── android_sqflite_logcat.dart │ │ ├── android_uninstall.dart │ │ ├── run_e2e_test.dart │ │ ├── run_flutter_driver_test.dart │ │ └── travis.dart ├── ios │ ├── .gitignore │ ├── Assets │ │ └── .gitkeep │ ├── Classes │ │ ├── SqfliteSqlCipherOperation.h │ │ ├── SqfliteSqlCipherOperation.m │ │ ├── SqfliteSqlCipherPlugin.h │ │ └── SqfliteSqlCipherPlugin.m │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ └── sqflite_sqlcipher.podspec ├── lib │ ├── sqflite.dart │ ├── sql.dart │ ├── sqlite_api.dart │ └── src │ │ ├── database_sql_cipher_impl.dart │ │ ├── factory_sql_cipher_impl.dart │ │ ├── sqflite_import.dart │ │ ├── sqflite_sql_cipher_impl.dart │ │ ├── sql_cipher_constant.dart │ │ └── sql_cipher_open_options.dart ├── macos │ ├── Classes │ │ ├── SqfliteSqlCipherOperation.h │ │ ├── SqfliteSqlCipherOperation.m │ │ ├── SqfliteSqlCipherPlugin.h │ │ └── SqfliteSqlCipherPlugin.m │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ └── sqflite_sqlcipher.podspec ├── pubspec.yaml └── test │ └── sqflite_sql_cipher_open_test.dart └── tool ├── copy_macos_code_to_ios.dart ├── run_test.dart ├── tag.dart └── travis.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://www.dartlang.org/guides/libraries/private-files 2 | 3 | # Files and directories created by pub 4 | .dart_tool/ 5 | .packages 6 | .pub/ 7 | build/ 8 | # If you're building an application, you may want to check-in your pubspec.lock 9 | pubspec.lock 10 | 11 | # Directory created by dartdoc 12 | /doc/api/ 13 | 14 | # flutter root folder wrongly created 15 | /ios 16 | /android 17 | .symlinks 18 | 19 | # IDE 20 | .idea/ 21 | *.iml 22 | .vscode/ 23 | /sqflite/example/.flutter-plugins-dependencies 24 | 25 | # Copied from flutter plugins 26 | .DS_Store 27 | .atom/ 28 | flutter_export_environment.sh 29 | 30 | Podfile 31 | Podfile.lock 32 | Pods/ 33 | .symlinks/ 34 | **/Flutter/App.framework/ 35 | **/Flutter/Flutter.framework/ 36 | **/Flutter/Generated.xcconfig 37 | **/Flutter/flutter_assets/ 38 | ServiceDefinitions.json 39 | xcuserdata/ 40 | *.xcworkspace 41 | **/DerivedData/ 42 | 43 | local.properties 44 | keystore.properties 45 | .gradle/ 46 | gradlew 47 | gradlew.bat 48 | gradle-wrapper.jar 49 | .flutter-plugins-dependencies 50 | 51 | GeneratedPluginRegistrant.h 52 | GeneratedPluginRegistrant.m 53 | GeneratedPluginRegistrant.java 54 | .flutter-plugins 55 | 56 | .project 57 | .classpath 58 | .settings -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: dart 2 | sudo: required 3 | dist: trusty 4 | dart: 5 | - stable 6 | - dev 7 | before_script: 8 | - pub run tekartik_travis_ci_flutter:install 9 | - source $(pub run tekartik_travis_ci_flutter:env) 10 | script: 11 | - dart tool/travis.dart 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2019, Tekartik 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sqflite_sqlcipher 2 | 3 | #### Package description and instructions: [Here](https://github.com/davidmartos96/sqflite_sqlcipher/blob/master/sqflite/README.md) -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | analyzer: 7 | strong-mode: 8 | implicit-casts: false 9 | 10 | errors: 11 | # treat missing required parameters as a warning (not a hint) 12 | missing_required_param: warning 13 | # treat missing returns as a warning (not a hint) 14 | missing_return: warning 15 | # allow having TODOs in the code 16 | todo: ignore 17 | # Ignore errors like 18 | # 'super_goes_last' is a deprecated lint rule and should not be used • included_file_warning 19 | included_file_warning: ignore 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: sqflite_sqlcipher_repo 2 | description: Sqflite SqlCipher repo 3 | version: 0.1.0 4 | homepage: https://github.com/davidmartos96/sqflite_sqlcipher 5 | publish_to: none 6 | 7 | environment: 8 | sdk: '>=2.4.0-dev <3.0.0' 9 | 10 | dev_dependencies: 11 | pedantic: '>=1.4.0 <3.0.0' 12 | tekartik_travis_ci_flutter: 13 | git: 14 | url: git://github.com/tekartik/travis_ci_flutter.dart 15 | ref: dart2 16 | version: '>=0.1.0' 17 | process_run: '>=0.10.6' 18 | 19 | dependency_overrides: 20 | pedantic: '>=1.9.0 <3.0.0' 21 | -------------------------------------------------------------------------------- /sqflite/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .packages 3 | .pub/ 4 | ios/.generated/ 5 | packages 6 | pubspec.lock 7 | 8 | # Directory created by dartdoc 9 | doc/api/ 10 | 11 | # Local folder 12 | .local/ 13 | 14 | # local flutter install (travis) 15 | flutter 16 | 17 | # Conventional directory for build outputs 18 | build/ 19 | coverage/ 20 | 21 | # flutter 22 | .metadata -------------------------------------------------------------------------------- /sqflite/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 3.1.0 2 | * Update SQLCipher version to [4.5.7](https://www.zetetic.net/blog/2024/04/24/sqlcipher-4.5.7-release/) 3 | 4 | ## 3.0.0 5 | * Update SQLCipher version to [4.5.6](https://www.zetetic.net/blog/2024/01/17/sqlcipher-4.5.6-release/) 6 | * Android minimum required SDK 21 and use `compileSdk` 34. 7 | * Ensure the provided password is valid when opening the database. This now makes it possible to differentiate between failing to cipher_migrate and opening a database with the wrong password. 8 | * On iOS/macOS, if you have sqflite as a transitive dependency with version 2.3.2 or greater, the `fmdb_override` workaround in the `dependency_overrides` is not needed anymore. 9 | * Add iOS/MacOS privacy manifest 10 | * Dart >= 3.3.0 11 | 12 | ## 2.2.1 13 | * Update minimum deployment targets for iOS (11.0) and macOS (10.13) to use SQLCipher 4.5.4 14 | 15 | ## 2.2.0 16 | * SQLCipher version 4.5.4 17 | 18 | ## 2.1.1 19 | * SQLCipher version 4.5.0 20 | * Update Android build version 21 | * Update example project 22 | 23 | ## 2.1.0 24 | * Remove references to deprecated android plugin embedding v1 25 | 26 | ## 2.0.0 27 | * Stable version with NNBD support 28 | 29 | ## 2.0.0-nullsafety.0 30 | * NNBD support 31 | 32 | ## 1.1.4 33 | 34 | * Update names in ios native implementation to avoid conflicts with the `sqflite` package 35 | 36 | ## 1.1.3 37 | 38 | * Update SQLCipher version to [4.4.2](https://www.zetetic.net/blog/2020/11/25/sqlcipher-442-release/) 39 | 40 | ## 1.1.2 41 | 42 | * Update SQLCipher version to [4.4.1](https://www.zetetic.net/blog/2020/11/06/sqlcipher-441-release/) 43 | * Fix Handler constructor deprecation 44 | 45 | ## 1.1.1 46 | 47 | * Remove unnecessary logs 48 | 49 | ## 1.1.0+1 50 | 51 | * Update SQLCipher version to [4.4.0](https://www.zetetic.net/blog/2020/05/12/sqlcipher-440-release/) 52 | 53 | ## 1.0.0+6 54 | 55 | * Initial package release, using `sqflite_common` as a dependency under the hood. 56 | -------------------------------------------------------------------------------- /sqflite/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Alexandre Roux Tekartik. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /sqflite/README.md: -------------------------------------------------------------------------------- 1 | # sqflite_sqlcipher 2 | 3 | [![pub package](https://img.shields.io/pub/v/sqflite_sqlcipher.svg)](https://pub.dev/packages/sqflite_sqlcipher) 4 | 5 | This is a fork from the plugin [sqflite](https://github.com/tekartik/sqflite). 6 | 7 | **[sqflite_common version 1.0.0](https://pub.dev/packages/sqflite_common)** 8 | 9 | This fork makes use of the Dart package `sqflite_common` but with a native implementation which uses the SqlCipher library on both iOS and Android. The API is the same as the `sqflite` plugin, only that the `openDatabase` method includes an optional parameter `password`. 10 | 11 | The SQLCipher version of the plugin is 4.x If you try to open a database encrypted with a lower version of SQLCipher, the plugin will try to migrate it to a new version using the operation `PRAGMA cipher_migrate` (This automatic migration to version 4 is only done in Android. PR welcome for this feature in iOS). 12 | 13 | ### Install and use 14 | 15 | To add it in your project include this in the `pubspec.yml`. 16 | ``` 17 | dependencies: 18 | sqflite_sqlcipher: {latest version} 19 | ``` 20 | 21 | ```dart 22 | import 'package:sqflite_sqlcipher/sqflite.dart'; 23 | 24 | Database db = await openDatabase( 25 | path, 26 | password: "my password", 27 | // onCreate, onUpgrade... 28 | ); 29 | ``` 30 | 31 | ### Android 32 | **REQUIRED:** Flutter now enables code shrinking by default when building an APK in release mode, so you need to add the following ProGuard rules to the file `android/app/proguard-rules.pro`. If it does not exist, create it: 33 | 34 | ``` 35 | -keep class net.sqlcipher.** { *; } 36 | ``` 37 | 38 | ### If using `sqflite` version < 2.3.2 as direct or transitive dependency 39 | 40 | If you use sqflite v2.3.2 or greater you can ignore this, because it doesn't use the `FMDB` pod anymore. 41 | 42 | If any of your project's dependencies uses sqflite (e.g: cached_network_image, flutter_cache_manager...), then for iOS to link correctly the SQLCipher libraries you need to override it in your `pubspec.yaml` file: 43 | 44 | ```yaml 45 | dependency_overrides: 46 | sqflite: 47 | git: 48 | url: https://www.github.com/davidmartos96/sqflite_sqlcipher.git 49 | path: sqflite 50 | ref: fmdb_override 51 | ``` 52 | 53 | The reason for this is that in iOS, the `FMDB` and `FMDB/SQLCipher` pods cannot be used at the same time. The override only changes that reference. The rest is the full `sqflite` package. 54 | If anyone knows about a better way to handle this, PRs are welcome :D 55 | 56 | 57 | --- 58 | 59 | ## Sqflite documentation 60 | 61 | * [Documentation](https://github.com/tekartik/sqflite/blob/master/sqflite/README.md) 62 | -------------------------------------------------------------------------------- /sqflite/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:lints/recommended.yaml 5 | 6 | analyzer: 7 | strong-mode: 8 | implicit-casts: false 9 | # implicit-dynamic: false 10 | 11 | errors: 12 | # treat missing required parameters as a warning (not a hint) 13 | missing_required_param: warning 14 | # treat missing returns as a warning (not a hint) 15 | missing_return: warning 16 | # allow having TODOs in the code 17 | todo: ignore 18 | # Ignore errors like 19 | # 'super_goes_last' is a deprecated lint rule and should not be used • included_file_warning 20 | included_file_warning: ignore 21 | 22 | linter: 23 | rules: 24 | # these rules are documented on and in the same order as 25 | # the Dart Lint rules page to make maintenance easier 26 | # http://dart-lang.github.io/linter/lints/ 27 | 28 | # === error rules === 29 | - avoid_empty_else 30 | - avoid_slow_async_io 31 | - cancel_subscriptions 32 | # - close_sinks # https://github.com/flutter/flutter/issues/5789 33 | # - comment_references # blocked on https://github.com/dart-lang/dartdoc/issues/1153 34 | - control_flow_in_finally 35 | - empty_statements 36 | - hash_and_equals 37 | # - invariant_booleans # https://github.com/flutter/flutter/issues/5790 38 | # - literal_only_boolean_expressions # https://github.com/flutter/flutter/issues/5791 39 | - no_adjacent_strings_in_list 40 | - no_duplicate_case_values 41 | - test_types_in_equals 42 | - throw_in_finally 43 | - unrelated_type_equality_checks 44 | - valid_regexps 45 | 46 | # === style rules === 47 | - always_declare_return_types 48 | # - always_put_control_body_on_new_line 49 | # - always_specify_types 50 | - annotate_overrides 51 | # - avoid_annotating_with_dynamic # not yet tested 52 | # - avoid_as # 2019-01-30 removed for no-implicit-casts 53 | # - avoid_catches_without_on_clauses # not yet tested 54 | # - avoid_catching_errors # not yet tested 55 | # - avoid_classes_with_only_static_members # not yet tested 56 | # - avoid_function_literals_in_foreach_calls # not yet tested 57 | - avoid_init_to_null 58 | - avoid_null_checks_in_equality_operators 59 | # - avoid_positional_boolean_parameters # not yet tested 60 | - avoid_return_types_on_setters 61 | # - avoid_returning_null # not yet tested 62 | # - avoid_returning_this # not yet tested 63 | # - avoid_setters_without_getters # not yet tested 64 | # - avoid_types_on_closure_parameters # not yet tested 65 | - await_only_futures 66 | - camel_case_types 67 | # - cascade_invocations # not yet tested 68 | # - constant_identifier_names # https://github.com/dart-lang/linter/issues/204 69 | - directives_ordering 70 | - empty_catches 71 | - empty_constructor_bodies 72 | - implementation_imports 73 | # - join_return_with_assignment # not yet tested 74 | - library_names 75 | - library_prefixes 76 | - non_constant_identifier_names 77 | # - omit_local_variable_types # opposite of always_specify_types 78 | # - one_member_abstracts # too many false positives 79 | # - only_throw_errors # https://github.com/flutter/flutter/issues/5792 80 | - overridden_fields 81 | - package_api_docs 82 | - package_prefixed_library_names 83 | # - parameter_assignments # we do this commonly 84 | - prefer_adjacent_string_concatenation 85 | - prefer_collection_literals 86 | # - prefer_conditional_assignment # not yet tested 87 | - prefer_const_constructors 88 | # - prefer_constructors_over_static_methods # not yet tested 89 | - prefer_contains 90 | # - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods 91 | # - prefer_final_fields # https://github.com/dart-lang/linter/issues/506 92 | - prefer_final_locals 93 | # - prefer_foreach # not yet tested 94 | # - prefer_function_declarations_over_variables # not yet tested 95 | - prefer_initializing_formals 96 | # - prefer_interpolation_to_compose_strings # not yet tested 97 | - prefer_is_empty 98 | - prefer_is_not_empty 99 | - prefer_void_to_null 100 | # - recursive_getters # https://github.com/dart-lang/linter/issues/452 101 | - slash_for_doc_comments 102 | - sort_constructors_first 103 | - sort_unnamed_constructors_first 104 | # - super_goes_last 105 | # - type_annotate_public_apis # subset of always_specify_types 106 | - type_init_formals 107 | # - unawaited_futures # https://github.com/flutter/flutter/issues/5793 108 | - unnecessary_brace_in_string_interps 109 | - unnecessary_const 110 | - unnecessary_getters_setters 111 | # - unnecessary_lambdas # https://github.com/dart-lang/linter/issues/498 112 | - unnecessary_new 113 | - unnecessary_null_aware_assignments 114 | - unnecessary_null_in_if_null_operators 115 | # - unnecessary_overrides # https://github.com/dart-lang/linter/issues/626 and https://github.com/dart-lang/linter/issues/627 116 | - unnecessary_statements 117 | - unnecessary_this 118 | - use_rethrow_when_possible 119 | # - use_setters_to_change_properties # not yet tested 120 | # - use_string_buffers # https://github.com/dart-lang/linter/pull/664 121 | # - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review 122 | 123 | # === pub rules === 124 | - package_names 125 | 126 | # === doc rules === 127 | - public_member_api_docs 128 | -------------------------------------------------------------------------------- /sqflite/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | 10 | /gradle 11 | /gradlew 12 | /gradlew.bat 13 | -------------------------------------------------------------------------------- /sqflite/android/build.gradle: -------------------------------------------------------------------------------- 1 | group 'com.davidmartos96.sqflite_sqlcipher' 2 | version '1.0-SNAPSHOT' 3 | 4 | buildscript { 5 | repositories { 6 | google() 7 | mavenCentral() 8 | } 9 | 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:8.3.0' 12 | } 13 | } 14 | 15 | rootProject.allprojects { 16 | repositories { 17 | google() 18 | mavenCentral() 19 | } 20 | } 21 | 22 | apply plugin: 'com.android.library' 23 | 24 | android { 25 | compileSdk 34 26 | 27 | namespace 'com.davidmartos96.sqflite_sqlcipher' 28 | 29 | compileOptions { 30 | sourceCompatibility JavaVersion.VERSION_17 31 | targetCompatibility JavaVersion.VERSION_17 32 | } 33 | 34 | defaultConfig { 35 | minSdk 21 36 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 37 | } 38 | lintOptions { 39 | disable 'InvalidPackage' 40 | } 41 | } 42 | 43 | dependencies { 44 | implementation 'net.zetetic:sqlcipher-android:4.5.7@aar' 45 | 46 | // We need to use a version compatible with sqlcipher. See here: 47 | // https://github.com/sqlcipher/sqlcipher-android/blob/c5bd0cf2a2d26cd977d6127180f594750675093e/build.gradle#L34 48 | implementation 'androidx.sqlite:sqlite:2.3.1' 49 | } 50 | -------------------------------------------------------------------------------- /sqflite/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | -------------------------------------------------------------------------------- /sqflite/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'sqflite_sqlcipher' 2 | -------------------------------------------------------------------------------- /sqflite/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/Constant.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher; 2 | 3 | /** 4 | * Constants between dart & Java world 5 | */ 6 | 7 | public class Constant { 8 | 9 | // Can be used as the name MethodChannel or to register with 10 | static final public String PLUGIN_KEY = "com.davidmartos96.sqflite_sqlcipher"; 11 | 12 | static final public String METHOD_GET_PLATFORM_VERSION = "getPlatformVersion"; 13 | static final public String METHOD_GET_DATABASES_PATH = "getDatabasesPath"; 14 | static final public String METHOD_DEBUG = "debug"; 15 | static final public String METHOD_OPTIONS = "options"; 16 | static final public String METHOD_OPEN_DATABASE = "openDatabase"; 17 | static final public String METHOD_CLOSE_DATABASE = "closeDatabase"; 18 | static final public String METHOD_INSERT = "insert"; 19 | static final public String METHOD_EXECUTE = "execute"; 20 | static final public String METHOD_QUERY = "query"; 21 | static final public String METHOD_UPDATE = "update"; 22 | static final public String METHOD_BATCH = "batch"; 23 | static final public String METHOD_DELETE_DATABASE = "deleteDatabase"; 24 | 25 | static final String PARAM_ID = "id"; 26 | static final String PARAM_PATH = "path"; 27 | // when opening a database 28 | static final String PARAM_READ_ONLY = "readOnly"; // boolean 29 | static final String PARAM_PASSWORD = "password"; // optional String 30 | static final String PARAM_SINGLE_INSTANCE = "singleInstance"; // boolean 31 | static final String PARAM_LOG_LEVEL = "logLevel"; // int 32 | // true when entering, false when leaving, null otherwise 33 | public static final String PARAM_IN_TRANSACTION = "inTransaction"; 34 | // Result when opening a database 35 | public static final String PARAM_RECOVERED = "recovered"; 36 | // Result when opening a database 37 | public static final String PARAM_RECOVERED_IN_TRANSACTION = "recoveredInTransaction"; 38 | 39 | static final String PARAM_QUERY_AS_MAP_LIST = "queryAsMapList"; // boolean 40 | static final String PARAM_THREAD_PRIORITY = "androidThreadPriority"; // int 41 | 42 | public static final String PARAM_SQL = "sql"; 43 | public static final String PARAM_SQL_ARGUMENTS = "arguments"; 44 | public static final String PARAM_NO_RESULT = "noResult"; 45 | public static final String PARAM_CONTINUE_OR_ERROR = "continueOnError"; 46 | 47 | // debugMode 48 | static final String PARAM_CMD = "cmd"; // debugMode cmd: get/set 49 | static final String CMD_GET = "get"; 50 | 51 | // in batch 52 | static final String PARAM_OPERATIONS = "operations"; 53 | // in each operation 54 | public static final String PARAM_METHOD = "method"; 55 | 56 | // Batch operation results 57 | public static final String PARAM_RESULT = "result"; 58 | public static final String PARAM_ERROR = "error"; // map with code/message/data 59 | public static final String PARAM_ERROR_CODE = "code"; 60 | public static final String PARAM_ERROR_MESSAGE = "message"; 61 | public static final String PARAM_ERROR_DATA = "data"; 62 | 63 | static final String SQLITE_ERROR = "sqlite_error"; // code 64 | static final String ERROR_BAD_PARAM = "bad_param"; // internal only 65 | static final String ERROR_OPEN_FAILED = "open_failed"; // msg 66 | static final String ERROR_DATABASE_CLOSED = "database_closed"; // msg 67 | 68 | // memory database path 69 | static final String MEMORY_DATABASE_PATH = ":memory:"; 70 | 71 | // android log tag 72 | static final public String TAG = "Sqflite"; 73 | 74 | // Obsolete since 1.17 75 | static final public String METHOD_DEBUG_MODE = "debugMode"; 76 | } 77 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/Database.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher; 2 | 3 | import android.util.Log; 4 | 5 | 6 | import java.io.File; 7 | 8 | import static com.davidmartos96.sqflite_sqlcipher.Constant.TAG; 9 | 10 | import net.zetetic.database.DatabaseErrorHandler; 11 | import net.zetetic.database.sqlcipher.SQLiteConnection; 12 | import net.zetetic.database.sqlcipher.SQLiteDatabase; 13 | import net.zetetic.database.sqlcipher.SQLiteDatabaseHook; 14 | 15 | class Database { 16 | final boolean singleInstance; 17 | final String path; 18 | final String password; 19 | final int id; 20 | final int logLevel; 21 | SQLiteDatabase sqliteDatabase; 22 | boolean inTransaction; 23 | 24 | 25 | Database(String path, String password, int id, boolean singleInstance, int logLevel) { 26 | this.path = path; 27 | this.password = (password != null) ? password : ""; 28 | 29 | this.singleInstance = singleInstance; 30 | this.id = id; 31 | this.logLevel = logLevel; 32 | } 33 | 34 | public void open() { 35 | openWithFlags(SQLiteDatabase.CREATE_IF_NECESSARY); 36 | 37 | } 38 | 39 | // Change default error handler to avoid erasing the existing file. 40 | public void openReadOnly() { 41 | openWithFlags(SQLiteDatabase.OPEN_READONLY, new DatabaseErrorHandler() { 42 | @Override 43 | public void onCorruption(SQLiteDatabase dbObj) { 44 | // ignored 45 | // default implementation delete the file 46 | // 47 | // This happens asynchronously so cannot be tracked. However a simple 48 | // access should fail 49 | } 50 | }); 51 | } 52 | 53 | private void openWithFlags(int flags) { 54 | openWithFlags(flags, null); 55 | } 56 | 57 | private void openWithFlags(int flags, DatabaseErrorHandler errorHandler) { 58 | try { 59 | sqliteDatabase = SQLiteDatabase.openDatabase(path, password, null, flags, errorHandler, null); 60 | 61 | }catch (Exception e) { 62 | Log.d(TAG, "Opening db in " + path + " with PRAGMA cipher_migrate"); 63 | SQLiteDatabaseHook hook = new SQLiteDatabaseHook() { 64 | @Override 65 | public void preKey(SQLiteConnection database) { 66 | 67 | } 68 | 69 | @Override 70 | public void postKey(SQLiteConnection database) { 71 | long migrateRes = database.executeForLong("PRAGMA cipher_migrate;", null, null); 72 | 73 | if (migrateRes != 0) { 74 | // Throw the original exception, assuming a wrong password was provided 75 | throw e; 76 | } 77 | } 78 | }; 79 | 80 | sqliteDatabase = SQLiteDatabase.openDatabase(path, password, null, flags, errorHandler, hook); 81 | } 82 | } 83 | 84 | public void close() { 85 | sqliteDatabase.close(); 86 | } 87 | 88 | public SQLiteDatabase getWritableDatabase() { 89 | return sqliteDatabase; 90 | } 91 | 92 | public SQLiteDatabase getReadableDatabase() { 93 | return sqliteDatabase; 94 | } 95 | 96 | public boolean enableWriteAheadLogging() { 97 | try { 98 | sqliteDatabase.rawExecSQL("PRAGMA journal_mode=WAL;"); 99 | } catch (Exception e) { 100 | Log.e(TAG, getThreadLogPrefix() + "enable WAL error: " + e); 101 | return false; 102 | } 103 | return true; 104 | } 105 | 106 | String getThreadLogTag() { 107 | Thread thread = Thread.currentThread(); 108 | 109 | return "" + id + "," + thread.getName() + "(" + thread.getId() + ")"; 110 | } 111 | 112 | String getThreadLogPrefix() { 113 | return "[" + getThreadLogTag() + "] "; 114 | } 115 | 116 | 117 | static void deleteDatabase(String path) { 118 | File file = new File(path); 119 | 120 | file.delete(); 121 | new File(file.getPath() + "-journal").delete(); 122 | new File(file.getPath() + "-shm").delete(); 123 | new File(file.getPath() + "-wal").delete(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/LogLevel.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher; 2 | 3 | import io.flutter.plugin.common.MethodCall; 4 | 5 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_LOG_LEVEL; 6 | 7 | public class LogLevel { 8 | 9 | static final int none = 0; 10 | static final int sql = 1; 11 | static final int verbose = 2; 12 | 13 | static Integer getLogLevel(MethodCall methodCall) { 14 | return methodCall.argument(PARAM_LOG_LEVEL); 15 | } 16 | 17 | static boolean hasSqlLevel(int level) { 18 | return level >= sql; 19 | } 20 | 21 | static boolean hasVerboseLevel(int level) { 22 | return level >= verbose; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/SqlCommand.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher; 2 | 3 | import android.util.Log; 4 | 5 | import com.davidmartos96.sqflite_sqlcipher.dev.Debug; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Arrays; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | import static com.davidmartos96.sqflite_sqlcipher.Constant.TAG; 14 | 15 | public class SqlCommand { 16 | public String getSql() { 17 | return sql; 18 | } 19 | 20 | final private String sql; 21 | final private List rawArguments; 22 | 23 | 24 | // Handle list of int as byte[] 25 | static private Object toValue(Object value) { 26 | if (value == null) { 27 | return null; 28 | } else { 29 | if (Debug.EXTRA_LOGV) { 30 | Log.d(TAG, "arg " + value.getClass().getCanonicalName() + " " + toString(value)); 31 | } 32 | // Assume a list is a blog 33 | if (value instanceof List) { 34 | @SuppressWarnings("unchecked") 35 | List list = (List) value; 36 | byte[] blob = new byte[list.size()]; 37 | for (int i = 0; i < list.size(); i++) { 38 | blob[i] = (byte) (int) list.get(i); 39 | } 40 | value = blob; 41 | 42 | } 43 | if (Debug.EXTRA_LOGV) { 44 | Log.d(TAG, "arg " + value.getClass().getCanonicalName() + " " + toString(value)); 45 | } 46 | return value; 47 | } 48 | } 49 | 50 | public SqlCommand(String sql, List rawArguments) { 51 | this.sql = sql; 52 | if (rawArguments == null) { 53 | rawArguments = new ArrayList<>(); 54 | } 55 | this.rawArguments = rawArguments; 56 | 57 | } 58 | 59 | // Only sanitize if the parameter count matches the argument count 60 | // For integer value replace ? with the actual value directly 61 | // to workaround an issue with references 62 | public SqlCommand sanitizeForQuery() { 63 | if (rawArguments.size() == 0) { 64 | return this; 65 | } 66 | StringBuilder sanitizeSqlSb = new StringBuilder(); 67 | List sanitizeArguments = new ArrayList<>(); 68 | int count = 0; 69 | int argumentIndex = 0; 70 | int sqlLength = sql.length(); 71 | for (int i = 0; i < sqlLength; i++) { 72 | char ch = sql.charAt(i); 73 | if (ch == '?') { 74 | // If it is followed by a number 75 | // it is an indexed param, cancel our weird conversion 76 | if ((i + 1 < sqlLength) && Character.isDigit(sql.charAt(i + 1))) { 77 | return this; 78 | } 79 | count++; 80 | // no match, return the same 81 | if (argumentIndex >= rawArguments.size()) { 82 | return this; 83 | } 84 | Object argument = rawArguments.get(argumentIndex++); 85 | if (argument instanceof Integer || argument instanceof Long) { 86 | sanitizeSqlSb.append(argument.toString()); 87 | continue; 88 | } else { 89 | // Let the other args as is 90 | sanitizeArguments.add(argument); 91 | } 92 | } 93 | // Simply append the existing 94 | sanitizeSqlSb.append(ch); 95 | } 96 | // no match (there might be an extra ? somwhere), return the same 97 | if (count != rawArguments.size()) { 98 | return this; 99 | } 100 | return new SqlCommand(sanitizeSqlSb.toString(), sanitizeArguments); 101 | } 102 | 103 | 104 | // Query only accept string arguments 105 | // so should not have byte[] 106 | private String[] getQuerySqlArguments(List rawArguments) { 107 | return getStringQuerySqlArguments(rawArguments).toArray(new String[0]); 108 | } 109 | 110 | private Object[] getSqlArguments(List rawArguments) { 111 | List fixedArguments = new ArrayList<>(); 112 | if (rawArguments != null) { 113 | for (Object rawArgument : rawArguments) { 114 | fixedArguments.add(toValue(rawArgument)); 115 | } 116 | } 117 | return fixedArguments.toArray(new Object[0]); 118 | } 119 | 120 | 121 | // Query only accept string arguments 122 | private List getStringQuerySqlArguments(List rawArguments) { 123 | List stringArguments = new ArrayList<>(); 124 | if (rawArguments != null) { 125 | for (Object rawArgument : rawArguments) { 126 | stringArguments.add(toString(rawArgument)); 127 | } 128 | } 129 | return stringArguments; 130 | } 131 | 132 | 133 | // Convert a value to a string 134 | // especially byte[] 135 | static private String toString(Object value) { 136 | if (value == null) { 137 | return null; 138 | } else if (value instanceof byte[]) { 139 | List list = new ArrayList<>(); 140 | for (byte _byte : (byte[]) value) { 141 | list.add((int) _byte); 142 | } 143 | return list.toString(); 144 | } else if (value instanceof Map) { 145 | @SuppressWarnings("unchecked") 146 | Map mapValue = (Map) value; 147 | return fixMap(mapValue).toString(); 148 | } else { 149 | return value.toString(); 150 | } 151 | } 152 | 153 | 154 | static private Map fixMap(Map map) { 155 | Map newMap = new HashMap<>(); 156 | for (Map.Entry entry : map.entrySet()) { 157 | Object value = entry.getValue(); 158 | if (value instanceof Map) { 159 | @SuppressWarnings("unchecked") 160 | Map mapValue = (Map) value; 161 | value = fixMap(mapValue); 162 | } else { 163 | value = toString(value); 164 | } 165 | newMap.put(toString(entry.getKey()), value); 166 | } 167 | return newMap; 168 | } 169 | 170 | @Override 171 | public String toString() { 172 | return sql + ((rawArguments == null || rawArguments.isEmpty()) ? "" : (" " + getStringQuerySqlArguments(rawArguments))); 173 | } 174 | 175 | // As expected by execSQL 176 | public Object[] getSqlArguments() { 177 | return getSqlArguments(rawArguments); 178 | } 179 | 180 | public String[] getQuerySqlArguments() { 181 | return getQuerySqlArguments(rawArguments); 182 | } 183 | 184 | public List getRawSqlArguments() { 185 | return rawArguments; 186 | } 187 | 188 | @Override 189 | public int hashCode() { 190 | return sql != null ? sql.hashCode() : 0; 191 | } 192 | 193 | @Override 194 | public boolean equals(Object obj) { 195 | if (obj instanceof SqlCommand) { 196 | SqlCommand o = (SqlCommand) obj; 197 | if (sql != null) { 198 | if (!sql.equals(o.sql)) { 199 | return false; 200 | } 201 | } else { 202 | if (o.sql != null) { 203 | return false; 204 | } 205 | } 206 | 207 | if (rawArguments.size() != o.rawArguments.size()) { 208 | return false; 209 | } 210 | for (int i = 0; i < rawArguments.size(); i++) { 211 | // special blob handling 212 | if (rawArguments.get(i) instanceof byte[] && o.rawArguments.get(i) instanceof byte[]) { 213 | if (!Arrays.equals((byte[]) rawArguments.get(i), (byte[]) o.rawArguments.get(i))) { 214 | return false; 215 | } 216 | } else { 217 | if (!rawArguments.get(i).equals(o.rawArguments.get(i))) { 218 | return false; 219 | } 220 | } 221 | } 222 | return true; 223 | } 224 | return false; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/dev/Debug.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.dev; 2 | 3 | import android.util.Log; 4 | 5 | import static android.content.ContentValues.TAG; 6 | 7 | /** 8 | * Created by alex on 09/01/18. 9 | */ 10 | 11 | public class Debug { 12 | 13 | // Log flags 14 | public static boolean LOGV = false; 15 | public static boolean _EXTRA_LOGV = false; // to set to true for type debugging 16 | // public static boolean _EXTRA_LOGV = true; // to set to true for type debugging 17 | static public boolean EXTRA_LOGV = false; // to set to true for type debugging 18 | 19 | // Deprecated to prevent usage 20 | @Deprecated 21 | public static void devLog(String tag, String message) { 22 | Log.d(TAG, message); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/BaseOperation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | /** 4 | * Created by alex on 09/01/18. 5 | */ 6 | 7 | public abstract class BaseOperation extends BaseReadOperation { 8 | 9 | // We actually have an inner object that does the implementation 10 | protected abstract OperationResult getOperationResult(); 11 | 12 | @Override 13 | public void success(Object result) { 14 | getOperationResult().success(result); 15 | } 16 | 17 | @Override 18 | public void error(String errorCode, String errorMessage, Object data) { 19 | getOperationResult().error(errorCode, errorMessage, data); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/BaseReadOperation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | 4 | import com.davidmartos96.sqflite_sqlcipher.SqlCommand; 5 | 6 | import java.util.List; 7 | 8 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_CONTINUE_OR_ERROR; 9 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_IN_TRANSACTION; 10 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_NO_RESULT; 11 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_SQL; 12 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_SQL_ARGUMENTS; 13 | 14 | /** 15 | * Created by alex on 09/01/18. 16 | */ 17 | 18 | public abstract class BaseReadOperation implements Operation { 19 | private String getSql() { 20 | return getArgument(PARAM_SQL); 21 | } 22 | 23 | private List getSqlArguments() { 24 | return getArgument(PARAM_SQL_ARGUMENTS); 25 | } 26 | 27 | public SqlCommand getSqlCommand() { 28 | return new SqlCommand(getSql(), getSqlArguments()); 29 | } 30 | 31 | public Boolean getInTransaction() { 32 | return getBoolean(PARAM_IN_TRANSACTION); 33 | } 34 | 35 | @Override 36 | public boolean getNoResult() { 37 | return Boolean.TRUE.equals(getArgument(PARAM_NO_RESULT)); 38 | } 39 | 40 | @Override 41 | public boolean getContinueOnError() { 42 | return Boolean.TRUE.equals(getArgument(PARAM_CONTINUE_OR_ERROR)); 43 | } 44 | 45 | private Boolean getBoolean(String key) { 46 | Object value = getArgument(key); 47 | if (value instanceof Boolean) { 48 | return (Boolean) value; 49 | } 50 | return null; 51 | } 52 | 53 | // We actually have an inner object that does the implementation 54 | protected abstract OperationResult getOperationResult(); 55 | 56 | } 57 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/BatchOperation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | import java.util.HashMap; 4 | import java.util.List; 5 | import java.util.Map; 6 | 7 | import io.flutter.plugin.common.MethodChannel; 8 | 9 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_ERROR; 10 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_ERROR_CODE; 11 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_ERROR_DATA; 12 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_ERROR_MESSAGE; 13 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_METHOD; 14 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_RESULT; 15 | 16 | /** 17 | * Created by alex on 09/01/18. 18 | */ 19 | 20 | public class BatchOperation extends BaseOperation { 21 | final Map map; 22 | final BatchOperationResult operationResult = new BatchOperationResult(); 23 | final boolean noResult; 24 | 25 | public class BatchOperationResult implements OperationResult { 26 | // success 27 | Object result; 28 | 29 | // error 30 | String errorCode; 31 | String errorMessage; 32 | Object errorData; 33 | 34 | @Override 35 | public void success(Object result) { 36 | this.result = result; 37 | } 38 | 39 | @Override 40 | public void error(String errorCode, String errorMessage, Object data) { 41 | this.errorCode = errorCode; 42 | this.errorMessage = errorMessage; 43 | this.errorData = data; 44 | } 45 | } 46 | 47 | public BatchOperation(Map map, boolean noResult) { 48 | this.map = map; 49 | this.noResult = noResult; 50 | } 51 | 52 | @Override 53 | public String getMethod() { 54 | return (String) map.get(PARAM_METHOD); 55 | } 56 | 57 | @SuppressWarnings("unchecked") 58 | @Override 59 | public T getArgument(String key) { 60 | return (T) map.get(key); 61 | } 62 | 63 | @Override 64 | public OperationResult getOperationResult() { 65 | return operationResult; 66 | } 67 | 68 | public Map getOperationSuccessResult() { 69 | Map results = new HashMap<>(); 70 | results.put(PARAM_RESULT, operationResult.result); 71 | return results; 72 | } 73 | 74 | public Map getOperationError() { 75 | Map error = new HashMap<>(); 76 | Map errorDetail = new HashMap<>(); 77 | errorDetail.put(PARAM_ERROR_CODE, operationResult.errorCode); 78 | errorDetail.put(PARAM_ERROR_MESSAGE, operationResult.errorMessage); 79 | errorDetail.put(PARAM_ERROR_DATA, operationResult.errorData); 80 | error.put(PARAM_ERROR, errorDetail); 81 | return error; 82 | } 83 | 84 | public void handleError(MethodChannel.Result result) { 85 | result.error(this.operationResult.errorCode, this.operationResult.errorMessage, this.operationResult.errorData); 86 | } 87 | 88 | @Override 89 | public boolean getNoResult() { 90 | return noResult; 91 | } 92 | 93 | public void handleSuccess(List> results) { 94 | if (!getNoResult()) { 95 | results.add(getOperationSuccessResult()); 96 | } 97 | } 98 | 99 | public void handleErrorContinue(List> results) { 100 | if (!getNoResult()) { 101 | results.add(getOperationError()); 102 | } 103 | } 104 | 105 | 106 | } 107 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/ExecuteOperation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | import com.davidmartos96.sqflite_sqlcipher.SqlCommand; 4 | 5 | import io.flutter.plugin.common.MethodChannel; 6 | 7 | /** 8 | * Created by alex on 09/01/18. 9 | */ 10 | 11 | public class ExecuteOperation extends BaseReadOperation { 12 | final private SqlCommand command; 13 | final private MethodChannel.Result result; 14 | final private Boolean inTransaction; 15 | 16 | public ExecuteOperation(MethodChannel.Result result, SqlCommand command, Boolean inTransaction) { 17 | this.result = result; 18 | this.command = command; 19 | this.inTransaction = inTransaction; 20 | } 21 | 22 | @Override 23 | public SqlCommand getSqlCommand() { 24 | return command; 25 | } 26 | 27 | @Override 28 | protected OperationResult getOperationResult() { 29 | return null; 30 | } 31 | 32 | @Override 33 | public String getMethod() { 34 | return null; 35 | } 36 | 37 | @Override 38 | public T getArgument(String key) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public void error(String errorCode, String errorMessage, Object data) { 44 | result.error(errorCode, errorMessage, data); 45 | } 46 | 47 | @Override 48 | public Boolean getInTransaction() { 49 | return inTransaction; 50 | } 51 | 52 | @Override 53 | public void success(Object result) { 54 | this.result.success(result); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/MethodCallOperation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | import io.flutter.plugin.common.MethodCall; 4 | import io.flutter.plugin.common.MethodChannel; 5 | 6 | /** 7 | * Operation for Method call 8 | */ 9 | 10 | public class MethodCallOperation extends BaseOperation { 11 | final MethodCall methodCall; 12 | final Result result; 13 | 14 | class Result implements OperationResult { 15 | 16 | final MethodChannel.Result result; 17 | 18 | Result(MethodChannel.Result result) { 19 | this.result = result; 20 | } 21 | 22 | @Override 23 | public void success(Object result) { 24 | this.result.success(result); 25 | } 26 | 27 | @Override 28 | public void error(String errorCode, String errorMessage, Object data) { 29 | result.error(errorCode, errorMessage, data); 30 | } 31 | 32 | } 33 | 34 | public MethodCallOperation(MethodCall methodCall, MethodChannel.Result result) { 35 | this.methodCall = methodCall; 36 | this.result = new Result(result); 37 | } 38 | 39 | @Override 40 | public String getMethod() { 41 | return methodCall.method; 42 | } 43 | 44 | @Override 45 | public T getArgument(String key) { 46 | return methodCall.argument(key); 47 | } 48 | 49 | @Override 50 | public OperationResult getOperationResult() { 51 | return result; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/Operation.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | import com.davidmartos96.sqflite_sqlcipher.SqlCommand; 4 | 5 | /** 6 | * Created by alex on 09/01/18. 7 | */ 8 | 9 | public interface Operation extends OperationResult { 10 | 11 | String getMethod(); 12 | 13 | T getArgument(String key); 14 | 15 | SqlCommand getSqlCommand(); 16 | 17 | boolean getNoResult(); 18 | 19 | // In batch, means ignoring the error 20 | boolean getContinueOnError(); 21 | 22 | // Only for execute command 23 | Boolean getInTransaction(); 24 | } 25 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/OperationResult.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | /** 4 | * Created by alex on 09/01/18. 5 | */ 6 | 7 | public interface OperationResult { 8 | void error(final String errorCode, final String errorMessage, final Object data); 9 | 10 | void success(final Object result); 11 | } 12 | -------------------------------------------------------------------------------- /sqflite/android/src/main/java/com/davidmartos96/sqflite_sqlcipher/operation/SqlErrorInfo.java: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.sqflite_sqlcipher.operation; 2 | 3 | import com.davidmartos96.sqflite_sqlcipher.SqlCommand; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_SQL; 9 | import static com.davidmartos96.sqflite_sqlcipher.Constant.PARAM_SQL_ARGUMENTS; 10 | 11 | public class SqlErrorInfo { 12 | 13 | static public Map getMap(Operation operation) { 14 | Map map = null; 15 | SqlCommand command = operation.getSqlCommand(); 16 | if (command != null) { 17 | map = new HashMap<>(); 18 | map.put(PARAM_SQL, command.getSql()); 19 | map.put(PARAM_SQL_ARGUMENTS, command.getRawSqlArguments()); 20 | } 21 | return map; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sqflite/example/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .atom/ 3 | .idea 4 | .packages 5 | .pub/ 6 | build/ 7 | ios/.generated/ 8 | packages 9 | pubspec.lock 10 | .flutter-plugins 11 | sqflite_example.iml 12 | 13 | # local files 14 | .local/ 15 | tmp/ 16 | 17 | # no web support 18 | /web/ -------------------------------------------------------------------------------- /sqflite/example/README.md: -------------------------------------------------------------------------------- 1 | # sqflite_example 2 | 3 | Demonstrates how to use the [sqflite plugin](https://github.com/tekartik/sqflite). 4 | 5 | ## Quick test 6 | 7 | 8 | flutter run 9 | 10 | Specific app entry point 11 | 12 | flutter run -t lib/main.dart 13 | 14 | ## Getting Started 15 | 16 | For help getting started with Flutter, view the online 17 | [documentation](https://flutter.io/). 18 | -------------------------------------------------------------------------------- /sqflite/example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | # Defines a default set of lint rules enforced for 2 | # projects at Google. For details and rationale, 3 | # see https://github.com/dart-lang/pedantic#enabled-lints. 4 | include: package:pedantic/analysis_options.yaml 5 | 6 | analyzer: 7 | strong-mode: 8 | implicit-casts: false 9 | # implicit-dynamic: false 10 | 11 | linter: 12 | rules: 13 | test_types_in_equals: true 14 | unrelated_type_equality_checks: true 15 | valid_regexps: true 16 | annotate_overrides: true 17 | hash_and_equals: true 18 | prefer_is_not_empty: true 19 | avoid_empty_else: true 20 | cancel_subscriptions: true 21 | close_sinks: true 22 | always_declare_return_types: true 23 | camel_case_types: true 24 | empty_constructor_bodies: true 25 | avoid_init_to_null: true 26 | constant_identifier_names: true 27 | one_member_abstracts: true 28 | slash_for_doc_comments: true 29 | sort_constructors_first: true 30 | unnecessary_brace_in_string_interps: true 31 | 32 | # === doc rules === 33 | public_member_api_docs: true 34 | 35 | # ignore specify types 36 | always_specify_types: false 37 | # ignore const for now 38 | prefer_const_constructors: false -------------------------------------------------------------------------------- /sqflite/example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /sqflite/example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.davidmartos96.example" 27 | compileSdk flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.davidmartos96.example" 46 | minSdkVersion 21 47 | targetSdkVersion flutter.targetSdkVersion 48 | versionCode flutterVersionCode.toInteger() 49 | versionName flutterVersionName 50 | } 51 | 52 | buildTypes { 53 | release { 54 | // TODO: Add your own signing config for the release build. 55 | // Signing with the debug keys for now, so `flutter run --release` works. 56 | signingConfig signingConfigs.debug 57 | } 58 | } 59 | } 60 | 61 | flutter { 62 | source '../..' 63 | } 64 | 65 | dependencies {} 66 | -------------------------------------------------------------------------------- /sqflite/example/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | -keep class net.sqlcipher.** { *; } 2 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 14 | 18 | 22 | 23 | 24 | 25 | 26 | 27 | 29 | 32 | 33 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/kotlin/com/davidmartos96/example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.davidmartos96.example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() 6 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /sqflite/example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sqflite/example/android/build.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | } 7 | 8 | rootProject.buildDir = '../build' 9 | subprojects { 10 | project.buildDir = "${rootProject.buildDir}/${project.name}" 11 | } 12 | subprojects { 13 | project.evaluationDependsOn(':app') 14 | } 15 | 16 | tasks.register("clean", Delete) { 17 | delete rootProject.buildDir 18 | } 19 | -------------------------------------------------------------------------------- /sqflite/example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /sqflite/example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip 6 | -------------------------------------------------------------------------------- /sqflite/example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | } 19 | 20 | plugins { 21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 22 | id "com.android.application" version "7.3.0" apply false 23 | id "org.jetbrains.kotlin.android" version "1.7.10" apply false 24 | } 25 | 26 | include ":app" 27 | -------------------------------------------------------------------------------- /sqflite/example/assets/example.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/assets/example.db -------------------------------------------------------------------------------- /sqflite/example/assets/example_pass_1234.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/assets/example_pass_1234.db -------------------------------------------------------------------------------- /sqflite/example/assets/issue_64.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/assets/issue_64.db -------------------------------------------------------------------------------- /sqflite/example/assets/sqlcipher-3.0-testkey.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/assets/sqlcipher-3.0-testkey.db -------------------------------------------------------------------------------- /sqflite/example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /sqflite/example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /sqflite/example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /sqflite/example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /sqflite/example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /sqflite/example/lib/batch_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher/sqflite.dart'; 2 | 3 | import 'test_page.dart'; 4 | 5 | /// Batch test page. 6 | class BatchTestPage extends TestPage { 7 | /// Batch test page. 8 | BatchTestPage() : super('Batch tests') { 9 | test('BatchQuery', () async { 10 | // await Sqflite.devSetDebugModeOn(); 11 | var path = await initDeleteDb('batch.db'); 12 | var db = await openDatabase(path); 13 | 14 | // empty batch 15 | var batch = db.batch(); 16 | batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 17 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item1']); 18 | var results = await batch.commit(); 19 | expect(results, [null, 1]); 20 | 21 | var dbResult = await db.rawQuery('SELECT id, name FROM Test'); 22 | // devPrint('dbResult $dbResult'); 23 | expect(dbResult, [ 24 | {'id': 1, 'name': 'item1'} 25 | ]); 26 | 27 | // one query 28 | batch = db.batch(); 29 | batch.rawQuery('SELECT id, name FROM Test'); 30 | batch.query('Test', columns: ['id', 'name']); 31 | results = await batch.commit(); 32 | // devPrint('select $results ${results?.first}'); 33 | expect(results, [ 34 | [ 35 | {'id': 1, 'name': 'item1'} 36 | ], 37 | [ 38 | {'id': 1, 'name': 'item1'} 39 | ] 40 | ]); 41 | await db.close(); 42 | }); 43 | test('Batch', () async { 44 | // await Sqflite.devSetDebugModeOn(); 45 | var path = await initDeleteDb('batch.db'); 46 | var db = await openDatabase(path); 47 | 48 | // empty batch 49 | var batch = db.batch(); 50 | var results = await batch.commit(); 51 | expect(results.length, 0); 52 | expect(results, []); 53 | 54 | // one create table 55 | batch = db.batch(); 56 | batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 57 | results = await batch.commit(); 58 | // devPrint('1 $results ${results?.first}'); 59 | expect(results, [null]); 60 | expect(results[0], null); 61 | 62 | // one insert 63 | batch = db.batch(); 64 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item1']); 65 | results = await batch.commit(); 66 | expect(results, [1]); 67 | 68 | // one query 69 | batch = db.batch(); 70 | batch.rawQuery('SELECT id, name FROM Test'); 71 | batch.query('Test', columns: ['id', 'name']); 72 | results = await batch.commit(); 73 | // devPrint('select $results ${results?.first}'); 74 | expect(results, [ 75 | [ 76 | {'id': 1, 'name': 'item1'} 77 | ], 78 | [ 79 | {'id': 1, 'name': 'item1'} 80 | ] 81 | ]); 82 | 83 | // two insert 84 | batch = db.batch(); 85 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item2']); 86 | batch.insert('Test', {'name': 'item3'}); 87 | results = await batch.commit(); 88 | expect(results, [2, 3]); 89 | 90 | // update 91 | batch = db.batch(); 92 | batch.rawUpdate( 93 | 'UPDATE Test SET name = ? WHERE name = ?', ['new_item', 'item1']); 94 | batch.update('Test', {'name': 'new_other_item'}, 95 | where: 'name != ?', whereArgs: ['new_item']); 96 | results = await batch.commit(); 97 | expect(results, [1, 2]); 98 | 99 | // delete 100 | batch = db.batch(); 101 | batch.rawDelete('DELETE FROM Test WHERE name = ?', ['new_item']); 102 | batch.delete('Test', 103 | where: 'name = ?', whereArgs: ['new_other_item']); 104 | results = await batch.commit(); 105 | expect(results, [1, 2]); 106 | 107 | // No result 108 | batch = db.batch(); 109 | batch.insert('Test', {'name': 'item'}); 110 | batch.update('Test', {'name': 'new_item'}, 111 | where: 'name = ?', whereArgs: ['item']); 112 | batch.delete('Test', where: 'name = ?', whereArgs: ['item']); 113 | results = await batch.commit(noResult: true); 114 | expect(results, null); 115 | 116 | await db.close(); 117 | }); 118 | 119 | test('Batch in transaction', () async { 120 | // await Sqflite.devSetDebugModeOn(); 121 | var path = await initDeleteDb('batch_in_transaction.db'); 122 | var db = await openDatabase(path); 123 | 124 | var results; 125 | 126 | await db.transaction((txn) async { 127 | var batch1 = txn.batch(); 128 | batch1.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 129 | var batch2 = txn.batch(); 130 | batch2.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item1']); 131 | results = await batch1.commit(); 132 | expect(results, [null]); 133 | 134 | results = await batch2.commit(); 135 | expect(results, [1]); 136 | }); 137 | 138 | await db.close(); 139 | }); 140 | 141 | test('Batch continue on error', () async { 142 | // await Sqflite.devSetDebugModeOn(); 143 | var path = await initDeleteDb('batch_continue_on_error.db'); 144 | var db = await openDatabase(path); 145 | try { 146 | var batch = db.batch(); 147 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item1']); 148 | batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 149 | batch.execute('DUMMY'); 150 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item1']); 151 | batch.rawQuery('SELECT * FROM Test'); 152 | var results = await batch.commit(continueOnError: true); 153 | // devPrint(results); 154 | // First result is an exception 155 | var exception = results[0] as DatabaseException; 156 | expect(exception.isNoSuchTableError(), true); 157 | // Second result is null (create table) 158 | expect(results[1], null); 159 | // Third result is an exception 160 | exception = results[2] as DatabaseException; 161 | expect(exception.isSyntaxError(), true); 162 | // Fourth result is an insert 163 | expect(results[3], 1); 164 | // Fifth is a select 165 | expect(results[4], [ 166 | {'id': 1, 'name': 'item1'} 167 | ]); 168 | } finally { 169 | await db.close(); 170 | } 171 | }); 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /sqflite/example/lib/database/database.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:io'; 3 | 4 | import 'package:path/path.dart'; 5 | import 'package:sqflite_sqlcipher/sqflite.dart'; 6 | 7 | /// delete the db, create the folder and returnes its path 8 | Future initDeleteDb(String dbName) async { 9 | final databasePath = await getDatabasesPath(); 10 | // print(databasePath); 11 | final path = join(databasePath, dbName); 12 | 13 | if (await File(path).exists()) { 14 | await deleteDatabase(path); 15 | } 16 | 17 | final parent = Directory(dirname(path)); 18 | 19 | // make sure the folder exists 20 | if (!(await parent.exists())) { 21 | await parent.create(recursive: true); 22 | } 23 | return path; 24 | } 25 | -------------------------------------------------------------------------------- /sqflite/example/lib/deprecated_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'test_page.dart'; 2 | 3 | /// Deprecated test page. 4 | class DeprecatedTestPage extends TestPage { 5 | /// Deprecated test page. 6 | DeprecatedTestPage() : super('Deprecated tests') { 7 | test('None', () async {}); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sqflite/example/lib/manual_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:sqflite_common/utils/utils.dart'; 5 | import 'package:sqflite_sqlcipher/sqflite.dart'; 6 | import 'package:sqflite_sqlcipher/src/sqflite_import.dart' as impl; 7 | import 'package:sqflite_sqlcipher_example/model/item.dart'; 8 | import 'package:sqflite_sqlcipher_example/src/item_widget.dart'; 9 | import 'package:sqflite_sqlcipher_example/utils.dart'; 10 | 11 | /// Manual test page. 12 | class ManualTestPage extends StatefulWidget { 13 | @override 14 | _ManualTestPageState createState() => _ManualTestPageState(); 15 | } 16 | 17 | class _ManualTestPageState extends State { 18 | Database? database; 19 | static const String dbName = 'manual_test.db'; 20 | 21 | Future _openDatabase() async { 22 | return database ??= await databaseFactory.openDatabase(dbName); 23 | } 24 | 25 | Future _closeDatabase() async { 26 | await database?.close(); 27 | database = null; 28 | } 29 | 30 | Future _deleteDatabase() async { 31 | await databaseFactory.deleteDatabase(dbName); 32 | } 33 | 34 | Future _incrementVersion() async { 35 | var version = await database!.getVersion(); 36 | print('version $version'); 37 | await database!.setVersion(version + 1); 38 | } 39 | 40 | late List items; 41 | late List itemWidgets; 42 | 43 | @override 44 | void didChangeDependencies() { 45 | super.didChangeDependencies(); 46 | items = [ 47 | MenuItem('openDatabase', () async { 48 | await _openDatabase(); 49 | }, summary: 'Open the database'), 50 | MenuItem('BEGIN EXCLUSIVE', () async { 51 | var db = await _openDatabase(); 52 | await db.execute('BEGIN EXCLUSIVE'); 53 | }, 54 | summary: 55 | 'Execute than exit or hot-restart the application. Open the database if needed'), 56 | MenuItem('close', () async { 57 | await _closeDatabase(); 58 | }, 59 | summary: 60 | 'Execute after starting then exit the app using the back button on Android and restart from the launcher.'), 61 | MenuItem('delete', () async { 62 | await _deleteDatabase(); 63 | }, 64 | summary: 65 | 'Try open (then optionally) delete, exit or hot-restart then delete then open'), 66 | MenuItem('Get info', () async { 67 | final factory = databaseFactory as impl.SqfliteDatabaseFactoryMixin; 68 | var info = await factory.getDebugInfo(); 69 | print(info.toString()); 70 | }, summary: 'Implementation info (dev only)'), 71 | MenuItem('Increment version', () async { 72 | print(await _incrementVersion()); 73 | }, summary: 'Implementation info (dev only)'), 74 | MenuItem('Multiple db', () async { 75 | await Navigator.of(context).push(MaterialPageRoute(builder: (_) { 76 | return MultipleDbTestPage(); 77 | })); 78 | }, summary: 'Open multiple databases') 79 | ]; 80 | } 81 | 82 | @override 83 | Widget build(BuildContext context) { 84 | itemWidgets = items 85 | .map((item) => ItemWidget( 86 | item, 87 | (item) async { 88 | final stopwatch = Stopwatch()..start(); 89 | var future = item.run(); 90 | setState(() {}); 91 | await future; 92 | // always add a small delay 93 | var elapsed = stopwatch.elapsedMilliseconds; 94 | if (elapsed < 300) { 95 | await sleep(300 - elapsed); 96 | } 97 | setState(() {}); 98 | }, 99 | summary: item.summary, 100 | )) 101 | .toList(growable: false); 102 | return Scaffold( 103 | appBar: AppBar( 104 | title: Text('Manual tests'), 105 | ), 106 | body: ListView( 107 | children: itemWidgets, 108 | ), 109 | ); 110 | } 111 | } 112 | 113 | /// Multiple db test page. 114 | class MultipleDbTestPage extends StatelessWidget { 115 | @override 116 | Widget build(BuildContext context) { 117 | Widget dbTile(String name) { 118 | return ListTile( 119 | title: Text(name), 120 | onTap: () { 121 | Navigator.of(context).push(MaterialPageRoute(builder: (_) { 122 | return SimpleDbTestPage( 123 | dbName: name, 124 | ); 125 | })); 126 | }, 127 | ); 128 | } 129 | 130 | return Scaffold( 131 | appBar: AppBar( 132 | title: Text('Multiple databases'), 133 | ), 134 | body: ListView( 135 | children: [ 136 | dbTile('data1.db'), 137 | dbTile('data2.db'), 138 | dbTile('data3.db') 139 | ], 140 | ), 141 | ); 142 | } 143 | } 144 | 145 | /// Simple db test page. 146 | class SimpleDbTestPage extends StatefulWidget { 147 | /// Simple db test page. 148 | const SimpleDbTestPage({Key? key, this.dbName}) : super(key: key); 149 | 150 | /// db name. 151 | final String? dbName; 152 | 153 | @override 154 | _SimpleDbTestPageState createState() => _SimpleDbTestPageState(); 155 | } 156 | 157 | class _SimpleDbTestPageState extends State { 158 | Database? database; 159 | 160 | Future _openDatabase() async { 161 | // await Sqflite.devSetOptions(SqfliteOptions(logLevel: sqfliteLogLevelVerbose)); 162 | return database ??= await databaseFactory.openDatabase(widget.dbName!, 163 | options: OpenDatabaseOptions( 164 | version: 1, 165 | onCreate: (db, version) async { 166 | await db.execute('CREATE TABLE Test (value TEXT)'); 167 | })); 168 | } 169 | 170 | Future _closeDatabase() async { 171 | await database?.close(); 172 | database = null; 173 | } 174 | 175 | @override 176 | void initState() { 177 | super.initState(); 178 | } 179 | 180 | @override 181 | Widget build(BuildContext context) { 182 | return Scaffold( 183 | appBar: AppBar( 184 | title: Text('Simple db ${widget.dbName}'), 185 | ), 186 | body: Builder( 187 | builder: (context) { 188 | Widget menuItem(String title, void Function() onTap, 189 | {String? summary}) { 190 | return ListTile( 191 | title: Text(title), 192 | subtitle: summary == null ? null : Text(summary), 193 | onTap: onTap, 194 | ); 195 | } 196 | 197 | Future _countRecord() async { 198 | var db = await _openDatabase(); 199 | var result = firstIntValue( 200 | await db.query('test', columns: ['COUNT(*)'])); 201 | ScaffoldMessenger.of(context).showSnackBar(SnackBar( 202 | content: Text('$result records'), 203 | duration: Duration(milliseconds: 700), 204 | )); 205 | } 206 | 207 | var items = [ 208 | menuItem('open Database', () async { 209 | await _openDatabase(); 210 | }, summary: 'Open the database'), 211 | menuItem('Add record', () async { 212 | var db = await _openDatabase(); 213 | await db.insert('test', {'value': 'some_value'}); 214 | await _countRecord(); 215 | }, summary: 'Add one record. Open the database if needed'), 216 | menuItem('Count record', () async { 217 | await _countRecord(); 218 | }, summary: 'Count records. Open the database if needed'), 219 | menuItem( 220 | 'Close Database', 221 | () async { 222 | await _closeDatabase(); 223 | }, 224 | ), 225 | ]; 226 | return ListView( 227 | children: items, 228 | ); 229 | }, 230 | )); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /sqflite/example/lib/model/item.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher_example/src/common_import.dart'; 2 | 3 | /// Item states. 4 | enum ItemState { 5 | /// test not run yet. 6 | none, 7 | 8 | /// test is running. 9 | running, 10 | 11 | /// test succeeded. 12 | success, 13 | 14 | /// test fails. 15 | failure 16 | } 17 | 18 | /// Menu item. 19 | class Item { 20 | /// Menu item. 21 | Item(this.name); 22 | 23 | /// Menu item state. 24 | ItemState state = ItemState.running; 25 | 26 | /// Menu item name/ 27 | String name; 28 | } 29 | 30 | /// Menu item implementation. 31 | class MenuItem extends Item { 32 | /// Menu item implementation. 33 | MenuItem(String name, this.body, {this.summary}) : super(name) { 34 | state = ItemState.none; 35 | } 36 | 37 | /// Summary. 38 | String? summary; 39 | 40 | /// Run the item. 41 | Future run() { 42 | state = ItemState.running; 43 | return Future.delayed(Duration()).then((_) async { 44 | try { 45 | await body(); 46 | state = ItemState.success; 47 | } catch (e) { 48 | state = ItemState.failure; 49 | rethrow; 50 | } 51 | }); 52 | } 53 | 54 | /// Menu item body. 55 | final FutureOr Function() body; 56 | } 57 | -------------------------------------------------------------------------------- /sqflite/example/lib/model/main_item.dart: -------------------------------------------------------------------------------- 1 | /// Main item. 2 | class MainItem { 3 | /// Main item. 4 | MainItem(this.title, this.description, {this.route}); 5 | 6 | /// Title. 7 | String title; 8 | 9 | /// Description. 10 | String description; 11 | 12 | /// Page route. 13 | String? route; 14 | } 15 | 16 | /// Main route item. 17 | class MainRouteItem { 18 | /// Main route item. 19 | MainRouteItem(this.title, this.description, {this.route}); 20 | 21 | /// Title. 22 | String title; 23 | 24 | /// Description. 25 | String description; 26 | 27 | /// Page route. 28 | MainRouteItem? route; 29 | } 30 | -------------------------------------------------------------------------------- /sqflite/example/lib/model/test.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | /// Test definition. 4 | class Test { 5 | /// Test definition. 6 | Test(this.name, this.fn, {bool? solo, bool? skip}) 7 | : solo = solo == true, 8 | skip = skip == true; 9 | 10 | /// Only run this test. 11 | final bool solo; 12 | 13 | /// Skip this test. 14 | final bool skip; 15 | 16 | /// Test name. 17 | String name; 18 | 19 | /// Test body. 20 | FutureOr Function() fn; 21 | } 22 | -------------------------------------------------------------------------------- /sqflite/example/lib/slow_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher/sqflite.dart'; 2 | 3 | import 'test_page.dart'; 4 | 5 | /// Slow test page. 6 | class SlowTestPage extends TestPage { 7 | /// Slow test page. 8 | SlowTestPage() : super('Slow tests') { 9 | test('Perf 100 insert', () async { 10 | var path = await initDeleteDb('slow_txn_100_insert.db'); 11 | var db = await openDatabase(path); 12 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 13 | await db.transaction((txn) async { 14 | for (var i = 0; i < 100; i++) { 15 | await txn 16 | .rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 17 | } 18 | }); 19 | await db.close(); 20 | }); 21 | 22 | test('Perf 100 insert no txn', () async { 23 | var path = await initDeleteDb('slow_100_insert.db'); 24 | var db = await openDatabase(path); 25 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 26 | for (var i = 0; i < 1000; i++) { 27 | await db.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 28 | } 29 | await db.close(); 30 | }); 31 | 32 | test('Perf 1000 insert', () async { 33 | await perfInsert(); 34 | }); 35 | 36 | test('Perf 1000 insert batch', () async { 37 | var path = await initDeleteDb('slow_txn_1000_insert_batch.db'); 38 | var db = await openDatabase(path); 39 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 40 | 41 | var sw = Stopwatch()..start(); 42 | var batch = db.batch(); 43 | 44 | for (var i = 0; i < 1000; i++) { 45 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 46 | } 47 | await batch.commit(); 48 | print('1000 insert batch ${sw.elapsed}'); 49 | await db.close(); 50 | }); 51 | 52 | test('Perf 1000 insert batch no result', () async { 53 | var path = await initDeleteDb('slow_txn_1000_insert_batch_no_result.db'); 54 | var db = await openDatabase(path); 55 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 56 | 57 | var sw = Stopwatch()..start(); 58 | var batch = db.batch(); 59 | 60 | for (var i = 0; i < 1000; i++) { 61 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 62 | } 63 | await batch.commit(noResult: true); 64 | 65 | print('1000 insert batch no result ${sw.elapsed}'); 66 | await db.close(); 67 | }); 68 | 69 | var count = 10000; 70 | 71 | test('Perf $count item', () async { 72 | //Sqflite.devSetDebugModeOn(true); 73 | await perfDo(count); 74 | }); 75 | } 76 | 77 | /// basic performance testing. 78 | Future perfDo(int count) async { 79 | var path = await initDeleteDb('pref_${count}_items.db'); 80 | var db = await openDatabase(path); 81 | try { 82 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 83 | 84 | var sw = Stopwatch()..start(); 85 | var batch = db.batch(); 86 | 87 | for (var i = 0; i < count; i++) { 88 | batch.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 89 | } 90 | await batch.commit(); 91 | print('sw ${sw.elapsed} insert $count items batch '); 92 | 93 | sw = Stopwatch()..start(); 94 | var result = await db.query('Test'); 95 | print('sw ${sw.elapsed} SELECT * From Test : ${result.length} items'); 96 | 97 | sw = Stopwatch()..start(); 98 | result = 99 | await db.query('Test', where: 'name LIKE ?', whereArgs: ['%item%']); 100 | print( 101 | 'sw ${sw.elapsed} SELECT * FROM Test WHERE name LIKE %item% ${result.length} items'); 102 | 103 | sw = Stopwatch()..start(); 104 | result = 105 | await db.query('Test', where: 'name LIKE ?', whereArgs: ['%dummy%']); 106 | print( 107 | 'sw ${sw.elapsed} SELECT * FROM Test WHERE name LIKE %dummy% ${result.length} items'); 108 | } finally { 109 | await db.close(); 110 | } 111 | } 112 | 113 | /// Insert perf testing. 114 | Future perfInsert() async { 115 | var path = await initDeleteDb('slow_txn_1000_insert.db'); 116 | var db = await openDatabase(path); 117 | await db.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 118 | 119 | var sw = Stopwatch()..start(); 120 | await db.transaction((txn) async { 121 | for (var i = 0; i < 1000; i++) { 122 | await txn.rawInsert('INSERT INTO Test (name) VALUES (?)', ['item $i']); 123 | } 124 | }); 125 | print('1000 insert ${sw.elapsed}'); 126 | await db.close(); 127 | } 128 | 129 | // 2019-02-26 130 | 131 | // BACKGROUND 132 | 133 | } 134 | -------------------------------------------------------------------------------- /sqflite/example/lib/sqlcipher_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:path/path.dart'; 5 | import 'package:sqflite_sqlcipher/sqflite.dart'; 6 | import 'package:sqflite_sqlcipher_example/open_test_page.dart'; 7 | 8 | import 'package:sqflite/sqflite.dart' as sqflite; 9 | 10 | import 'test_page.dart'; 11 | 12 | /// Cipher test page. 13 | class SqlCipherTestPage extends TestPage { 14 | /// Cipher test page. 15 | SqlCipherTestPage() : super('SqlCipher tests') { 16 | test('Open and query database', () async { 17 | var path = await initDeleteDb('encrypted.db'); 18 | 19 | const password = '1234'; 20 | 21 | var db = await openDatabase( 22 | path, 23 | password: password, 24 | version: 1, 25 | onCreate: (db, version) async { 26 | var batch = db.batch(); 27 | 28 | batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, text NAME)'); 29 | await batch.commit(); 30 | }, 31 | ); 32 | 33 | try { 34 | expect(await db.rawInsert('INSERT INTO Test (text) VALUES (?)', ['test']), 1); 35 | var result = await db.query('Test'); 36 | var expected = [ 37 | {'id': 1, 'text': 'test'} 38 | ]; 39 | expect(result, expected); 40 | 41 | expect(await isDatabase(path, password: password), isTrue); 42 | } finally { 43 | await db.close(); 44 | } 45 | expect(await isDatabase(path, password: password), isTrue); 46 | }); 47 | 48 | test('Open asset database', () async { 49 | var path = await initDeleteDb('asset_example.db'); 50 | 51 | // Copy from asset 52 | var data = await rootBundle.load(join('assets', 'example_pass_1234.db')); 53 | List bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 54 | // Write and flush the bytes written 55 | await File(path).writeAsBytes(bytes, flush: true); 56 | 57 | // open the database 58 | var db = await openDatabase(path, password: '1234'); 59 | 60 | // Our database as a single table with a single element 61 | List> list = await db.rawQuery('SELECT * FROM Test'); 62 | print('list $list'); 63 | expect(list.first['name'], 'simple value'); 64 | 65 | await db.close(); 66 | }); 67 | 68 | test('Wrong password', () async { 69 | var path = await initDeleteDb('asset_example.db'); 70 | 71 | // Copy from asset 72 | var data = await rootBundle.load(join('assets', 'example_pass_1234.db')); 73 | List bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 74 | // Write and flush the bytes written 75 | await File(path).writeAsBytes(bytes, flush: true); 76 | 77 | try { 78 | // open the database with the wrong password 79 | await openDatabase(path, password: 'abc'); 80 | fail('Should trhow'); 81 | } on DatabaseException catch (e) { 82 | print('error captured: $e'); 83 | expect(e.toString().contains('open_failed'), isTrue); 84 | } 85 | }); 86 | 87 | test('Open asset database (SQLCipher 3.x, cipher_migrate on Android)', () async { 88 | var path = await initDeleteDb('asset_example.db'); 89 | 90 | // Copy from asset 91 | var data = await rootBundle.load(join('assets', 'sqlcipher-3.0-testkey.db')); 92 | List bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); 93 | // Write and flush the bytes written 94 | await File(path).writeAsBytes(bytes, flush: true); 95 | 96 | // open the database 97 | var db = await openDatabase(path, password: 'testkey'); 98 | 99 | // Our database as a single table with a single element 100 | List> list = await db.rawQuery('SELECT * FROM t1'); 101 | expect(list.length, greaterThan(0)); 102 | 103 | await db.close(); 104 | }); 105 | 106 | test('Open an unencrypted database with the package sqflite', () async { 107 | var path = await initDeleteDb('unencrypted.db'); 108 | 109 | var db = await sqflite.openDatabase( 110 | path, 111 | version: 1, 112 | onCreate: (db, version) async { 113 | var batch = db.batch(); 114 | 115 | batch.execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, text NAME)'); 116 | await batch.commit(); 117 | }, 118 | ); 119 | 120 | try { 121 | expect(await db.rawInsert('INSERT INTO Test (text) VALUES (?)', ['test']), 1); 122 | var result = await db.query('Test'); 123 | var expected = [ 124 | {'id': 1, 'text': 'test'} 125 | ]; 126 | expect(result, expected); 127 | } finally { 128 | await db.close(); 129 | } 130 | }); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /sqflite/example/lib/src/common_import.dart: -------------------------------------------------------------------------------- 1 | export 'dart:async'; 2 | export 'dart:convert'; 3 | 4 | export 'package:collection/collection.dart'; 5 | 6 | export 'dev_utils.dart'; 7 | -------------------------------------------------------------------------------- /sqflite/example/lib/src/dev_utils.dart: -------------------------------------------------------------------------------- 1 | export 'dart:async'; 2 | 3 | /// Deprecated to prevent keeping the code used. 4 | @deprecated 5 | void devPrint(Object object) { 6 | print(object); 7 | } 8 | 9 | /// Deprecated to prevent keeping the code used. 10 | /// 11 | /// Can be use as a todo for weird code. int value = devWarning(myFunction()); 12 | /// The function is always called 13 | @deprecated 14 | T devWarning(T value) => value; 15 | -------------------------------------------------------------------------------- /sqflite/example/lib/src/expect.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | 7 | import 'package:matcher/matcher.dart'; 8 | 9 | /// An exception thrown when a test assertion fails. 10 | class TestFailure extends Error { 11 | /// An exception thrown when a test assertion fails. 12 | TestFailure(this.message); 13 | 14 | /// Exception message 15 | final String message; 16 | 17 | @override 18 | String toString() => message; 19 | } 20 | 21 | /// The type used for functions that can be used to build up error reports 22 | /// upon failures in [expect]. 23 | @Deprecated('Will be removed in 0.13.0.') 24 | typedef ErrorFormatter = String Function(dynamic actual, Matcher matcher, 25 | String? reason, Map matchState, bool verbose); 26 | 27 | /// Assert that [actual] matches [matcher]. 28 | /// 29 | /// This is the main assertion function. [reason] is optional and is typically 30 | /// not supplied, as a reason is generated from [matcher]; if [reason] 31 | /// is included it is appended to the reason generated by the matcher. 32 | /// 33 | /// [matcher] can be a value in which case it will be wrapped in an 34 | /// [equals] matcher. 35 | /// 36 | /// If the assertion fails a [TestFailure] is thrown. 37 | /// 38 | /// If [skip] is a String or `true`, the assertion is skipped. The arguments are 39 | /// still evaluated, but [actual] is not verified to match [matcher]. If 40 | /// [actual] is a [Future], the test won't complete until the future emits a 41 | /// value. 42 | /// 43 | /// If [skip] is a string, it should explain why the assertion is skipped; this 44 | /// reason will be printed when running the test. 45 | /// 46 | /// Certain matchers, like [completion] and [throwsA], either match or fail 47 | /// asynchronously. When you use [expect] with these matchers, it ensures that 48 | /// the test doesn't complete until the matcher has either matched or failed. If 49 | /// you want to wait for the matcher to complete before continuing the test, you 50 | /// can call [expectLater] instead and `await` the result. 51 | void expect( 52 | actual, 53 | matcher, { 54 | String? reason, 55 | skip, 56 | }) { 57 | _expect(actual, matcher, reason: reason, skip: skip); 58 | } 59 | 60 | /// Just like [expect], but returns a [Future] that completes when the matcher 61 | /// has finished matching. 62 | /// 63 | /// For the [completes] and [completion] matchers, as well as [throwsA] and 64 | /// related matchers when they're matched against a [Future], the returned 65 | /// future completes when the matched future completes. For the [prints] 66 | /// matcher, it completes when the future returned by the callback completes. 67 | /// Otherwise, it completes immediately. 68 | /// 69 | /// If the matcher fails asynchronously, that failure is piped to the returned 70 | /// future where it can be handled by user code. 71 | Future expectLater(actual, matcher, {String? reason, skip}) => 72 | _expect(actual, matcher, reason: reason, skip: skip); 73 | 74 | String _formatFailure(Matcher expected, actual, String which, {String? reason}) { 75 | var buffer = StringBuffer(); 76 | buffer.writeln(indent(prettyPrint(expected), first: 'Expected: ')); 77 | buffer.writeln(indent(prettyPrint(actual), first: ' Actual: ')); 78 | if (which.isNotEmpty) buffer.writeln(indent(which, first: ' Which: ')); 79 | if (reason != null) buffer.writeln(reason); 80 | return buffer.toString(); 81 | } 82 | 83 | /// The implementation of [expect] and [expectLater]. 84 | Future _expect(actual, matcher, 85 | {String? reason, 86 | skip, 87 | bool verbose = false, 88 | // ignore: deprecated_member_use, deprecated_member_use_from_same_package 89 | ErrorFormatter? formatter}) async { 90 | formatter ??= (actual, matcher, reason, matchState, verbose) { 91 | var mismatchDescription = StringDescription(); 92 | matcher.describeMismatch(actual, mismatchDescription, matchState, verbose); 93 | 94 | // ignore: deprecated_member_use 95 | return _formatFailure(matcher, actual, mismatchDescription.toString(), 96 | reason: reason); 97 | }; 98 | 99 | if (skip != null && skip is! bool && skip is! String) { 100 | throw ArgumentError.value(skip, 'skip', 'must be a bool or a String'); 101 | } 102 | 103 | matcher = wrapMatcher(matcher); 104 | 105 | var matchState = {}; 106 | try { 107 | if ((matcher as Matcher).matches(actual, matchState)) { 108 | return Future.sync(() {}); 109 | } 110 | } catch (e, trace) { 111 | reason ??= '$e at $trace'; 112 | } 113 | 114 | final errorStr = formatter(actual, matcher as Matcher, reason, matchState, verbose); 115 | print('Error str: $errorStr'); 116 | fail(errorStr); 117 | } 118 | 119 | /// Convenience method for throwing a new [TestFailure] with the provided 120 | /// [message]. 121 | Never fail([String? message]) => throw TestFailure(message ?? 'should fail'); 122 | 123 | /// index text helper. 124 | String indent(String text, {String? first}) { 125 | if (first != null) { 126 | return '$first $text'; 127 | } 128 | return '$text'; 129 | } 130 | 131 | /// index text helper. 132 | String prettyPrint(dynamic text, {String? first}) { 133 | if (first != null) { 134 | return '$first $text'; 135 | } 136 | return '$text'; 137 | } 138 | 139 | /// The default error formatter. 140 | @Deprecated('Will be removed in 0.13.0.') 141 | String formatFailure(Matcher expected, actual, String which, {String? reason}) { 142 | var buffer = StringBuffer(); 143 | buffer.writeln(indent(prettyPrint(expected), first: 'Expected: ')); 144 | buffer.writeln(indent(prettyPrint(actual), first: ' Actual: ')); 145 | if (which.isNotEmpty) buffer.writeln(indent(which, first: ' Which: ')); 146 | if (reason != null) buffer.writeln(reason); 147 | return buffer.toString(); 148 | } 149 | -------------------------------------------------------------------------------- /sqflite/example/lib/src/item_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../model/item.dart'; 4 | 5 | /// Item widget. 6 | class ItemWidget extends StatefulWidget { 7 | /// Item widget. 8 | ItemWidget(this.item, this.onTap, {this.summary}); 9 | 10 | /// item summary. 11 | final String? summary; 12 | 13 | /// item data. 14 | final Item item; 15 | 16 | /// Action when pressed (typically run). 17 | final Function onTap; // = Function(MainItem item); 18 | 19 | @override 20 | _ItemWidgetState createState() => _ItemWidgetState(); 21 | } 22 | 23 | class _ItemWidgetState extends State { 24 | @override 25 | Widget build(BuildContext context) { 26 | IconData? icon; 27 | Color? color; 28 | 29 | switch (widget.item.state) { 30 | case ItemState.none: 31 | icon = Icons.arrow_forward_ios; 32 | break; 33 | case ItemState.running: 34 | icon = Icons.more_horiz; 35 | break; 36 | case ItemState.success: 37 | icon = Icons.check; 38 | color = Colors.green; 39 | break; 40 | case ItemState.failure: 41 | icon = Icons.close; 42 | color = Colors.red; 43 | break; 44 | } 45 | return ListTile( 46 | // isThreeLine: widget.summary != null, 47 | leading: SizedBox( 48 | child: IconButton( 49 | icon: Icon(icon, color: color), 50 | 51 | onPressed: null, // null disables the button 52 | )), 53 | title: Text(widget.item.name), 54 | subtitle: widget.summary != null ? Text(widget.summary!) : null, 55 | onTap: _onTap); 56 | } 57 | 58 | void _onTap() { 59 | widget.onTap(widget.item); 60 | 61 | //print(widget.item.route); 62 | //Navigator.pushNamed(context, widget.item.route); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /sqflite/example/lib/src/main_item_widget.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | 3 | import '../model/main_item.dart'; 4 | 5 | /// Main item widget. 6 | class MainItemWidget extends StatefulWidget { 7 | /// Main item widget. 8 | MainItemWidget(this.item, this.onTap); 9 | 10 | /// item data. 11 | final MainItem item; 12 | 13 | /// onTap action (typically run or open). 14 | final Function onTap; // = Function(MainItem item); 15 | 16 | @override 17 | _MainItemWidgetState createState() => _MainItemWidgetState(); 18 | } 19 | 20 | class _MainItemWidgetState extends State { 21 | @override 22 | Widget build(BuildContext context) { 23 | return ListTile( 24 | title: Text(widget.item.title), 25 | subtitle: Text(widget.item.description), 26 | onTap: _onTap); 27 | } 28 | 29 | void _onTap() { 30 | widget.onTap(widget.item); 31 | 32 | //print(widget.item.route); 33 | //Navigator.pushNamed(context, widget.item.route); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sqflite/example/lib/test_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter/material.dart'; 4 | import 'package:sqflite_sqlcipher_example/src/common_import.dart'; 5 | import 'package:sqflite_sqlcipher_example/src/expect.dart'; 6 | 7 | import 'model/item.dart'; 8 | import 'model/test.dart'; 9 | import 'src/item_widget.dart'; 10 | 11 | export 'package:matcher/matcher.dart'; 12 | export 'package:sqflite_sqlcipher_example/database/database.dart'; 13 | 14 | export 'src/expect.dart' show expect, fail; 15 | 16 | /// Base test page. 17 | class TestPage extends StatefulWidget { 18 | /// Base test page. 19 | TestPage(this.title); 20 | 21 | /// The title. 22 | final String title; 23 | 24 | /// Test list. 25 | final List tests = []; 26 | 27 | /// define a test. 28 | void test(String name, FutureOr Function() fn) { 29 | tests.add(Test(name, fn)); 30 | } 31 | 32 | /// define a solo test. 33 | @Deprecated('SOLO_TEST - On purpose to remove before checkin') 34 | void solo_test(String name, FutureOr Function() fn) { 35 | tests.add(Test(name, fn, solo: true)); 36 | } 37 | 38 | /// skip a test. 39 | @Deprecated('SKIP_TEST - On purpose to remove before checkin') 40 | void skip_test(String name, FutureOr Function() fn) { 41 | tests.add(Test(name, fn, skip: true)); 42 | } 43 | 44 | /// Thrown an exception 45 | void fail([String? message]) { 46 | throw Exception(message ?? 'should fail'); 47 | } 48 | 49 | @override 50 | _TestPageState createState() => _TestPageState(); 51 | } 52 | 53 | /// Verify a condition. 54 | bool? verify(bool? condition, [String? message]) { 55 | message ??= 'verify failed'; 56 | expect(condition, true, reason: message); 57 | /* 58 | if (condition == null) { 59 | throw new Exception(''$message' null condition'); 60 | } 61 | if (!condition) { 62 | throw new Exception(''$message''); 63 | } 64 | */ 65 | return condition; 66 | } 67 | 68 | /// Group. 69 | abstract mixin class Group { 70 | /// List of tests. 71 | List get tests; 72 | 73 | bool? _hasSolo; 74 | final _tests = []; 75 | 76 | /// Add a test. 77 | void add(Test test) { 78 | if (!test.skip) { 79 | if (test.solo) { 80 | if (_hasSolo != true) { 81 | _hasSolo = true; 82 | _tests.clear(); 83 | } 84 | _tests.add(test); 85 | } else if (_hasSolo != true) { 86 | _tests.add(test); 87 | } 88 | } 89 | } 90 | 91 | /// true if it has solo or contains item with solo feature 92 | bool? get hasSolo => _hasSolo; 93 | } 94 | 95 | class _TestPageState extends State with Group { 96 | int get _itemCount => items.length; 97 | 98 | List items = []; 99 | 100 | Future _run() async { 101 | if (!mounted) { 102 | return null; 103 | } 104 | 105 | setState(() { 106 | items.clear(); 107 | }); 108 | _tests.clear(); 109 | for (var test in widget.tests) { 110 | add(test); 111 | } 112 | for (var test in _tests) { 113 | var item = Item('${test.name}'); 114 | 115 | late int position; 116 | setState(() { 117 | position = items.length; 118 | items.add(item); 119 | }); 120 | await runZonedGuarded( 121 | () async { 122 | await test.fn(); 123 | item = Item('${test.name}')..state = ItemState.success; 124 | }, 125 | (e, st) { 126 | print(e); 127 | print(st); 128 | item = Item('${test.name}')..state = ItemState.failure; 129 | 130 | if (!mounted) { 131 | return null; 132 | } 133 | setState(() { 134 | items[position] = item; 135 | }); 136 | }, 137 | ); 138 | 139 | if (!mounted) { 140 | return null; 141 | } 142 | 143 | setState(() { 144 | items[position] = item; 145 | }); 146 | } 147 | } 148 | 149 | Future _runTest(int index) async { 150 | if (!mounted) { 151 | return null; 152 | } 153 | 154 | var test = _tests[index]; 155 | 156 | var item = items[index]; 157 | setState(() { 158 | item.state = ItemState.running; 159 | }); 160 | try { 161 | print('TEST Running ${test.name}'); 162 | await test.fn(); 163 | print('TEST Done ${test.name}'); 164 | 165 | item = Item('${test.name}')..state = ItemState.success; 166 | } catch (e, st) { 167 | print('TEST Error $e running ${test.name}'); 168 | try { 169 | print(st); 170 | } catch (_) {} 171 | item = Item('${test.name}')..state = ItemState.failure; 172 | } 173 | 174 | if (!mounted) { 175 | return null; 176 | } 177 | 178 | setState(() { 179 | items[index] = item; 180 | }); 181 | } 182 | 183 | @override 184 | void initState() { 185 | super.initState(); 186 | /* 187 | setState(() { 188 | _itemCount = 3; 189 | }); 190 | */ 191 | _run(); 192 | } 193 | 194 | @override 195 | Widget build(BuildContext context) { 196 | return Scaffold( 197 | appBar: AppBar(title: Text(widget.title), actions: [ 198 | IconButton( 199 | icon: Icon(Icons.refresh), 200 | tooltip: 'Run again', 201 | onPressed: _run, 202 | ), 203 | ]), 204 | body: 205 | ListView.builder(itemBuilder: _itemBuilder, itemCount: _itemCount)); 206 | } 207 | 208 | Widget _itemBuilder(BuildContext context, int index) { 209 | var item = getItem(index); 210 | return ItemWidget(item, (Item item) { 211 | //Navigator.of(context).pushNamed(item.route); 212 | _runTest(index); 213 | }); 214 | } 215 | 216 | Item getItem(int index) { 217 | return items[index]; 218 | } 219 | 220 | @override 221 | List get tests => widget.tests; 222 | } 223 | -------------------------------------------------------------------------------- /sqflite/example/lib/todo_test_page.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:sqflite_sqlcipher/sqflite.dart'; 4 | 5 | import 'test_page.dart'; 6 | 7 | /// `todo` table name 8 | final String tableTodo = 'todo'; 9 | 10 | /// id column name 11 | final String columnId = '_id'; 12 | 13 | /// title column name 14 | final String columnTitle = 'title'; 15 | 16 | /// done column name 17 | final String columnDone = 'done'; 18 | 19 | /// Todo model. 20 | class Todo { 21 | /// Todo model. 22 | Todo(); 23 | 24 | /// Read from a record. 25 | Todo.fromMap(Map map) { 26 | id = map[columnId] as int?; 27 | title = map[columnTitle] as String?; 28 | done = map[columnDone] == 1; 29 | } 30 | 31 | /// id. 32 | int? id; 33 | 34 | /// title. 35 | String? title; 36 | 37 | /// done. 38 | bool? done; 39 | 40 | /// Convert to a record. 41 | Map toMap() { 42 | var map = { 43 | columnTitle: title, 44 | columnDone: done == true ? 1 : 0 45 | }; 46 | if (id != null) { 47 | map[columnId] = id; 48 | } 49 | return map; 50 | } 51 | } 52 | 53 | /// Todo provider. 54 | class TodoProvider { 55 | /// The database when opened. 56 | late Database db; 57 | 58 | /// Open the database. 59 | Future open(String path) async { 60 | db = await openDatabase(path, version: 1, 61 | onCreate: (Database db, int version) async { 62 | await db.execute(''' 63 | create table $tableTodo ( 64 | $columnId integer primary key autoincrement, 65 | $columnTitle text not null, 66 | $columnDone integer not null) 67 | '''); 68 | }); 69 | } 70 | 71 | /// Insert a todo. 72 | Future insert(Todo todo) async { 73 | todo.id = await db.insert(tableTodo, todo.toMap()); 74 | return todo; 75 | } 76 | 77 | /// Get a todo. 78 | Future getTodo(int id) async { 79 | List maps = await db.query(tableTodo, 80 | columns: [columnId, columnDone, columnTitle], 81 | where: '$columnId = ?', 82 | whereArgs: [id]); 83 | if (maps.isNotEmpty) { 84 | return Todo.fromMap(maps.first); 85 | } 86 | return null; 87 | } 88 | 89 | /// Delete a todo. 90 | Future delete(int id) async { 91 | return await db.delete(tableTodo, where: '$columnId = ?', whereArgs: [id]); 92 | } 93 | 94 | /// Update a todo. 95 | Future update(Todo todo) async { 96 | return await db.update(tableTodo, todo.toMap(), 97 | where: '$columnId = ?', whereArgs: [todo.id!]); 98 | } 99 | 100 | /// Close database. 101 | Future close() async => db.close(); 102 | } 103 | 104 | /// Todo test page. 105 | class TodoTestPage extends TestPage { 106 | /// Todo test page. 107 | TodoTestPage() : super('Todo example') { 108 | test('open', () async { 109 | // await Sqflite.devSetDebugModeOn(true); 110 | var path = await initDeleteDb('simple_todo_open.db'); 111 | var todoProvider = TodoProvider(); 112 | await todoProvider.open(path); 113 | 114 | await todoProvider.close(); 115 | //await Sqflite.setDebugModeOn(false); 116 | }); 117 | 118 | test('insert/query/update/delete', () async { 119 | // await Sqflite.devSetDebugModeOn(); 120 | var path = await initDeleteDb('simple_todo.db'); 121 | var todoProvider = TodoProvider(); 122 | await todoProvider.open(path); 123 | 124 | var todo = Todo()..title = 'test'; 125 | await todoProvider.insert(todo); 126 | expect(todo.id, 1); 127 | 128 | expect(await todoProvider.getTodo(0), null); 129 | todo = (await todoProvider.getTodo(1))!; 130 | expect(todo.id, 1); 131 | expect(todo.title, 'test'); 132 | expect(todo.done, false); 133 | 134 | todo.done = true; 135 | expect(await todoProvider.update(todo), 1); 136 | todo = (await todoProvider.getTodo(1))!; 137 | expect(todo.id, 1); 138 | expect(todo.title, 'test'); 139 | expect(todo.done, true); 140 | 141 | expect(await todoProvider.delete(0), 0); 142 | expect(await todoProvider.delete(1), 1); 143 | expect(await todoProvider.getTodo(1), null); 144 | 145 | await todoProvider.close(); 146 | //await Sqflite.setDebugModeOn(false); 147 | }); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /sqflite/example/lib/utils.dart: -------------------------------------------------------------------------------- 1 | export 'dart:io' hide sleep; 2 | 3 | /// Usage: await sleep(500); 4 | Future sleep(int milliseconds) => 5 | Future.delayed(Duration(milliseconds: milliseconds)); 6 | -------------------------------------------------------------------------------- /sqflite/example/macos/.gitignore: -------------------------------------------------------------------------------- 1 | # Flutter-related 2 | **/Flutter/ephemeral/ 3 | **/Pods/ 4 | 5 | # Xcode-related 6 | **/dgph 7 | **/xcuserdata/ 8 | -------------------------------------------------------------------------------- /sqflite/example/macos/Flutter/Flutter-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/macos/Flutter/Flutter-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "ephemeral/Flutter-Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/macos/Flutter/GeneratedPluginRegistrant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Generated file. Do not edit. 3 | // 4 | 5 | import FlutterMacOS 6 | import Foundation 7 | 8 | import sqflite 9 | import sqflite_sqlcipher 10 | 11 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { 12 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) 13 | SqfliteSqlCipherPlugin.register(with: registry.registrar(forPlugin: "SqfliteSqlCipherPlugin")) 14 | } 15 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | @NSApplicationMain 5 | class AppDelegate: FlutterAppDelegate { 6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 7 | return true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "app_icon_16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "app_icon_32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "app_icon_32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "app_icon_64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "app_icon_128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "app_icon_256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "app_icon_256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "app_icon_512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "app_icon_512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "app_icon_1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/example/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Configs/AppInfo.xcconfig: -------------------------------------------------------------------------------- 1 | // Application-level settings for the Runner target. 2 | // 3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the 4 | // future. If not, the values below would default to using the project name when this becomes a 5 | // 'flutter create' template. 6 | 7 | // The application's name. By default this is also the title of the Flutter window. 8 | PRODUCT_NAME = example 9 | 10 | // The application's bundle identifier 11 | PRODUCT_BUNDLE_IDENTIFIER = com.davidmartos96.example 12 | 13 | // The copyright displayed in application information 14 | PRODUCT_COPYRIGHT = Copyright © 2024 com.davidmartos96. All rights reserved. 15 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Configs/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Debug.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Configs/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "../../Flutter/Flutter-Release.xcconfig" 2 | #include "Warnings.xcconfig" 3 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Configs/Warnings.xcconfig: -------------------------------------------------------------------------------- 1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings 2 | GCC_WARN_UNDECLARED_SELECTOR = YES 3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES 4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 6 | CLANG_WARN_PRAGMA_PACK = YES 7 | CLANG_WARN_STRICT_PROTOTYPES = YES 8 | CLANG_WARN_COMMA = YES 9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES 10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES 11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 12 | GCC_WARN_SHADOW = YES 13 | CLANG_WARN_UNREACHABLE_CODE = YES 14 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/DebugProfile.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | com.apple.security.network.server 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSMinimumSystemVersion 24 | $(MACOSX_DEPLOYMENT_TARGET) 25 | NSHumanReadableCopyright 26 | $(PRODUCT_COPYRIGHT) 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/MainFlutterWindow.swift: -------------------------------------------------------------------------------- 1 | import Cocoa 2 | import FlutterMacOS 3 | 4 | class MainFlutterWindow: NSWindow { 5 | override func awakeFromNib() { 6 | let flutterViewController = FlutterViewController() 7 | let windowFrame = self.frame 8 | self.contentViewController = flutterViewController 9 | self.setFrame(windowFrame, display: true) 10 | 11 | RegisterGeneratedPlugins(registry: flutterViewController) 12 | 13 | super.awakeFromNib() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /sqflite/example/macos/Runner/Release.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sqflite/example/macos/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import FlutterMacOS 2 | import Cocoa 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /sqflite/example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: sqflite_sqlcipher_example 2 | description: Demonstrates how to use the sqflite plugin. 3 | publish_to: none 4 | version: "0.2.0" 5 | 6 | environment: 7 | sdk: '>=3.3.0 <4.0.0' 8 | 9 | dependencies: 10 | path: any 11 | collection: any 12 | flutter: 13 | sdk: flutter 14 | matcher: ^0.12.16 15 | sqflite_sqlcipher: 16 | path: ../ 17 | sqflite: ^2.3.2 18 | synchronized: any 19 | 20 | dev_dependencies: 21 | flutter_test: 22 | sdk: flutter 23 | flutter_driver: 24 | sdk: flutter 25 | integration_test: 26 | sdk: flutter 27 | test: 28 | pedantic: ">=1.4.0 <3.0.0" 29 | process_run: ">=0.10.0" 30 | 31 | # For information on the generic Dart part of this file, see the 32 | # following page: https://www.dartlang.org/tools/pub/pubspec 33 | 34 | # The following section is specific to Flutter. 35 | flutter: 36 | # The following line ensures that the Material Icons font is 37 | # included with your application, so that you can use the icons in 38 | # the Icons class. 39 | uses-material-design: true 40 | 41 | # To add assets to your application, add an assets section here, in 42 | # this "flutter" section, as in: 43 | # assets: 44 | # - images/a_dot_burr.jpeg 45 | # - images/a_dot_ham.jpeg 46 | assets: 47 | - assets/example.db 48 | - assets/example_pass_1234.db 49 | - assets/sqlcipher-3.0-testkey.db 50 | - assets/issue_64.db 51 | 52 | dependency_overrides: 53 | sqflite_sqlcipher: 54 | path: ../ 55 | -------------------------------------------------------------------------------- /sqflite/example/test/database_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | 3 | void main() { 4 | group('database', () { 5 | test('open', () async { 6 | // Can't do unit test flutter plugin yet 7 | }); 8 | }); 9 | } 10 | -------------------------------------------------------------------------------- /sqflite/example/test/main/test_main.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher_example/main.dart' as app; 2 | import 'package:sqflite_sqlcipher_example/main.dart'; 3 | 4 | Future main() async { 5 | // ignore_for_file: deprecated_member_use, deprecated_member_use_from_same_package 6 | // debugAutoStartRouteName = testExceptionRoute; 7 | // debugAutoStartRouteName = testOpenRoute; 8 | debugAutoStartRouteName = testManualRoute; 9 | // debugAutoStartRouteName = testRawRoute; 10 | // debugAutoStartRouteName = testTypeRoute; 11 | // debugAutoStartRouteName = testExpRoute; 12 | 13 | app.main(); 14 | } 15 | -------------------------------------------------------------------------------- /sqflite/example/test/model_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_test/flutter_test.dart'; 2 | import 'package:sqflite_sqlcipher_example/model/test.dart'; 3 | 4 | void main() { 5 | group('model', () { 6 | test('test_sync', () async { 7 | var ran = false; 8 | var test = Test('test', () { 9 | ran = true; 10 | }); 11 | await test.fn(); 12 | expect(ran, isTrue); 13 | }); 14 | 15 | test('test_async', () async { 16 | var ran = false; 17 | var test = Test('test', () async { 18 | ran = true; 19 | }); 20 | await test.fn(); 21 | expect(ran, isTrue); 22 | }); 23 | }); 24 | } 25 | -------------------------------------------------------------------------------- /sqflite/example/test/sqflite_e2e.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019, the Chromium project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:io'; 6 | 7 | import 'package:flutter_test/flutter_test.dart'; 8 | import 'package:integration_test/integration_test.dart'; 9 | import 'package:path/path.dart'; 10 | import 'package:sqflite_sqlcipher/sqflite.dart'; 11 | // import 'sqflite_impl_test.dart' show devVerbose; 12 | 13 | void main() { 14 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 15 | 16 | group('sqflite', () { 17 | group('open', () { 18 | test('missing directory', () async { 19 | //await devVerbose(); 20 | var path = join('test_missing_sub_dir', 'simple.db'); 21 | try { 22 | await Directory(join(await getDatabasesPath(), dirname(path))) 23 | .delete(recursive: true); 24 | } catch (_) {} 25 | var db = 26 | await openDatabase(path, version: 1, onCreate: (db, version) async { 27 | expect(await db.getVersion(), 0); 28 | }); 29 | expect(await db.getVersion(), 1); 30 | await db.close(); 31 | }); 32 | test('failure', () { 33 | // This one seems ignored 34 | // fail('regular test failure'); 35 | }); 36 | test('in_memory', () async { 37 | var db = await openDatabase(inMemoryDatabasePath, version: 1, 38 | onCreate: (db, version) async { 39 | expect(await db.getVersion(), 0); 40 | }); 41 | expect(await db.getVersion(), 1); 42 | await db.close(); 43 | }); 44 | }); 45 | }); 46 | 47 | testWidgets('widget_test', (WidgetTester tester) async { 48 | //await devVerbose(); 49 | var path = join('widget_test_missing_sub_dir', 'simple.db'); 50 | try { 51 | await Directory(join(await getDatabasesPath(), dirname(path))) 52 | .delete(recursive: true); 53 | } catch (_) {} 54 | var db = 55 | await openDatabase(path, version: 1, onCreate: (db, version) async { 56 | expect(await db.getVersion(), 0); 57 | }); 58 | expect(await db.getVersion(), 1); 59 | await db.close(); 60 | }); 61 | testWidgets('widget_test_failure', (WidgetTester tester) async { 62 | // This fails 63 | // fail('widget test_failure'); 64 | }); 65 | } 66 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/main.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:flutter_driver/driver_extension.dart'; 4 | import 'package:flutter_test/flutter_test.dart'; 5 | import 'package:sqflite_sqlcipher_example/src/common_import.dart'; 6 | 7 | import 'sqflite_impl_test.dart' as sqflite_impl_test; 8 | import 'sqflite_test.dart' as sqflite_test; 9 | 10 | void main() { 11 | final completer = Completer(); 12 | enableFlutterDriverExtension(handler: (_) => completer.future); 13 | tearDownAll(() => completer.complete('')); 14 | 15 | group('driver', () { 16 | sqflite_test.main(); 17 | sqflite_impl_test.main(); 18 | }); 19 | } 20 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/main_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_driver/flutter_driver.dart'; 2 | import 'package:test/test.dart'; 3 | 4 | void main() { 5 | test('Sqflite driver test', () async { 6 | final driver = await FlutterDriver.connect(); 7 | await driver.requestData(null, timeout: const Duration(minutes: 1)); 8 | await driver.close(); 9 | }); 10 | } 11 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/sqflite_e2e.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019, the Chromium project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:io'; 6 | 7 | import 'package:flutter_test/flutter_test.dart'; 8 | import 'package:integration_test/integration_test.dart'; 9 | import 'package:path/path.dart'; 10 | import 'package:sqflite_sqlcipher/sqflite.dart'; 11 | // import 'sqflite_impl_test.dart' show devVerbose; 12 | 13 | void main() { 14 | IntegrationTestWidgetsFlutterBinding.ensureInitialized(); 15 | 16 | group('sqflite', () { 17 | group('open', () { 18 | test('missing directory', () async { 19 | //await devVerbose(); 20 | var path = join('test_missing_sub_dir', 'simple.db'); 21 | try { 22 | await Directory(join(await getDatabasesPath(), dirname(path))) 23 | .delete(recursive: true); 24 | } catch (_) {} 25 | var db = 26 | await openDatabase(path, version: 1, onCreate: (db, version) async { 27 | expect(await db.getVersion(), 0); 28 | }); 29 | expect(await db.getVersion(), 1); 30 | await db.close(); 31 | }); 32 | }); 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/sqflite_e2e_test.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2019, the Chromium project authors. Please see the AUTHORS file 2 | // for details. All rights reserved. Use of this source code is governed by a 3 | // BSD-style license that can be found in the LICENSE file. 4 | 5 | import 'dart:async'; 6 | import 'dart:io'; 7 | import 'package:flutter_driver/flutter_driver.dart'; 8 | 9 | Future main() async { 10 | final driver = await FlutterDriver.connect(); 11 | final result = 12 | await driver.requestData(null, timeout: const Duration(minutes: 1)); 13 | await driver.close(); 14 | exit(result == 'pass' ? 0 : 1); 15 | } 16 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/sqflite_impl_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:path/path.dart'; 2 | import 'package:sqflite_sqlcipher/sqflite.dart'; 3 | import 'package:sqflite_sqlcipher/src/sqflite_import.dart' as impl; 4 | 5 | import 'package:sqflite_sqlcipher_example/utils.dart'; 6 | import 'package:test/test.dart'; 7 | 8 | void main() { 9 | final factory = databaseFactory as impl.SqfliteDatabaseFactoryMixin; 10 | group('impl', () { 11 | if (Platform.isIOS || Platform.isAndroid) { 12 | group('debug_info', () { 13 | 14 | // test('verbose') 15 | 16 | test('simple', () async { 17 | // await devVerbose(); 18 | var path = 'simple.db'; 19 | await deleteDatabase(path); 20 | 21 | var info = await factory.getDebugInfo(); 22 | expect(info.databases, isNull); 23 | 24 | var sw = Stopwatch()..start(); 25 | var db = await openDatabase(path) as impl.SqfliteDatabaseMixin; 26 | expect(db.id, greaterThan(0)); 27 | print('Sqflite opening database: ${sw.elapsed}'); 28 | try { 29 | info = await factory.getDebugInfo(); 30 | expect(info.databases!.length, 1); 31 | var dbInfo = info.databases!.values.first; 32 | expect(dbInfo.singleInstance, isTrue); 33 | expect(dbInfo.path, join(await factory.getDatabasesPath(), path)); 34 | // expect(dbInfo.logLevel, isNull); 35 | 36 | // open again 37 | var previousDb = db; 38 | var id = db.id; 39 | db = await openDatabase(path) as impl.SqfliteDatabaseMixin; 40 | expect(db.id, id); 41 | expect(db, previousDb); 42 | } finally { 43 | sw = Stopwatch()..start(); 44 | await db.close(); 45 | print('Sqflite closing database: ${sw.elapsed}'); 46 | } 47 | 48 | info = await factory.getDebugInfo(); 49 | expect(info.databases, isNull); 50 | 51 | // reopen 52 | var id = db.id!; 53 | sw = Stopwatch()..start(); 54 | var db3 = await openDatabase(path) as impl.SqfliteDatabaseMixin; 55 | print('Sqflite opening database: ${sw.elapsed}'); 56 | try { 57 | expect(db3.id, id + 1); 58 | } finally { 59 | sw = Stopwatch()..start(); 60 | await db3.close(); 61 | print('Sqflite closing database: ${sw.elapsed}'); 62 | 63 | // close again 64 | print('Sqflite closing again'); 65 | await db3.close(); 66 | } 67 | }); 68 | }); 69 | } 70 | }); 71 | } 72 | -------------------------------------------------------------------------------- /sqflite/example/test_driver/sqflite_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:path/path.dart'; 2 | import 'package:pedantic/pedantic.dart'; 3 | import 'package:sqflite_sqlcipher/sqflite.dart'; 4 | import 'package:sqflite_sqlcipher_example/utils.dart'; 5 | import 'package:test/test.dart'; 6 | 7 | void main() { 8 | group('sqflite', () { 9 | test('exists', () async { 10 | expect(await databaseExists(inMemoryDatabasePath), isFalse); 11 | var path = 'test_exists.db'; 12 | await deleteDatabase(path); 13 | expect(await databaseExists(path), isFalse); 14 | var db = await openDatabase(path); 15 | try { 16 | expect(await databaseExists(path), isTrue); 17 | } finally { 18 | await db.close(); 19 | } 20 | }); 21 | test('close in transaction', () async { 22 | // await Sqflite.devSetDebugModeOn(true); 23 | var path = 'test_close_in_transaction.db'; 24 | var factory = databaseFactory; 25 | await deleteDatabase(path); 26 | var db = await factory.openDatabase(path, 27 | options: OpenDatabaseOptions(version: 1)); 28 | try { 29 | await db.execute('BEGIN TRANSACTION'); 30 | await db.close(); 31 | 32 | db = await factory.openDatabase(path, 33 | options: OpenDatabaseOptions(version: 1)); 34 | } finally { 35 | await db.close(); 36 | } 37 | }); 38 | 39 | /// Check if a file is a valid database file 40 | /// 41 | /// An empty file is a valid empty sqlite file 42 | Future isDatabase(String path) async { 43 | Database? db; 44 | var isDatabase = false; 45 | try { 46 | db = await openReadOnlyDatabase(path); 47 | } catch (_) {} finally { 48 | await db?.close(); 49 | } 50 | return isDatabase; 51 | } 52 | 53 | test('read_only missing database', () async { 54 | var path = 'test_missing_database.db'; 55 | await deleteDatabase(path); 56 | try { 57 | var db = await openReadOnlyDatabase(path); 58 | fail('should fail ${db.path}'); 59 | } on DatabaseException catch (_) {} 60 | 61 | expect(await isDatabase(path), isFalse); 62 | }); 63 | 64 | test('read_only empty file', () async { 65 | var path = 'empty_file_database.db'; 66 | await deleteDatabase(path); 67 | var fullPath = join(await getDatabasesPath(), path); 68 | await Directory(dirname(fullPath)).create(recursive: true); 69 | await File(fullPath).writeAsString(''); 70 | 71 | // Open is fine, that is the native behavior 72 | var db = await openReadOnlyDatabase(fullPath); 73 | expect(await File(fullPath).readAsString(), ''); 74 | 75 | await db.getVersion(); 76 | 77 | await db.close(); 78 | expect(await File(fullPath).readAsString(), ''); 79 | expect(await isDatabase(fullPath), isTrue); 80 | }); 81 | 82 | test('read_only missing bad format', () async { 83 | var path = 'test_bad_format_database.db'; 84 | await deleteDatabase(path); 85 | var fullPath = join(await getDatabasesPath(), path); 86 | await Directory(dirname(fullPath)).create(recursive: true); 87 | await File(fullPath).writeAsString('test'); 88 | 89 | expect(await File(fullPath).readAsString(), 'test'); 90 | try { 91 | var db = await openReadOnlyDatabase(fullPath); 92 | await db.close(); 93 | } on DatabaseException catch (_) { 94 | // Android: DatabaseException(file is not a database) 95 | } 96 | expect(await File(fullPath).readAsString(), 'test'); 97 | 98 | expect(await isDatabase(fullPath), isFalse); 99 | expect(await isDatabase(fullPath), isFalse); 100 | 101 | expect(await File(fullPath).readAsString(), 'test'); 102 | }); 103 | 104 | test('multiple database', () async { 105 | //await Sqflite.devSetDebugModeOn(true); 106 | var count = 10; 107 | var dbs = List.filled(count, null); 108 | for (var i = 0; i < count; i++) { 109 | var path = 'test_multiple_$i.db'; 110 | await deleteDatabase(path); 111 | dbs[i] = 112 | await openDatabase(path, version: 1, onCreate: (db, version) async { 113 | await db 114 | .execute('CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT)'); 115 | expect( 116 | await db 117 | .rawInsert('INSERT INTO Test (name) VALUES (?)', ['test_$i']), 118 | 1); 119 | }); 120 | } 121 | 122 | for (var i = 0; i < count; i++) { 123 | var db = dbs[i]!; 124 | try { 125 | var name = (await db.query('Test', columns: ['name'])) 126 | .first 127 | .values 128 | .first as String?; 129 | expect(name, 'test_$i'); 130 | } finally { 131 | await db.close(); 132 | } 133 | } 134 | 135 | for (var i = 0; i < count; i++) { 136 | var db = dbs[i]!; 137 | await db.close(); 138 | } 139 | }); 140 | 141 | test('version', () async { 142 | // await Sqflite.devSetDebugModeOn(true); 143 | var path = 'test_version.db'; 144 | await deleteDatabase(path); 145 | var db = await openDatabase(path, version: 1); 146 | try { 147 | expect(await db.getVersion(), 1); 148 | unawaited(db.close()); 149 | 150 | db = await openDatabase(path, version: 2); 151 | expect(await db.getVersion(), 2); 152 | unawaited(db.close()); 153 | 154 | db = await openDatabase(path, version: 1); 155 | expect(await db.getVersion(), 1); 156 | unawaited(db.close()); 157 | 158 | db = await openDatabase(path, version: 1); 159 | expect(await db.getVersion(), 1); 160 | expect(await isDatabase(path), isTrue); 161 | } finally { 162 | await db.close(); 163 | } 164 | expect(await isDatabase(path), isTrue); 165 | }); 166 | 167 | test('duplicated_column', () async { 168 | // await Sqflite.devSetDebugModeOn(true); 169 | var path = 'test_duplicated_column.db'; 170 | await deleteDatabase(path); 171 | var db = await openDatabase(path); 172 | try { 173 | await db.execute('CREATE TABLE Test (col1 INTEGER, col2 INTEGER)'); 174 | await db.insert('Test', {'col1': 1, 'col2': 2}); 175 | 176 | var result = await db.rawQuery( 177 | 'SELECT t.col1, col1, t.col2, col2 AS col1 FROM Test AS t'); 178 | expect(result, [ 179 | {'col1': 2, 'col2': 2} 180 | ]); 181 | } finally { 182 | await db.close(); 183 | } 184 | }); 185 | 186 | test('indexed_param', () async { 187 | final db = await openDatabase(':memory:'); 188 | expect(await db.rawQuery('SELECT ?1 + ?2', [3, 4]), [ 189 | {'?1 + ?2': 7} 190 | ]); 191 | await db.close(); 192 | }); 193 | 194 | test('deleteDatabase', () async { 195 | // await devVerbose(); 196 | late Database db; 197 | try { 198 | var path = 'test_delete_database.db'; 199 | await deleteDatabase(path); 200 | db = await openDatabase(path); 201 | expect(await db.getVersion(), 0); 202 | await db.setVersion(1); 203 | 204 | // delete without closing every time 205 | await deleteDatabase(path); 206 | db = await openDatabase(path); 207 | expect(await db.getVersion(), 0); 208 | await db.execute('BEGIN TRANSACTION'); 209 | await db.setVersion(2); 210 | 211 | await deleteDatabase(path); 212 | db = await openDatabase(path); 213 | expect(await db.getVersion(), 0); 214 | await db.setVersion(3); 215 | 216 | await deleteDatabase(path); 217 | db = await openDatabase(path); 218 | expect(await db.getVersion(), 0); 219 | } finally { 220 | await db.close(); 221 | } 222 | }); 223 | }); 224 | } 225 | -------------------------------------------------------------------------------- /sqflite/example/tool/android_sqflite_logcat.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | import 'package:sqflite_sqlcipher_example/src/common_import.dart'; 3 | 4 | Future main() async { 5 | final controller = StreamController>(); 6 | final shell = Shell(stdout: controller.sink, verbose: false); 7 | 8 | controller.stream 9 | .transform(utf8.decoder) 10 | .transform(LineSplitter()) 11 | .listen((line) { 12 | if (line.contains('Sqflite')) { 13 | print('$line'); 14 | } 15 | }); 16 | 17 | await shell.run('adb logcat'); 18 | 19 | // We'll never get there actually... 20 | await controller.close(); 21 | } 22 | -------------------------------------------------------------------------------- /sqflite/example/tool/android_uninstall.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | Future main() async { 4 | final shell = Shell(); 5 | 6 | await shell.run(''' 7 | 8 | adb uninstall com.davidmartos96.example 9 | 10 | '''); 11 | } 12 | -------------------------------------------------------------------------------- /sqflite/example/tool/run_e2e_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:path/path.dart'; 2 | import 'package:process_run/shell.dart'; 3 | import 'package:sqflite_sqlcipher_example/utils.dart'; 4 | 5 | Future main() async { 6 | final shell = Shell(); 7 | 8 | // # flutter driver --driver=test_driver/sqflite_e2e_test.dart test_driver/sqflite_e2e.dart 9 | await shell.run('flutter build apk'); 10 | var dir = absolute(Directory.current.path); 11 | var target = join(dir, 'test/sqflite_e2e.dart'); 12 | print(target); 13 | await shell.pushd('android').run(''' 14 | ./gradlew app:connectedAndroidTest -Ptarget=$target 15 | '''); 16 | } 17 | -------------------------------------------------------------------------------- /sqflite/example/tool/run_flutter_driver_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | Future main() async { 4 | final shell = Shell(); 5 | 6 | await shell.run(''' 7 | 8 | flutter driver --target=test_driver/main.dart 9 | 10 | '''); 11 | } 12 | -------------------------------------------------------------------------------- /sqflite/example/tool/travis.dart: -------------------------------------------------------------------------------- 1 | import 'package:path/path.dart'; 2 | import 'package:process_run/shell.dart'; 3 | import 'package:sqflite_sqlcipher_example/utils.dart'; 4 | 5 | import 'run_flutter_driver_test.dart' as driver; 6 | 7 | Future main() async { 8 | final shell = Shell(); 9 | 10 | await shell.run(''' 11 | 12 | flutter analyze 13 | flutter test 14 | 15 | '''); 16 | 17 | Object? exception; 18 | try { 19 | await driver.main(); 20 | } catch (e) { 21 | exception = e; 22 | } 23 | 24 | // For android look for some kind of generated file 25 | if (await Directory(join('build', 'sqflite', 'generated')).exists()) { 26 | if (exception != null) { 27 | throw exception; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sqflite/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | 13 | *.pbxuser 14 | *.mode1v3 15 | *.mode2v3 16 | *.perspectivev3 17 | 18 | !default.pbxuser 19 | !default.mode1v3 20 | !default.mode2v3 21 | !default.perspectivev3 22 | 23 | xcuserdata 24 | 25 | *.moved-aside 26 | 27 | *.pyc 28 | *sync/ 29 | Icon? 30 | .tags* 31 | 32 | Pods/ 33 | Podfile -------------------------------------------------------------------------------- /sqflite/ios/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidmartos96/sqflite_sqlcipher/9bf43091d4c7c6b63bd9f8e3a3715c326f502832/sqflite/ios/Assets/.gitkeep -------------------------------------------------------------------------------- /sqflite/ios/Classes/SqfliteSqlCipherOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Operation.h 3 | // sqflite 4 | // 5 | // Created by Alexandre Roux on 09/01/2018. 6 | // 7 | #import "SqfliteSqlCipherPlugin.h" 8 | 9 | #ifndef SqfliteSqlCipherOperation_h 10 | #define SqfliteSqlCipherOperation_h 11 | 12 | @interface SqfliteSqlCipherOperation : NSObject 13 | 14 | - (NSString*)getMethod; 15 | - (NSString*)getSql; 16 | - (NSArray*)getSqlArguments; 17 | - (NSNumber*)getInTransactionArgument; 18 | - (void)success:(NSObject*)results; 19 | - (void)error:(FlutterError*)error; 20 | - (bool)getNoResult; 21 | - (bool)getContinueOnError; 22 | 23 | @end 24 | 25 | @interface SqfliteSqlCipherBatchOperation : SqfliteSqlCipherOperation 26 | 27 | @property (atomic, retain) NSDictionary* dictionary; 28 | @property (atomic, retain) NSObject* results; 29 | @property (atomic, retain) FlutterError* error; 30 | @property (atomic, assign) bool noResult; 31 | @property (atomic, assign) bool continueOnError; 32 | 33 | - (void)handleSuccess:(NSMutableArray*)results; 34 | - (void)handleErrorContinue:(NSMutableArray*)results; 35 | - (void)handleError:(FlutterResult)result; 36 | 37 | @end 38 | 39 | @interface SqfliteSqlCipherMethodCallOperation : SqfliteSqlCipherOperation 40 | 41 | @property (atomic, retain) FlutterMethodCall* flutterMethodCall; 42 | @property (atomic, assign) FlutterResult flutterResult; 43 | 44 | + (SqfliteSqlCipherMethodCallOperation*)newWithCall:(FlutterMethodCall*)flutterMethodCall result:(FlutterResult)flutterResult; 45 | 46 | @end 47 | 48 | #endif /* SqfliteSqlCipherOperation_h */ 49 | -------------------------------------------------------------------------------- /sqflite/ios/Classes/SqfliteSqlCipherOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // Operation.m 3 | // sqflite 4 | // 5 | // Created by Alexandre Roux on 09/01/2018. 6 | // 7 | 8 | #import 9 | #import "SqfliteSqlCipherOperation.h" 10 | #import "SqfliteSqlCipherPlugin.h" 11 | 12 | // Abstract 13 | @implementation SqfliteSqlCipherOperation 14 | 15 | - (NSString*)getMethod { 16 | return nil; 17 | } 18 | - (NSString*)getSql { 19 | return nil; 20 | } 21 | - (NSArray*)getSqlArguments { 22 | return nil; 23 | } 24 | - (NSNumber*)getInTransactionArgument { 25 | return nil; 26 | } 27 | - (bool)getNoResult { 28 | return false; 29 | } 30 | - (bool)getContinueOnError { 31 | return false; 32 | } 33 | - (void)success:(NSObject*)results {} 34 | 35 | - (void)error:(NSObject*)error {} 36 | 37 | @end 38 | 39 | @implementation SqfliteSqlCipherBatchOperation 40 | 41 | @synthesize dictionary, results, error, noResult, continueOnError; 42 | 43 | - (NSString*)getMethod { 44 | return [dictionary objectForKey:SqfliteSqlCipherParamMethod]; 45 | } 46 | 47 | - (NSString*)getSql { 48 | return [dictionary objectForKey:SqfliteSqlCipherParamSql]; 49 | } 50 | 51 | - (NSArray*)getSqlArguments { 52 | NSArray* arguments = [dictionary objectForKey:SqfliteSqlCipherParamSqlArguments]; 53 | return [SqfliteSqlCipherPlugin toSqlArguments:arguments]; 54 | } 55 | 56 | - (NSNumber*)getInTransactionArgument { 57 | return [dictionary objectForKey:SqfliteSqlCipherParamInTransaction]; 58 | } 59 | 60 | - (bool)getNoResult { 61 | return noResult; 62 | } 63 | 64 | - (bool)getContinueOnError { 65 | return continueOnError; 66 | } 67 | 68 | - (void)success:(NSObject*)results { 69 | self.results = results; 70 | } 71 | 72 | - (void)error:(FlutterError*)error { 73 | self.error = error; 74 | } 75 | 76 | - (void)handleSuccess:(NSMutableArray*)results { 77 | if (![self getNoResult]) { 78 | // We wrap the result in 'result' map 79 | [results addObject:[NSDictionary dictionaryWithObject:((self.results == nil) ? [NSNull null] : self.results) 80 | forKey:SqfliteSqlCipherParamResult]]; 81 | } 82 | } 83 | 84 | // Encore the flutter error in a map 85 | - (void)handleErrorContinue:(NSMutableArray*)results { 86 | if (![self getNoResult]) { 87 | // We wrap the error in an 'error' map 88 | NSMutableDictionary* error = [NSMutableDictionary new]; 89 | error[SqfliteSqlCipherParamErrorCode] = self.error.code; 90 | if (self.error.message != nil) { 91 | error[SqfliteSqlCipherParamErrorMessage] = self.error.message; 92 | } 93 | if (self.error.details != nil) { 94 | error[SqfliteSqlCipherParamErrorData] = self.error.details; 95 | } 96 | [results addObject:[NSDictionary dictionaryWithObject:error 97 | forKey:SqfliteSqlCipherParamError]]; 98 | } 99 | } 100 | 101 | - (void)handleError:(FlutterResult)result { 102 | result(error); 103 | } 104 | 105 | @end 106 | 107 | @implementation SqfliteSqlCipherMethodCallOperation 108 | 109 | @synthesize flutterMethodCall; 110 | @synthesize flutterResult; 111 | 112 | + (SqfliteSqlCipherMethodCallOperation*)newWithCall:(FlutterMethodCall*)flutterMethodCall result:(FlutterResult)flutterResult { 113 | SqfliteSqlCipherMethodCallOperation* operation = [SqfliteSqlCipherMethodCallOperation new]; 114 | operation.flutterMethodCall = flutterMethodCall; 115 | operation.flutterResult = flutterResult; 116 | return operation; 117 | } 118 | 119 | - (NSString*)getMethod { 120 | return flutterMethodCall.method; 121 | } 122 | 123 | - (NSString*)getSql { 124 | return flutterMethodCall.arguments[SqfliteSqlCipherParamSql]; 125 | } 126 | 127 | - (bool)getNoResult { 128 | NSNumber* noResult = flutterMethodCall.arguments[SqfliteSqlCipherParamNoResult]; 129 | return [noResult boolValue]; 130 | } 131 | 132 | - (bool)getContinueOnError { 133 | NSNumber* noResult = flutterMethodCall.arguments[SqfliteSqlCipherParamContinueOnError]; 134 | return [noResult boolValue]; 135 | } 136 | 137 | - (NSArray*)getSqlArguments { 138 | NSArray* arguments = flutterMethodCall.arguments[SqfliteSqlCipherParamSqlArguments]; 139 | return [SqfliteSqlCipherPlugin toSqlArguments:arguments]; 140 | } 141 | 142 | - (NSNumber*)getInTransactionArgument { 143 | return flutterMethodCall.arguments[SqfliteSqlCipherParamInTransaction]; 144 | } 145 | 146 | - (void)success:(NSObject*)results { 147 | flutterResult(results); 148 | } 149 | - (void)error:(NSObject*)error { 150 | flutterResult(error); 151 | } 152 | @end 153 | -------------------------------------------------------------------------------- /sqflite/ios/Classes/SqfliteSqlCipherPlugin.h: -------------------------------------------------------------------------------- 1 | #if TARGET_OS_IPHONE 2 | #import 3 | #else 4 | #import 5 | #endif 6 | 7 | @interface SqfliteSqlCipherPlugin : NSObject 8 | 9 | + (NSArray*)toSqlArguments:(NSArray*)rawArguments; 10 | 11 | @end 12 | 13 | extern NSString *const SqfliteSqlCipherParamMethod; 14 | extern NSString *const SqfliteSqlCipherParamSql; 15 | extern NSString *const SqfliteSqlCipherParamSqlArguments; 16 | extern NSString *const SqfliteSqlCipherParamInTransaction; 17 | extern NSString *const SqfliteSqlCipherParamNoResult; 18 | extern NSString *const SqfliteSqlCipherParamContinueOnError; 19 | extern NSString *const SqfliteSqlCipherParamResult; 20 | extern NSString *const SqfliteSqlCipherParamError; 21 | extern NSString *const SqfliteSqlCipherParamErrorCode; 22 | extern NSString *const SqfliteSqlCipherParamErrorMessage; 23 | extern NSString *const SqfliteSqlCipherParamErrorData; 24 | -------------------------------------------------------------------------------- /sqflite/ios/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTrackingDomains 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | NSPrivacyCollectedDataTypes 10 | 11 | NSPrivacyTracking 12 | 13 | 14 | -------------------------------------------------------------------------------- /sqflite/ios/sqflite_sqlcipher.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'sqflite_sqlcipher' 6 | s.version = '0.0.1' 7 | s.summary = 'SQLite plugin with SqlCipher support.' 8 | s.description = <<-DESC 9 | Access SQLite database. 10 | DESC 11 | s.homepage = 'https://github.com/davidmartos96/sqflite_sqlcipher' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'David' => 'davidmartos96@gmail.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'Flutter' 18 | s.dependency 'FMDB/SQLCipher', '~> 2.7.5' 19 | s.dependency 'SQLCipher', '4.5.7' 20 | 21 | s.platform = :ios, '11.0' 22 | s.ios.deployment_target = '11.0' 23 | s.pod_target_xcconfig = { 24 | 'DEFINES_MODULE' => 'YES', 25 | 'HEADER_SEARCH_PATHS' => 'SQLCipher', 26 | 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' 27 | } 28 | s.resource_bundles = {'sqflite_sqlcipher_ios_privacy' => ['Resources/PrivacyInfo.xcprivacy']} 29 | end 30 | 31 | -------------------------------------------------------------------------------- /sqflite/lib/sqflite.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:sqflite_common/utils/utils.dart' as utils; 4 | import 'package:sqflite_sqlcipher/sqlite_api.dart'; 5 | import 'package:sqflite_sqlcipher/src/factory_sql_cipher_impl.dart' 6 | show databaseFactory; 7 | import 'package:sqflite_sqlcipher/src/sqflite_import.dart' as impl; 8 | import 'package:sqflite_sqlcipher/src/sqflite_import.dart'; 9 | import 'package:sqflite_sqlcipher/src/sqflite_sql_cipher_impl.dart'; 10 | 11 | export 'package:sqflite_sqlcipher/src/factory_sql_cipher_impl.dart' 12 | show databaseFactory; 13 | 14 | export 'sqlite_api.dart'; 15 | 16 | /// 17 | /// sqflite plugin 18 | /// 19 | class Sqflite { 20 | //static MethodChannel get _channel => channel; 21 | 22 | /// deprecated 23 | @Deprecated('internal use only') 24 | static Future get platformVersion => 25 | invokeMethod(methodGetPlatformVersion); 26 | 27 | /// Turns on debug mode if you want to see the SQL query 28 | /// executed natively. 29 | static Future setDebugModeOn([bool on = true]) async { 30 | await invokeMethod(methodSetDebugModeOn, on); 31 | } 32 | 33 | /// Planned Deprecated for 1.1.7 34 | static Future getDebugModeOn() async { 35 | return impl.debugModeOn; 36 | } 37 | 38 | /// deprecated on purpose to remove from code. 39 | /// 40 | /// To use during developpment/debugging 41 | /// Set extra dart and nativate debug logs 42 | @Deprecated('Debug only') 43 | static Future devSetDebugModeOn([bool on = true]) { 44 | impl.debugModeOn = on; 45 | return setDebugModeOn(on); 46 | } 47 | 48 | 49 | /// Testing only 50 | @Deprecated('Testing only') 51 | static Future devInvokeMethod(String method, 52 | [dynamic arguments]) async { 53 | await invokeMethod(method, arguments); 54 | } 55 | 56 | /// helper to get the first int value in a query 57 | /// Useful for COUNT(*) queries 58 | static int? firstIntValue(List> list) => 59 | utils.firstIntValue(list); 60 | 61 | /// Utility to encode a blob to allow blow query using 62 | /// 'hex(blob_field) = ?', Sqlite.hex([1,2,3]) 63 | static String hex(List bytes) => utils.hex(bytes); 64 | 65 | /// Sqlite has a dead lock warning feature that will print some text 66 | /// after 10s, you can override the default behavior 67 | static void setLockWarningInfo( 68 | {Duration? duration, void Function()? callback}) { 69 | utils.setLockWarningInfo(duration: duration, callback: callback); 70 | } 71 | } 72 | 73 | /// 74 | /// Open the database at a given path 75 | /// 76 | /// [version] (optional) specifies the schema version of the database being 77 | /// opened. This is used to decide whether to call [onCreate], [onUpgrade], 78 | /// and [onDowngrade] 79 | /// 80 | /// The optional callbacks are called in the following order: 81 | /// 82 | /// 1. [onConfigure] 83 | /// 2. [onCreate] or [onUpgrade] or [onDowngrade] 84 | /// 5. [onOpen] 85 | /// 86 | /// [onConfigure] is the first callback invoked when opening the database. It 87 | /// allows you to perform database initialization such as enabling foreign keys 88 | /// or write-ahead logging 89 | /// 90 | /// If [version] is specified, [onCreate], [onUpgrade], and [onDowngrade] can 91 | /// be called. These functions are mutually exclusive — only one of them can be 92 | /// called depending on the context, although they can all be specified to 93 | /// cover multiple scenarios 94 | /// 95 | /// [onCreate] is called if the database did not exist prior to calling 96 | /// [openDatabase]. You can use the opportunity to create the required tables 97 | /// in the database according to your schema 98 | /// 99 | /// [onUpgrade] is called if either of the following conditions are met: 100 | /// 101 | /// 1. [onCreate] is not specified 102 | /// 2. The database already exists and [version] is higher than the last 103 | /// database version 104 | /// 105 | /// In the first case where [onCreate] is not specified, [onUpgrade] is called 106 | /// with its [oldVersion] parameter as `0`. In the second case, you can perform 107 | /// the necessary migration procedures to handle the differing schema 108 | /// 109 | /// [onDowngrade] is called only when [version] is lower than the last database 110 | /// version. This is a rare case and should only come up if a newer version of 111 | /// your code has created a database that is then interacted with by an older 112 | /// version of your code. You should try to avoid this scenario 113 | /// 114 | /// [onOpen] is the last optional callback to be invoked. It is called after 115 | /// the database version has been set and before [openDatabase] returns 116 | /// 117 | /// When [readOnly] (false by default) is true, all other parameters are 118 | /// ignored and the database is opened as-is 119 | /// 120 | /// When [singleInstance] is true (the default), a single database instance is 121 | /// returned for a given path. Subsequent calls to [openDatabase] with the 122 | /// same path will return the same instance, and will discard all other 123 | /// parameters such as callbacks for that invocation. 124 | /// 125 | Future openDatabase(String path, 126 | {int? version, 127 | OnDatabaseConfigureFn? onConfigure, 128 | OnDatabaseCreateFn? onCreate, 129 | OnDatabaseVersionChangeFn? onUpgrade, 130 | OnDatabaseVersionChangeFn? onDowngrade, 131 | OnDatabaseOpenFn? onOpen, 132 | String? password, 133 | bool readOnly = false, 134 | bool singleInstance = true}) { 135 | final options = SqlCipherOpenDatabaseOptions( 136 | version: version, 137 | onConfigure: onConfigure, 138 | onCreate: onCreate, 139 | onUpgrade: onUpgrade, 140 | onDowngrade: onDowngrade, 141 | onOpen: onOpen, 142 | password: password, 143 | readOnly: readOnly, 144 | singleInstance: singleInstance); 145 | return databaseFactory.openDatabase(path, options: options); 146 | } 147 | 148 | /// 149 | /// Open the database at a given path in read only mode 150 | /// 151 | Future openReadOnlyDatabase(String path, {String? password}) => 152 | openDatabase(path, readOnly: true, password: password); 153 | 154 | /// 155 | /// Get the default databases location. 156 | /// 157 | /// On Android, it is typically data/data//databases 158 | /// 159 | /// On iOS, it is the Documents directory 160 | /// 161 | Future getDatabasesPath() => databaseFactory.getDatabasesPath(); 162 | 163 | /// 164 | /// Delete the database at the given path. 165 | /// 166 | Future deleteDatabase(String path) => 167 | databaseFactory.deleteDatabase(path); 168 | 169 | /// 170 | /// Check if a database exists at a given path. 171 | /// 172 | Future databaseExists(String path) => 173 | databaseFactory.databaseExists(path); 174 | -------------------------------------------------------------------------------- /sqflite/lib/sql.dart: -------------------------------------------------------------------------------- 1 | // Only export: 2 | // * [ConflictAlgorithm] 3 | // * [escapeName] 4 | // * [unescapeName] 5 | export 'package:sqflite_common/sql.dart'; 6 | -------------------------------------------------------------------------------- /sqflite/lib/sqlite_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_common/sqlite_api.dart'; 2 | import 'package:sqflite_sqlcipher/src/sql_cipher_open_options.dart' as impl; 3 | 4 | export 'package:sqflite_common/sqlite_api.dart'; 5 | 6 | /// 7 | /// Options for opening the database 8 | /// see [openDatabase] for details 9 | /// 10 | abstract class SqlCipherOpenDatabaseOptions extends OpenDatabaseOptions { 11 | /// Open the database at a given path 12 | /// 13 | /// [version] (optional) specifies the schema version of the database being 14 | /// opened. This is used to decide whether to call [onCreate], [onUpgrade], 15 | /// and [onDowngrade] 16 | /// 17 | /// The optional callbacks are called in the following order: 18 | /// 19 | /// 1. [onConfigure] 20 | /// 2. [onCreate] or [onUpgrade] or [onDowngrade] 21 | /// 5. [onOpen] 22 | /// 23 | /// [onConfigure] is the first callback invoked when opening the database. It 24 | /// allows you to perform database initialization such as enabling foreign keys 25 | /// or write-ahead logging 26 | /// 27 | /// If [version] is specified, [onCreate], [onUpgrade], and [onDowngrade] can 28 | /// be called. These functions are mutually exclusive — only one of them can be 29 | /// called depending on the context, although they can all be specified to 30 | /// cover multiple scenarios 31 | /// 32 | /// [onCreate] is called if the database did not exist prior to calling 33 | /// [openDatabase]. You can use the opportunity to create the required tables 34 | /// in the database according to your schema 35 | /// 36 | /// [onUpgrade] is called if either of the following conditions are met: 37 | /// 38 | /// 1. [onCreate] is not specified 39 | /// 2. The database already exists and [version] is higher than the last 40 | /// database version 41 | /// 42 | /// In the first case where [onCreate] is not specified, [onUpgrade] is called 43 | /// with its [oldVersion] parameter as `0`. In the second case, you can perform 44 | /// the necessary migration procedures to handle the differing schema 45 | /// 46 | /// [onDowngrade] is called only when [version] is lower than the last database 47 | /// version. This is a rare case and should only come up if a newer version of 48 | /// your code has created a database that is then interacted with by an older 49 | /// version of your code. You should try to avoid this scenario 50 | /// 51 | /// [onOpen] is the last optional callback to be invoked. It is called after 52 | /// the database version has been set and before [openDatabase] returns 53 | /// 54 | /// When [readOnly] (false by default) is true, all other parameters are 55 | /// ignored and the database is opened as-is 56 | /// 57 | /// When [singleInstance] is true (the default), a single database instance is 58 | /// returned for a given path. Subsequent calls to [openDatabase] with the 59 | /// same path will return the same instance, and will discard all other 60 | /// parameters such as callbacks for that invocation. 61 | /// 62 | /// Specify [password] for encrypted database 63 | /// 64 | factory SqlCipherOpenDatabaseOptions( 65 | {int? version, 66 | OnDatabaseConfigureFn? onConfigure, 67 | OnDatabaseCreateFn? onCreate, 68 | OnDatabaseVersionChangeFn? onUpgrade, 69 | OnDatabaseVersionChangeFn? onDowngrade, 70 | OnDatabaseOpenFn? onOpen, 71 | String? password, 72 | bool readOnly = false, 73 | bool singleInstance = true}) { 74 | return impl.SqfliteSqlCipherOpenDatabaseOptions( 75 | version: version, 76 | onConfigure: onConfigure, 77 | onCreate: onCreate, 78 | onUpgrade: onUpgrade, 79 | onDowngrade: onDowngrade, 80 | onOpen: onOpen, 81 | password: password, 82 | readOnly: readOnly, 83 | singleInstance: singleInstance); 84 | } 85 | 86 | /// Password for encrypted database. 87 | String? password; 88 | } 89 | -------------------------------------------------------------------------------- /sqflite/lib/src/database_sql_cipher_impl.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher/src/sqflite_import.dart'; 2 | import 'package:sqflite_sqlcipher/src/sql_cipher_constant.dart'; 3 | import 'package:sqflite_sqlcipher/src/sql_cipher_open_options.dart'; 4 | 5 | /// Sql Cipher database impl. 6 | class SqfileSqlCipherDatabaseImpl extends SqfliteDatabaseBase { 7 | /// Sql Cipher database ctor. 8 | SqfileSqlCipherDatabaseImpl(SqfliteDatabaseOpenHelper openHelper, String path) 9 | : super(openHelper, path); 10 | 11 | @override 12 | Future invokeMethod(String method, [dynamic arguments]) => 13 | method == methodOpenDatabase 14 | ? _invokeOpenDatabaseMethod(method, arguments) 15 | : factory.invokeMethod(method, arguments); 16 | 17 | Future _invokeOpenDatabaseMethod(String method, [dynamic arguments]) { 18 | // Inject password parameter if needed 19 | final options = this.options; 20 | if (options is SqfliteSqlCipherOpenDatabaseOptions) { 21 | if (options.password != null) { 22 | (arguments as Map)[paramPassword] = options.password; 23 | } 24 | } 25 | return factory.invokeMethod(method, arguments); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sqflite/lib/src/factory_sql_cipher_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:flutter/services.dart'; 4 | import 'package:sqflite_common/sqlite_api.dart'; 5 | import 'package:sqflite_common/src/exception.dart'; // ignore: implementation_imports 6 | import 'package:sqflite_sqlcipher/src/database_sql_cipher_impl.dart'; 7 | 8 | import 'sqflite_import.dart'; 9 | import 'sqflite_sql_cipher_impl.dart'; 10 | 11 | /// Platform error constant 12 | const String sqliteErrorCode = 'sqlite_error'; 13 | 14 | DatabaseFactory? _databaseFactory; 15 | 16 | /// Default factory 17 | DatabaseFactory get databaseFactory => sqlfliteSqlCipherDatabaseFactory; 18 | 19 | /// Default factory 20 | DatabaseFactory get sqlfliteSqlCipherDatabaseFactory => 21 | _databaseFactory ??= SqfliteSqlCipherDatabaseFactoryImpl(invokeMethod); 22 | 23 | /// Factory implementation. 24 | class SqfliteSqlCipherDatabaseFactoryImpl 25 | with SqfliteDatabaseFactoryMixin 26 | implements SqfliteInvokeHandler { 27 | /// Factory ctor. 28 | SqfliteSqlCipherDatabaseFactoryImpl(this._invokeMethod); 29 | 30 | final Future Function(String method, [dynamic arguments]) 31 | _invokeMethod; 32 | 33 | @override 34 | Future invokeMethod(String method, [dynamic arguments]) async => 35 | (await _invokeMethod(method, arguments)) as T; 36 | 37 | @override 38 | Future wrapDatabaseException(Future Function() action) async { 39 | try { 40 | final result = await action(); 41 | return result; 42 | } on PlatformException catch (e) { 43 | if (e.code == sqliteErrorCode) { 44 | throw SqfliteDatabaseException(e.message, e.details); 45 | //rethrow; 46 | } else { 47 | rethrow; 48 | } 49 | } 50 | } 51 | 52 | @override 53 | SqfliteDatabase newDatabase( 54 | SqfliteDatabaseOpenHelper openHelper, String path) { 55 | return SqfileSqlCipherDatabaseImpl(openHelper, path); 56 | } 57 | 58 | /// Optimized but could be removed 59 | @override 60 | Future databaseExists(String path) async { 61 | path = await fixPath(path); 62 | try { 63 | // avoid slow async method 64 | return File(path).existsSync(); 65 | } catch (_) {} 66 | return false; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /sqflite/lib/src/sqflite_import.dart: -------------------------------------------------------------------------------- 1 | // Explicit list of needed private import 2 | export 'package:sqflite_common/src/constant.dart' // ignore: implementation_imports 3 | show 4 | methodOpenDatabase, 5 | methodOptions, 6 | methodGetPlatformVersion, 7 | methodSetDebugModeOn; 8 | export 'package:sqflite_common/src/database.dart' // ignore: implementation_imports 9 | show 10 | SqfliteDatabaseOpenHelper, 11 | SqfliteDatabase; 12 | export 'package:sqflite_common/src/database_mixin.dart' // ignore: implementation_imports 13 | show 14 | SqfliteDatabaseMixin, 15 | SqfliteDatabaseBase; 16 | export 'package:sqflite_common/src/factory_mixin.dart' // ignore: implementation_imports 17 | show 18 | SqfliteDatabaseFactoryMixin; 19 | export 'package:sqflite_common/src/mixin/factory.dart' // ignore: implementation_imports 20 | show 21 | SqfliteInvokeHandler; 22 | export 'package:sqflite_common/src/utils.dart' // ignore: implementation_imports 23 | show 24 | debugModeOn; 25 | -------------------------------------------------------------------------------- /sqflite/lib/src/sqflite_sql_cipher_impl.dart: -------------------------------------------------------------------------------- 1 | import 'dart:core'; 2 | 3 | import 'package:flutter/services.dart'; 4 | 5 | /// Sqflite channel name 6 | const String channelName = 'com.davidmartos96.sqflite_sqlcipher'; 7 | 8 | /// Sqflite channel 9 | const MethodChannel channel = MethodChannel(channelName); 10 | 11 | /// Invoke a native method 12 | Future invokeMethod(String method, [dynamic arguments]) => 13 | channel.invokeMethod(method, arguments); 14 | -------------------------------------------------------------------------------- /sqflite/lib/src/sql_cipher_constant.dart: -------------------------------------------------------------------------------- 1 | /// When opening the database (String) (optional) 2 | const String paramPassword = 'password'; 3 | -------------------------------------------------------------------------------- /sqflite/lib/src/sql_cipher_open_options.dart: -------------------------------------------------------------------------------- 1 | import 'package:sqflite_sqlcipher/sqlite_api.dart'; 2 | 3 | /// 4 | /// Options to open a database 5 | /// See [openDatabase] for details 6 | /// 7 | class SqfliteSqlCipherOpenDatabaseOptions 8 | implements SqlCipherOpenDatabaseOptions { 9 | /// See [openDatabase] for details 10 | SqfliteSqlCipherOpenDatabaseOptions({ 11 | this.version, 12 | this.onConfigure, 13 | this.onCreate, 14 | this.onUpgrade, 15 | this.onDowngrade, 16 | this.onOpen, 17 | this.password, 18 | this.readOnly = false, 19 | this.singleInstance = true, 20 | }); 21 | 22 | @override 23 | int? version; 24 | @override 25 | OnDatabaseConfigureFn? onConfigure; 26 | @override 27 | OnDatabaseCreateFn? onCreate; 28 | @override 29 | OnDatabaseVersionChangeFn? onUpgrade; 30 | @override 31 | OnDatabaseVersionChangeFn? onDowngrade; 32 | @override 33 | OnDatabaseOpenFn? onOpen; 34 | @override 35 | String? password; 36 | @override 37 | bool readOnly; 38 | @override 39 | bool singleInstance; 40 | 41 | @override 42 | String toString() { 43 | final map = {}; 44 | if (version != null) { 45 | map['version'] = version; 46 | } 47 | map['readOnly'] = readOnly; 48 | map['singleInstance'] = singleInstance; 49 | return map.toString(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /sqflite/macos/Classes/SqfliteSqlCipherOperation.h: -------------------------------------------------------------------------------- 1 | // 2 | // Operation.h 3 | // sqflite 4 | // 5 | // Created by Alexandre Roux on 09/01/2018. 6 | // 7 | #import "SqfliteSqlCipherPlugin.h" 8 | 9 | #ifndef SqfliteSqlCipherOperation_h 10 | #define SqfliteSqlCipherOperation_h 11 | 12 | @interface SqfliteSqlCipherOperation : NSObject 13 | 14 | - (NSString*)getMethod; 15 | - (NSString*)getSql; 16 | - (NSArray*)getSqlArguments; 17 | - (NSNumber*)getInTransactionArgument; 18 | - (void)success:(NSObject*)results; 19 | - (void)error:(FlutterError*)error; 20 | - (bool)getNoResult; 21 | - (bool)getContinueOnError; 22 | 23 | @end 24 | 25 | @interface SqfliteSqlCipherBatchOperation : SqfliteSqlCipherOperation 26 | 27 | @property (atomic, retain) NSDictionary* dictionary; 28 | @property (atomic, retain) NSObject* results; 29 | @property (atomic, retain) FlutterError* error; 30 | @property (atomic, assign) bool noResult; 31 | @property (atomic, assign) bool continueOnError; 32 | 33 | - (void)handleSuccess:(NSMutableArray*)results; 34 | - (void)handleErrorContinue:(NSMutableArray*)results; 35 | - (void)handleError:(FlutterResult)result; 36 | 37 | @end 38 | 39 | @interface SqfliteSqlCipherMethodCallOperation : SqfliteSqlCipherOperation 40 | 41 | @property (atomic, retain) FlutterMethodCall* flutterMethodCall; 42 | @property (atomic, assign) FlutterResult flutterResult; 43 | 44 | + (SqfliteSqlCipherMethodCallOperation*)newWithCall:(FlutterMethodCall*)flutterMethodCall result:(FlutterResult)flutterResult; 45 | 46 | @end 47 | 48 | #endif /* SqfliteSqlCipherOperation_h */ 49 | -------------------------------------------------------------------------------- /sqflite/macos/Classes/SqfliteSqlCipherOperation.m: -------------------------------------------------------------------------------- 1 | // 2 | // Operation.m 3 | // sqflite 4 | // 5 | // Created by Alexandre Roux on 09/01/2018. 6 | // 7 | 8 | #import 9 | #import "SqfliteSqlCipherOperation.h" 10 | #import "SqfliteSqlCipherPlugin.h" 11 | 12 | // Abstract 13 | @implementation SqfliteSqlCipherOperation 14 | 15 | - (NSString*)getMethod { 16 | return nil; 17 | } 18 | - (NSString*)getSql { 19 | return nil; 20 | } 21 | - (NSArray*)getSqlArguments { 22 | return nil; 23 | } 24 | - (NSNumber*)getInTransactionArgument { 25 | return nil; 26 | } 27 | - (bool)getNoResult { 28 | return false; 29 | } 30 | - (bool)getContinueOnError { 31 | return false; 32 | } 33 | - (void)success:(NSObject*)results {} 34 | 35 | - (void)error:(NSObject*)error {} 36 | 37 | @end 38 | 39 | @implementation SqfliteSqlCipherBatchOperation 40 | 41 | @synthesize dictionary, results, error, noResult, continueOnError; 42 | 43 | - (NSString*)getMethod { 44 | return [dictionary objectForKey:SqfliteSqlCipherParamMethod]; 45 | } 46 | 47 | - (NSString*)getSql { 48 | return [dictionary objectForKey:SqfliteSqlCipherParamSql]; 49 | } 50 | 51 | - (NSArray*)getSqlArguments { 52 | NSArray* arguments = [dictionary objectForKey:SqfliteSqlCipherParamSqlArguments]; 53 | return [SqfliteSqlCipherPlugin toSqlArguments:arguments]; 54 | } 55 | 56 | - (NSNumber*)getInTransactionArgument { 57 | return [dictionary objectForKey:SqfliteSqlCipherParamInTransaction]; 58 | } 59 | 60 | - (bool)getNoResult { 61 | return noResult; 62 | } 63 | 64 | - (bool)getContinueOnError { 65 | return continueOnError; 66 | } 67 | 68 | - (void)success:(NSObject*)results { 69 | self.results = results; 70 | } 71 | 72 | - (void)error:(FlutterError*)error { 73 | self.error = error; 74 | } 75 | 76 | - (void)handleSuccess:(NSMutableArray*)results { 77 | if (![self getNoResult]) { 78 | // We wrap the result in 'result' map 79 | [results addObject:[NSDictionary dictionaryWithObject:((self.results == nil) ? [NSNull null] : self.results) 80 | forKey:SqfliteSqlCipherParamResult]]; 81 | } 82 | } 83 | 84 | // Encore the flutter error in a map 85 | - (void)handleErrorContinue:(NSMutableArray*)results { 86 | if (![self getNoResult]) { 87 | // We wrap the error in an 'error' map 88 | NSMutableDictionary* error = [NSMutableDictionary new]; 89 | error[SqfliteSqlCipherParamErrorCode] = self.error.code; 90 | if (self.error.message != nil) { 91 | error[SqfliteSqlCipherParamErrorMessage] = self.error.message; 92 | } 93 | if (self.error.details != nil) { 94 | error[SqfliteSqlCipherParamErrorData] = self.error.details; 95 | } 96 | [results addObject:[NSDictionary dictionaryWithObject:error 97 | forKey:SqfliteSqlCipherParamError]]; 98 | } 99 | } 100 | 101 | - (void)handleError:(FlutterResult)result { 102 | result(error); 103 | } 104 | 105 | @end 106 | 107 | @implementation SqfliteSqlCipherMethodCallOperation 108 | 109 | @synthesize flutterMethodCall; 110 | @synthesize flutterResult; 111 | 112 | + (SqfliteSqlCipherMethodCallOperation*)newWithCall:(FlutterMethodCall*)flutterMethodCall result:(FlutterResult)flutterResult { 113 | SqfliteSqlCipherMethodCallOperation* operation = [SqfliteSqlCipherMethodCallOperation new]; 114 | operation.flutterMethodCall = flutterMethodCall; 115 | operation.flutterResult = flutterResult; 116 | return operation; 117 | } 118 | 119 | - (NSString*)getMethod { 120 | return flutterMethodCall.method; 121 | } 122 | 123 | - (NSString*)getSql { 124 | return flutterMethodCall.arguments[SqfliteSqlCipherParamSql]; 125 | } 126 | 127 | - (bool)getNoResult { 128 | NSNumber* noResult = flutterMethodCall.arguments[SqfliteSqlCipherParamNoResult]; 129 | return [noResult boolValue]; 130 | } 131 | 132 | - (bool)getContinueOnError { 133 | NSNumber* noResult = flutterMethodCall.arguments[SqfliteSqlCipherParamContinueOnError]; 134 | return [noResult boolValue]; 135 | } 136 | 137 | - (NSArray*)getSqlArguments { 138 | NSArray* arguments = flutterMethodCall.arguments[SqfliteSqlCipherParamSqlArguments]; 139 | return [SqfliteSqlCipherPlugin toSqlArguments:arguments]; 140 | } 141 | 142 | - (NSNumber*)getInTransactionArgument { 143 | return flutterMethodCall.arguments[SqfliteSqlCipherParamInTransaction]; 144 | } 145 | 146 | - (void)success:(NSObject*)results { 147 | flutterResult(results); 148 | } 149 | - (void)error:(NSObject*)error { 150 | flutterResult(error); 151 | } 152 | @end 153 | -------------------------------------------------------------------------------- /sqflite/macos/Classes/SqfliteSqlCipherPlugin.h: -------------------------------------------------------------------------------- 1 | #if TARGET_OS_IPHONE 2 | #import 3 | #else 4 | #import 5 | #endif 6 | 7 | @interface SqfliteSqlCipherPlugin : NSObject 8 | 9 | + (NSArray*)toSqlArguments:(NSArray*)rawArguments; 10 | 11 | @end 12 | 13 | extern NSString *const SqfliteSqlCipherParamMethod; 14 | extern NSString *const SqfliteSqlCipherParamSql; 15 | extern NSString *const SqfliteSqlCipherParamSqlArguments; 16 | extern NSString *const SqfliteSqlCipherParamInTransaction; 17 | extern NSString *const SqfliteSqlCipherParamNoResult; 18 | extern NSString *const SqfliteSqlCipherParamContinueOnError; 19 | extern NSString *const SqfliteSqlCipherParamResult; 20 | extern NSString *const SqfliteSqlCipherParamError; 21 | extern NSString *const SqfliteSqlCipherParamErrorCode; 22 | extern NSString *const SqfliteSqlCipherParamErrorMessage; 23 | extern NSString *const SqfliteSqlCipherParamErrorData; 24 | -------------------------------------------------------------------------------- /sqflite/macos/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyTrackingDomains 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | NSPrivacyCollectedDataTypes 10 | 11 | NSPrivacyTracking 12 | 13 | 14 | -------------------------------------------------------------------------------- /sqflite/macos/sqflite_sqlcipher.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. 3 | # 4 | Pod::Spec.new do |s| 5 | s.name = 'sqflite_sqlcipher' 6 | s.version = '0.0.1' 7 | s.summary = 'SQLite plugin with SqlCipher support.' 8 | s.description = <<-DESC 9 | Access SQLite database. 10 | DESC 11 | s.homepage = 'https://github.com/davidmartos96/sqflite_sqlcipher' 12 | s.license = { :file => '../LICENSE' } 13 | s.author = { 'David' => 'davidmartos96@gmail.com' } 14 | s.source = { :path => '.' } 15 | s.source_files = 'Classes/**/*' 16 | s.public_header_files = 'Classes/**/*.h' 17 | s.dependency 'FlutterMacOS' 18 | s.dependency 'FMDB/SQLCipher', '~> 2.7.5' 19 | s.dependency 'SQLCipher', '4.5.7' 20 | 21 | s.platform = :osx, '10.13' 22 | s.pod_target_xcconfig = { 23 | 'DEFINES_MODULE' => 'YES', 24 | 'HEADER_SEARCH_PATHS' => 'SQLCipher' 25 | } 26 | s.swift_version = '5.0' 27 | s.resource_bundles = {'sqflite_sqlcipher_ios_privacy' => ['Resources/PrivacyInfo.xcprivacy']} 28 | end 29 | -------------------------------------------------------------------------------- /sqflite/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: sqflite_sqlcipher 2 | homepage: https://github.com/davidmartos96/sqflite_sqlcipher 3 | description: Flutter plugin for SQLite, a self-contained, high-reliability, 4 | embedded, SQL database engine. (SqlCipher support) 5 | version: 3.1.0+1 6 | 7 | environment: 8 | sdk: '>=3.3.0 <4.0.0' 9 | flutter: ">=3.19.0" 10 | 11 | flutter: 12 | plugin: 13 | platforms: 14 | android: 15 | package: com.davidmartos96.sqflite_sqlcipher 16 | pluginClass: SqfliteSqlCipherPlugin 17 | ios: 18 | pluginClass: SqfliteSqlCipherPlugin 19 | macos: 20 | pluginClass: SqfliteSqlCipherPlugin 21 | 22 | 23 | dependencies: 24 | flutter: 25 | sdk: flutter 26 | synchronized: '>=3.0.0 <4.0.0' 27 | path: '>=1.8.0 <3.0.0' 28 | sqflite_common: ^2.5.0 29 | 30 | dev_dependencies: 31 | lints: ^3.0.0 32 | process_run: ^0.13.1 33 | flutter_test: 34 | sdk: flutter 35 | -------------------------------------------------------------------------------- /sqflite/test/sqflite_sql_cipher_open_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/services.dart'; 2 | import 'package:flutter_test/flutter_test.dart'; 3 | import 'package:sqflite_sqlcipher/sqflite.dart'; 4 | 5 | const channel = MethodChannel('com.davidmartos96.sqflite_sqlcipher'); 6 | 7 | class MockMethodCall { 8 | String? expectedMethod; 9 | dynamic expectedArguments; 10 | dynamic response; 11 | 12 | @override 13 | String toString() => '$expectedMethod $expectedArguments $response'; 14 | } 15 | 16 | class MockScenario { 17 | MockScenario(List data) { 18 | methodsCalls = data 19 | .map((list) => MockMethodCall() 20 | ..expectedMethod = list[0]?.toString() 21 | ..expectedArguments = list[1] 22 | ..response = list[2]) 23 | .toList(growable: false); 24 | } 25 | 26 | late List methodsCalls; 27 | var index = 0; 28 | dynamic exception; 29 | 30 | void end() { 31 | expect(exception, isNull, reason: '$exception'); 32 | expect(index, methodsCalls.length); 33 | } 34 | } 35 | 36 | MockScenario startScenario(List data) { 37 | final scenario = MockScenario(data); 38 | 39 | TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger.setMockMethodCallHandler(channel, 40 | (MethodCall methodCall) async { 41 | final index = scenario.index++; 42 | // devPrint('$index ${scenario.methodsCalls[index]}'); 43 | final item = scenario.methodsCalls[index]; 44 | try { 45 | expect(methodCall.method, item.expectedMethod); 46 | expect(methodCall.arguments, item.expectedArguments); 47 | } catch (e) { 48 | scenario.exception ??= '$e $index'; 49 | } 50 | return item.response; 51 | }); 52 | return scenario; 53 | } 54 | 55 | void main() { 56 | TestWidgetsFlutterBinding.ensureInitialized(); 57 | 58 | group('sqflite_sql_cipher', () { 59 | test('open no password', () async { 60 | final scenario = startScenario([ 61 | [ 62 | 'openDatabase', 63 | {'path': ':memory:', 'singleInstance': true}, 64 | 1 65 | ], 66 | [ 67 | 'closeDatabase', 68 | {'id': 1}, 69 | null 70 | ], 71 | ]); 72 | final db = await openDatabase(inMemoryDatabasePath); 73 | await db.close(); 74 | scenario.end(); 75 | }); 76 | test('open with version and password', () async { 77 | final scenario = startScenario([ 78 | [ 79 | 'openDatabase', 80 | {'path': ':memory:', 'singleInstance': true, 'password': 'my_password'}, 81 | 1 82 | ], 83 | [ 84 | 'query', 85 | {'sql': 'PRAGMA user_version', 'arguments': null, 'id': 1}, 86 | {} 87 | ], 88 | [ 89 | 'execute', 90 | {'sql': 'BEGIN EXCLUSIVE', 'arguments': null, 'id': 1, 'inTransaction': true}, 91 | null 92 | ], 93 | [ 94 | 'query', 95 | {'sql': 'PRAGMA user_version', 'arguments': null, 'id': 1}, 96 | {} 97 | ], 98 | [ 99 | 'execute', 100 | {'sql': 'PRAGMA user_version = 1', 'arguments': null, 'id': 1}, 101 | null 102 | ], 103 | [ 104 | 'execute', 105 | {'sql': 'COMMIT', 'arguments': null, 'id': 1, 'inTransaction': false}, 106 | null 107 | ], 108 | [ 109 | 'closeDatabase', 110 | {'id': 1}, 111 | null 112 | ], 113 | ]); 114 | final db = 115 | await openDatabase(inMemoryDatabasePath, password: 'my_password', version: 1, onCreate: (db, version) {}); 116 | await db.close(); 117 | scenario.end(); 118 | }); 119 | }); 120 | } 121 | -------------------------------------------------------------------------------- /tool/copy_macos_code_to_ios.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | Future main() async { 4 | var shell = Shell(); 5 | 6 | await shell.run(''' 7 | # Code is shared between ios and macos 8 | # There is no easy way to do that so the macos code is the reference 9 | # and is copied to ios 10 | cp -R sqflite/macos/Classes/ sqflite/ios/Classes/ 11 | 12 | '''); 13 | } 14 | -------------------------------------------------------------------------------- /tool/run_test.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | /// Run unit and driver test on a connected device 4 | Future main() async { 5 | var shell = Shell(); 6 | 7 | shell = shell.pushd('sqflite'); 8 | await shell.run(''' 9 | 10 | flutter test 11 | 12 | '''); 13 | 14 | shell = shell.pushd('example'); 15 | await shell.run(''' 16 | 17 | flutter packages get 18 | flutter test 19 | dart tool/run_flutter_driver_test.dart 20 | 21 | '''); 22 | shell = shell.popd(); 23 | shell = shell.popd(); 24 | } 25 | -------------------------------------------------------------------------------- /tool/tag.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:process_run/package/package.dart'; 4 | import 'package:process_run/shell.dart'; 5 | 6 | Future main() async { 7 | var shell = Shell(); 8 | var version = await getPackageVersion(dir: 'sqflite'); 9 | print('Version $version'); 10 | print('Tap anything or CTRL-C: $version'); 11 | 12 | await stdin.first; 13 | await shell.run(''' 14 | git tag v$version 15 | git push origin --tags 16 | '''); 17 | } 18 | -------------------------------------------------------------------------------- /tool/travis.dart: -------------------------------------------------------------------------------- 1 | import 'package:process_run/shell.dart'; 2 | 3 | Future main() async { 4 | var shell = Shell(); 5 | 6 | await shell.run('flutter doctor'); 7 | 8 | for (var dir in [ 9 | 'sqflite/example', 10 | 'sqflite', 11 | ]) { 12 | shell = shell.pushd(dir); 13 | await shell.run(''' 14 | 15 | flutter packages get 16 | dart tool/travis.dart 17 | 18 | '''); 19 | shell = shell.popd(); 20 | } 21 | } 22 | --------------------------------------------------------------------------------