├── .eslintignore ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml └── workflows │ ├── autofix.yml │ ├── build.yml │ ├── bump_version.yml │ └── test.yml ├── .gitignore ├── .npmignore ├── .prettierrc.js ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── CapgoCapacitorDataStorageSqlite.podspec ├── LICENSE ├── Package.swift ├── android ├── .classpath ├── .gitignore ├── .project ├── .settings │ └── org.eclipse.buildship.core.prefs ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proguard-rules.pro ├── settings.gradle └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── getcapacitor │ │ └── android │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── jeep │ │ │ └── plugin │ │ │ └── capacitor │ │ │ └── capgocapacitordatastoragesqlite │ │ │ ├── CapgoCapacitorDataStorageSqlite.java │ │ │ ├── CapgoCapacitorDataStorageSqlitePlugin.java │ │ │ ├── RetHandler.java │ │ │ └── cdssUtils │ │ │ ├── Data.java │ │ │ ├── Global.java │ │ │ ├── ImportExportJson │ │ │ ├── JsonStore.java │ │ │ ├── JsonTable.java │ │ │ └── JsonValue.java │ │ │ ├── StorageDatabaseHelper.java │ │ │ └── UtilsSQLCipher.java │ └── res │ │ └── .gitkeep │ └── test │ └── java │ └── com │ └── getcapacitor │ └── ExampleUnitTest.java ├── bun.lockb ├── dist └── esm │ ├── definitions.d.ts │ ├── definitions.js │ ├── definitions.js.map │ ├── index.d.ts │ ├── index.js │ ├── index.js.map │ ├── web.d.ts │ ├── web.js │ └── web.js.map ├── docs ├── API.md ├── ImportExportJson.md └── USAGE.md ├── electron ├── .gitignore ├── .npmignore ├── rollup.config.mjs ├── src │ ├── electron-utils │ │ ├── Data.ts │ │ ├── StorageDatabaseHelper.ts │ │ ├── UtilsSQLite.ts │ │ └── json-utils.ts │ └── index.ts └── tsconfig.json ├── ios ├── Plugin.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ ├── Plugin.xcscheme │ │ └── PluginTests.xcscheme ├── Plugin.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Plugin │ ├── CapgoCapacitorDataStorageSqlite.swift │ ├── CapgoCapacitorDataStorageSqlitePlugin.swift │ ├── Data.swift │ ├── Global.swift │ ├── ImportExportJson │ │ └── JsonStore.swift │ ├── Info.plist │ ├── ReturnHandler.swift │ ├── StorageDatabaseHelper.swift │ └── Utils │ │ ├── Blob.swift │ │ ├── UtilsBinding.swift │ │ ├── UtilsEncryption.swift │ │ ├── UtilsFile.swift │ │ └── UtilsSQLCipher.swift ├── PluginTests │ ├── CapacitorDataStorageSqlitePluginTests.swift │ └── Info.plist └── Podfile ├── package.json ├── readme.md ├── renovate.json ├── rollup.config.mjs ├── src ├── definitions.ts ├── index.ts ├── web-utils │ ├── Data.ts │ ├── StorageDatabaseHelper.ts │ └── json-utils.ts └── web.ts └── tsconfig.json /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | example 4 | examples 5 | docs 6 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: riderx 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 🚨 Bug report 2 | title: "bug: " 3 | description: Create a bug report to help us improve 4 | labels: ["bug/fix", "needs: triage"] 5 | 6 | body: 7 | - type: input 8 | attributes: 9 | label: Version 10 | description: | 11 | Let us know the version number of each affected plugin. Please make sure you are using the latest version before reporting an issue. Chances are that the bug you discovered has already been fixed in a subsequent version. 12 | placeholder: 6.0.0 13 | validations: 14 | required: true 15 | - type: checkboxes 16 | attributes: 17 | label: Platform(s) 18 | description: Select the platforms that this bug affects. 19 | options: 20 | - label: Android 21 | - label: iOS 22 | - label: Web 23 | - type: textarea 24 | attributes: 25 | label: Current behavior 26 | description: A concise description of what you're experiencing. 27 | validations: 28 | required: true 29 | - type: textarea 30 | attributes: 31 | label: Expected behavior 32 | description: A concise description of what you expected to happen. 33 | validations: 34 | required: true 35 | - type: input 36 | attributes: 37 | label: Reproduction 38 | description: | 39 | Please provide a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) in a public GitHub repository so that we can debug the issue. 40 | We have prepared a template repository that you can use: [Cap-go/.capacitor-app](https://github.com/Cap-go/.capacitor-app). 41 | placeholder: https://github.com/... 42 | validations: 43 | required: false 44 | - type: textarea 45 | attributes: 46 | label: Steps to reproduce 47 | description: Steps to reproduce the behaviour using the provided example. 48 | placeholder: | 49 | 1. In this environment... 50 | 2. With this config... 51 | 3. Run '...' 52 | 4. See error... 53 | validations: 54 | required: true 55 | - type: textarea 56 | attributes: 57 | label: Other information 58 | description: List any other information that is relevant to your issue. Device information, stack traces, screenshots, related issues, etc. 59 | - type: textarea 60 | attributes: 61 | label: Capacitor doctor 62 | description: Run `npx cap doctor` in a terminal and paste the output below. 63 | validations: 64 | required: true 65 | - type: checkboxes 66 | attributes: 67 | label: Before submitting 68 | description: | 69 | A well-written bug report allows the maintainers to quickly recreate the necessary conditions to inspect the bug and quickly find its root cause. 70 | Please ensure your bug report fulfills all of the following requirements. 71 | options: 72 | - label: I have read and followed the [bug report guidelines](https://capawesome.io/contributing/bug-reports/). 73 | required: true 74 | - label: I have attached links to possibly related issues and discussions. 75 | required: true 76 | - label: I understand that incomplete issues (e.g. without reproduction) are closed. 77 | required: true 78 | - type: checkboxes 79 | attributes: 80 | label: Fastest way to fix this issue 81 | description: | 82 | Founding is a great way to get your issue fixed fast. This make community contributions more likely to happen and discharge the maintainers from the burden of being the only one fixing all issues. 83 | options: 84 | - label: I want to get this fix ASAP and [found the issue with Algora](https://console.algora.io/org/gl/bounties/community?fund=Cap-go%2Fcapacitor-inappbrowser) we recommend ($50 to $500) 85 | required: false 86 | 87 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: ⚡️ Feature request 2 | title: "feat: " 3 | description: Suggest an idea for this project 4 | labels: ["feature", "needs: triage"] 5 | 6 | body: 7 | - type: textarea 8 | attributes: 9 | label: Current problem 10 | description: A clear and concise description of what the problem is. 11 | placeholder: I'm always frustrated when [...] 12 | validations: 13 | required: true 14 | - type: textarea 15 | attributes: 16 | label: Preferred solution 17 | description: A clear and concise description of what you want to happen. 18 | validations: 19 | required: true 20 | - type: textarea 21 | attributes: 22 | label: Alternative options 23 | description: A clear and concise description of any alternative solutions or features you've considered. 24 | - type: textarea 25 | attributes: 26 | label: Additional context 27 | description: Add any other context or screenshots about the feature request here. 28 | - type: checkboxes 29 | attributes: 30 | label: Before submitting 31 | description: | 32 | Please ensure your idea fulfills all of the following requirements. 33 | options: 34 | - label: I have read and followed the [feature request guidelines](https://capawesome.io/contributing/feature-requests/). 35 | required: true 36 | - label: I have attached links to possibly related issues and discussions. 37 | required: true 38 | - type: checkboxes 39 | attributes: 40 | label: Fastest way to get this feature added 41 | description: | 42 | Founding is a great way to get your feature added fast. This make community contributions more likely to happen and discharge the maintainers from the burden of being the only one adding features. 43 | options: 44 | - label: I want to get this feature ASAP and [found the issue with Algora](https://console.algora.io/org/gl/bounties/community?fund=Cap-go%2Fcapacitor-inappbrowser) we recommend ($100 to $1000) 45 | required: false 46 | -------------------------------------------------------------------------------- /.github/workflows/autofix.yml: -------------------------------------------------------------------------------- 1 | name: autofix.ci # needed to securely identify the workflow 2 | 3 | on: 4 | pull_request: 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | autofix: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v4 14 | - name: Setup bun 15 | uses: oven-sh/setup-bun@v2 16 | with: 17 | bun-version: latest 18 | - name: Install dependencies 19 | run: bun install 20 | - name: Lint 21 | id: lint_code 22 | run: npm run fmt 23 | - uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef 24 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build source code and check lint 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | build_android: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Check out 13 | uses: actions/checkout@v4 14 | - uses: oven-sh/setup-bun@v2 15 | - name: Install dependencies 16 | id: install_code 17 | run: bun i 18 | - name: Setup java 19 | uses: actions/setup-java@v4 20 | with: 21 | distribution: 'zulu' 22 | java-version: '21' 23 | cache: 'gradle' 24 | cache-dependency-path: | # optional 25 | android/.gradle/*.gradle* 26 | android/**/gradle-wrapper.properties 27 | - name: Build 28 | id: build_code 29 | run: npm run verify:android 30 | build_ios: 31 | runs-on: macOS-latest 32 | steps: 33 | - name: Check out 34 | uses: actions/checkout@v4 35 | - uses: oven-sh/setup-bun@v2 36 | - uses: actions/cache@v4 37 | id: cocoapods-cache 38 | with: 39 | path: ios/Pods 40 | key: ${{ runner.os }}-pods-${{ hashFiles('ios/Podfile.lock') }} 41 | restore-keys: | 42 | ${{ runner.os }}-pods- 43 | - name: Install dependencies 44 | id: install_code 45 | run: bun i 46 | - name: Build 47 | id: build_code 48 | run: bun run verify:ios 49 | deploy: 50 | needs: [build_android, build_ios] 51 | runs-on: ubuntu-latest 52 | name: "Build code and npm release" 53 | permissions: 54 | contents: read 55 | id-token: write 56 | steps: 57 | - name: Check out 58 | uses: actions/checkout@v4 59 | - uses: oven-sh/setup-bun@v2 60 | - name: Install dependencies 61 | id: install_code 62 | run: bun i 63 | - name: Lint 64 | id: lint_code 65 | run: bun run lint 66 | - name: Build 67 | id: build_code 68 | run: bun run build 69 | - name: Verify 70 | id: verify_code 71 | run: bun run verify:web 72 | - uses: JS-DevTools/npm-publish@v3 73 | if: ${{ !contains(github.ref, '-alpha.') }} 74 | with: 75 | token: ${{ secrets.NPM_TOKEN }} 76 | provenance: true 77 | - uses: JS-DevTools/npm-publish@v3 78 | if: ${{ contains(github.ref, '-alpha.') }} 79 | with: 80 | token: ${{ secrets.NPM_TOKEN }} 81 | tag: next 82 | provenance: true 83 | -------------------------------------------------------------------------------- /.github/workflows/bump_version.yml: -------------------------------------------------------------------------------- 1 | name: Bump version 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - development 8 | 9 | jobs: 10 | bump-version: 11 | if: ${{ !startsWith(github.event.head_commit.message, 'chore(release):') }} 12 | runs-on: ubuntu-latest 13 | name: "Bump version and create changelog with standard version" 14 | steps: 15 | - name: Check out 16 | uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | token: '${{ secrets.PERSONAL_ACCESS_TOKEN }}' 20 | - uses: oven-sh/setup-bun@v2 21 | - name: Install dependencies 22 | id: install_code 23 | run: bun i 24 | - name: Git config 25 | run: | 26 | git config --local user.name "github-actions[bot]" 27 | git config --local user.email "github-actions[bot]@users.noreply.github.com" 28 | - name: Update Doc 29 | run: bun run docgen 30 | - name: Add doc to github 31 | run: | 32 | git add README.md 33 | git commit --m "docs: update doc" || true 34 | - name: Create bump and changelog main 35 | if: github.ref == 'refs/heads/main' 36 | run: bunx capacitor-plugin-standard-version@latest 37 | - name: Create bump and changelog development 38 | if: github.ref != 'refs/heads/main' 39 | run: bunx capacitor-plugin-standard-version@latest --prerelease alpha 40 | - name: Push to origin 41 | run: | 42 | CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) 43 | remote_repo="https://${GITHUB_ACTOR}:${{ secrets.PERSONAL_ACCESS_TOKEN }}@github.com/${GITHUB_REPOSITORY}.git" 44 | git pull $remote_repo $CURRENT_BRANCH 45 | git push $remote_repo HEAD:$CURRENT_BRANCH --follow-tags --tags 46 | create-cache: 47 | if: ${{ !startsWith(github.event.head_commit.message, 'chore(release):') }} 48 | runs-on: ubuntu-latest 49 | name: "Create global cache on main branch" 50 | steps: 51 | - uses: actions/checkout@v4 52 | - uses: oven-sh/setup-bun@v2 53 | - name: Install dependencies 54 | id: install_code 55 | run: bun i 56 | - name: CLI capacitor-standard-version install 57 | run: bunx capacitor-standard-version@latest --version 58 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build source code and test it 2 | 3 | on: 4 | push: 5 | branches: 6 | - renovate/** 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build_android: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out 15 | uses: actions/checkout@v4 16 | - uses: oven-sh/setup-bun@v2 17 | - name: Install dependencies 18 | id: install_code 19 | run: bun i 20 | - name: Setup java 21 | uses: actions/setup-java@v4 22 | with: 23 | distribution: 'zulu' 24 | java-version: '21' 25 | - name: Build 26 | id: build_code 27 | run: npm run verify:android 28 | build_ios: 29 | runs-on: macOS-latest 30 | steps: 31 | - name: Check out 32 | uses: actions/checkout@v4 33 | - uses: oven-sh/setup-bun@v2 34 | - name: Install dependencies 35 | id: install_code 36 | run: bun i 37 | - name: Build 38 | id: build_code 39 | run: bun run verify:ios 40 | web: 41 | runs-on: ubuntu-latest 42 | name: 'Build code and test' 43 | steps: 44 | - name: Check out 45 | uses: actions/checkout@v4 46 | - uses: oven-sh/setup-bun@v2 47 | - name: Install dependencies 48 | id: install_code 49 | run: bun i 50 | - name: Lint 51 | id: lint_code 52 | run: bun run lint 53 | - name: Build 54 | id: build_code 55 | run: bun run build 56 | - name: Verify 57 | id: verify_code 58 | run: bun run verify:web 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # node files 2 | dist 3 | node_modules 4 | 5 | # iOS files 6 | Pods 7 | Podfile.lock 8 | Package.resolved 9 | Build 10 | xcuserdata 11 | /.build 12 | /Packages 13 | xcuserdata/ 14 | DerivedData/ 15 | .swiftpm/configuration/registries.json 16 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 17 | .netrc 18 | 19 | 20 | # macOS files 21 | .DS_Store 22 | 23 | 24 | 25 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore 26 | 27 | # Built application files 28 | *.apk 29 | *.ap_ 30 | 31 | # Files for the ART/Dalvik VM 32 | *.dex 33 | 34 | # Java class files 35 | *.class 36 | 37 | # Generated files 38 | bin 39 | gen 40 | out 41 | 42 | # Gradle files 43 | .gradle 44 | build 45 | 46 | # Local configuration file (sdk path, etc) 47 | local.properties 48 | 49 | # Proguard folder generated by Eclipse 50 | proguard 51 | 52 | # Log Files 53 | *.log 54 | 55 | # Android Studio Navigation editor temp files 56 | .navigation 57 | 58 | # Android Studio captures folder 59 | captures 60 | 61 | # IntelliJ 62 | *.iml 63 | .idea 64 | 65 | # Keystore files 66 | # Uncomment the following line if you do not want to check your keystore files in. 67 | #*.jks 68 | 69 | # External native build folder generated in Android Studio 2.2 and later 70 | .externalNativeBuild 71 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # node files 2 | dist/ 3 | node_modules/ 4 | 5 | # iOS files 6 | Pods 7 | Build 8 | xcuserdata 9 | 10 | # macOS files 11 | .DS_Store 12 | 13 | 14 | 15 | # Based on Android gitignore template: https://github.com/github/gitignore/blob/master/Android.gitignore 16 | 17 | # Built application files 18 | *.apk 19 | *.ap_ 20 | 21 | # Files for the ART/Dalvik VM 22 | *.dex 23 | 24 | # Java class files 25 | *.class 26 | 27 | # Generated files 28 | bin/ 29 | gen/ 30 | out/ 31 | 32 | # Gradle files 33 | .gradle/ 34 | build/ 35 | 36 | # Local configuration file (sdk path, etc) 37 | local.properties 38 | 39 | # Proguard folder generated by Eclipse 40 | proguard/ 41 | 42 | # Log Files 43 | *.log 44 | 45 | # Android Studio Navigation editor temp files 46 | .navigation/ 47 | 48 | # Android Studio captures folder 49 | captures/ 50 | 51 | # IntelliJ 52 | *.iml 53 | .idea 54 | 55 | # Keystore files 56 | # Uncomment the following line if you do not want to check your keystore files in. 57 | #*.jks 58 | 59 | # External native build folder generated in Android Studio 2.2 and later 60 | .externalNativeBuild 61 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [require.resolve("prettier-plugin-java")], 3 | }; 4 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | Please see [`CODE_OF_CONDUCT.md`](https://github.com/capacitor-community/welcome/blob/main/CODE_OF_CONDUCT.md) in the Capacitor Community Welcome repository. 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | TODO 4 | -------------------------------------------------------------------------------- /CapgoCapacitorDataStorageSqlite.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'CapgoCapacitorDataStorageSqlite' 7 | s.version = package['version'] 8 | s.summary = package['description'] 9 | s.license = package['license'] 10 | s.homepage = package['repository']['url'] 11 | s.author = package['author'] 12 | s.source = { :git => package['repository']['url'], :tag => s.version.to_s } 13 | s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}' 14 | s.ios.deployment_target = '14.0' 15 | s.dependency 'Capacitor' 16 | s.dependency 'SQLite.swift/SQLCipher' 17 | s.swift_version = '5.1' 18 | end 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Capacitor Data Storage Sqlite 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "CapgoCapacitorDataStorageSqlite", 6 | platforms: [.iOS(.v14)], 7 | products: [ 8 | .library( 9 | name: "CapgoCapacitorDataStorageSqlite", 10 | targets: ["CapgoCapacitorDataStorageSqlitePlugin"]) 11 | ], 12 | dependencies: [ 13 | .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.2.0") 14 | .package(url: "https://github.com/stephencelis/SQLite.swift.git", from: "0.15.3") 15 | 16 | ], 17 | targets: [ 18 | .target( 19 | name: "CapgoCapacitorDataStorageSqlitePlugin", 20 | dependencies: [ 21 | .product(name: "Capacitor", package: "capacitor-swift-pm"), 22 | .product(name: "Cordova", package: "capacitor-swift-pm"), 23 | .product(name: "SQLite", package: "SQLite.swift/SQLCipher") 24 | ], 25 | path: "ios/Sources/CapgoCapacitorDataStorageSqlitePlugin"), 26 | .testTarget( 27 | name: "CapgoCapacitorDataStorageSqlitePluginTests", 28 | dependencies: ["CapgoCapacitorDataStorageSqlitePlugin"], 29 | path: "ios/Tests/CapgoCapacitorDataStorageSqlitePluginTests") 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /android/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /android/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.buildship.core.gradleprojectbuilder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.buildship.core.gradleprojectnature 22 | 23 | 24 | 25 | 1622708758499 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | arguments= 2 | auto.sync=false 3 | build.scans.enabled=false 4 | connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER) 5 | connection.project.dir= 6 | eclipse.preferences.version=1 7 | gradle.user.home= 8 | java.home=/Library/Java/JavaVirtualMachines/adoptopenjdk-11.jdk/Contents/Home 9 | jvm.arguments= 10 | offline.mode=false 11 | override.workspace.settings=true 12 | show.console.view=true 13 | show.executions.view=true 14 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | ext { 2 | junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2' 3 | androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0' 4 | androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1' 5 | androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1' 6 | } 7 | 8 | buildscript { 9 | repositories { 10 | google() 11 | mavenCentral() 12 | } 13 | dependencies { 14 | classpath 'com.android.tools.build:gradle:8.7.2' 15 | } 16 | } 17 | 18 | apply plugin: 'com.android.library' 19 | 20 | android { 21 | namespace "com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite" 22 | compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35 23 | defaultConfig { 24 | minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23 25 | targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35 26 | versionCode 1 27 | versionName "1.0" 28 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 29 | } 30 | buildTypes { 31 | release { 32 | minifyEnabled false 33 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 34 | } 35 | } 36 | lintOptions { 37 | abortOnError false 38 | } 39 | compileOptions { 40 | sourceCompatibility JavaVersion.VERSION_21 41 | targetCompatibility JavaVersion.VERSION_21 42 | } 43 | } 44 | 45 | repositories { 46 | google() 47 | mavenCentral() 48 | mavenCentral() 49 | } 50 | 51 | 52 | dependencies { 53 | implementation fileTree(dir: 'libs', include: ['*.jar']) 54 | implementation project(':capacitor-android') 55 | implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion" 56 | testImplementation "junit:junit:$junitVersion" 57 | androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion" 58 | androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion" 59 | implementation "androidx.coordinatorlayout:coordinatorlayout:1.3.0" 60 | implementation 'net.zetetic:android-database-sqlcipher:4.4.3@aar' 61 | implementation "androidx.sqlite:sqlite:2.5.1" 62 | 63 | } 64 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | 19 | # AndroidX package structure to make it clearer which packages are bundled with the 20 | # Android operating system, and which are packaged with your app's APK 21 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 22 | android.useAndroidX=true 23 | 24 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cap-go/capacitor-data-storage-sqlite/ee052dc1f263bd9a0ec9ef0f8e2f2f364a5948a3/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-all.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /android/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':capacitor-android' 2 | project(':capacitor-android').projectDir = new File('../node_modules/@capacitor/android/capacitor') -------------------------------------------------------------------------------- /android/src/androidTest/java/com/getcapacitor/android/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor.android; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import android.content.Context; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | import androidx.test.platform.app.InstrumentationRegistry; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * @see Testing documentation 15 | */ 16 | @RunWith(AndroidJUnit4.class) 17 | public class ExampleInstrumentedTest { 18 | 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getInstrumentation() 23 | .getTargetContext(); 24 | 25 | assertEquals("com.getcapacitor.android", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/CapgoCapacitorDataStorageSqlite.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite; 2 | 3 | import android.content.Context; 4 | import com.getcapacitor.JSObject; 5 | import com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.Data; 6 | import com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.ImportExportJson.JsonStore; 7 | import com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.ImportExportJson.JsonTable; 8 | import com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.StorageDatabaseHelper; 9 | import java.io.File; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | public class CapgoCapacitorDataStorageSqlite { 14 | 15 | private StorageDatabaseHelper mDb; 16 | private Context context; 17 | 18 | public CapgoCapacitorDataStorageSqlite(Context context) { 19 | this.context = context; 20 | } 21 | 22 | public void openStore( 23 | String dbName, 24 | String tableName, 25 | Boolean encrypted, 26 | String inMode, 27 | int version 28 | ) throws Exception { 29 | try { 30 | mDb = new StorageDatabaseHelper( 31 | context, 32 | dbName + "SQLite.db", 33 | tableName, 34 | encrypted, 35 | inMode, 36 | version 37 | ); 38 | if (mDb != null) { 39 | mDb.open(); 40 | if (mDb.isOpen) { 41 | return; 42 | } else { 43 | throw new Exception("mDb is not opened"); 44 | } 45 | } else { 46 | throw new Exception("mDb is null"); 47 | } 48 | } catch (Exception e) { 49 | throw new Exception(e.getMessage()); 50 | } 51 | } 52 | 53 | public void closeStore(String dbName) throws Exception { 54 | String database = dbName + "SQLite.db"; 55 | if (mDb != null && mDb.isOpen && mDb.getStoreName().equals(database)) { 56 | try { 57 | mDb.close(); 58 | return; 59 | } catch (Exception e) { 60 | throw new Exception(e.getMessage()); 61 | } 62 | } else { 63 | throw new Exception("mDb " + dbName + " is not opened or null"); 64 | } 65 | } 66 | 67 | public boolean isStoreOpen(String dbName) throws Exception { 68 | String database = dbName + "SQLite.db"; 69 | if (mDb != null && mDb.getStoreName().equals(database)) { 70 | return mDb.isOpen; 71 | } else { 72 | throw new Exception("mDb " + dbName + " is not the current one or null"); 73 | } 74 | } 75 | 76 | public void set(String key, String value) throws Exception { 77 | if (mDb != null && mDb.isOpen) { 78 | try { 79 | Data data = new Data(); 80 | data.name = key; 81 | data.value = value; 82 | mDb.set(data); 83 | return; 84 | } catch (Exception e) { 85 | throw new Exception(e.getMessage()); 86 | } 87 | } else { 88 | throw new Exception("mDb is not opened or null"); 89 | } 90 | } 91 | 92 | public String get(String key) throws Exception { 93 | if (mDb != null && mDb.isOpen) { 94 | try { 95 | Data data = mDb.get(key); 96 | if (data.id == null) { 97 | return ""; 98 | } else { 99 | return data.value; 100 | } 101 | } catch (Exception e) { 102 | throw new Exception(e.getMessage()); 103 | } 104 | } else { 105 | throw new Exception("mDb is not opened or null"); 106 | } 107 | } 108 | 109 | public void remove(String name) throws Exception { 110 | if (mDb != null && mDb.isOpen) { 111 | try { 112 | mDb.remove(name); 113 | return; 114 | } catch (Exception e) { 115 | throw new Exception(e.getMessage()); 116 | } 117 | } else { 118 | throw new Exception("mDb is not opened or null"); 119 | } 120 | } 121 | 122 | public void clear() throws Exception { 123 | if (mDb != null && mDb.isOpen) { 124 | try { 125 | mDb.clear(); 126 | return; 127 | } catch (Exception e) { 128 | throw new Exception(e.getMessage()); 129 | } 130 | } else { 131 | throw new Exception("mDb is not opened or null"); 132 | } 133 | } 134 | 135 | public boolean iskey(String name) throws Exception { 136 | boolean ret = false; 137 | if (mDb != null && mDb.isOpen) { 138 | try { 139 | ret = mDb.iskey(name); 140 | return ret; 141 | } catch (Exception e) { 142 | throw new Exception(e.getMessage()); 143 | } 144 | } else { 145 | throw new Exception("mDb is not opened or null"); 146 | } 147 | } 148 | 149 | public String[] keys() throws Exception { 150 | if (mDb != null && mDb.isOpen) { 151 | try { 152 | List resKeys = mDb.keys(); 153 | String[] keyArray = resKeys.toArray(new String[resKeys.size()]); 154 | return keyArray; 155 | } catch (Exception e) { 156 | throw new Exception(e.getMessage()); 157 | } 158 | } else { 159 | throw new Exception("mDb is not opened or null"); 160 | } 161 | } 162 | 163 | public String[] values() throws Exception { 164 | if (mDb != null && mDb.isOpen) { 165 | try { 166 | List resValues = mDb.values(); 167 | String[] valueArray = resValues.toArray(new String[resValues.size()]); 168 | return valueArray; 169 | } catch (Exception e) { 170 | throw new Exception(e.getMessage()); 171 | } 172 | } else { 173 | throw new Exception("mDb is not opened or null"); 174 | } 175 | } 176 | 177 | public String[] filtervalues(String filter) throws Exception { 178 | if (mDb != null && mDb.isOpen) { 179 | try { 180 | List resValues = mDb.filtervalues(filter); 181 | String[] valueArray = resValues.toArray(new String[resValues.size()]); 182 | return valueArray; 183 | } catch (Exception e) { 184 | throw new Exception(e.getMessage()); 185 | } 186 | } else { 187 | throw new Exception("mDb is not opened or null"); 188 | } 189 | } 190 | 191 | public JSObject[] keysvalues() throws Exception { 192 | if (mDb != null && mDb.isOpen) { 193 | try { 194 | List resKeysValues = mDb.keysvalues(); 195 | JSObject[] jsObjArray = new JSObject[resKeysValues.size()]; 196 | 197 | for (int i = 0; i < resKeysValues.size(); i++) { 198 | JSObject res = new JSObject(); 199 | res.put("key", resKeysValues.get(i).name); 200 | res.put("value", resKeysValues.get(i).value); 201 | jsObjArray[i] = res; 202 | } 203 | return jsObjArray; 204 | } catch (Exception e) { 205 | throw new Exception(e.getMessage()); 206 | } 207 | } else { 208 | throw new Exception("mDb is not opened or null"); 209 | } 210 | } 211 | 212 | public void setTable(String table) throws Exception { 213 | if (mDb != null && mDb.isOpen) { 214 | try { 215 | mDb.setTable(table, true); 216 | return; 217 | } catch (Exception e) { 218 | throw new Exception(e.getMessage()); 219 | } 220 | } else { 221 | throw new Exception("mDb is not opened or null"); 222 | } 223 | } 224 | 225 | public boolean isTable(String table) throws Exception { 226 | boolean ret = false; 227 | if (mDb != null && mDb.isOpen) { 228 | try { 229 | ret = mDb.isTable(table); 230 | return ret; 231 | } catch (Exception e) { 232 | throw new Exception(e.getMessage()); 233 | } 234 | } else { 235 | throw new Exception("mDb is not opened or null"); 236 | } 237 | } 238 | 239 | public String[] tables() throws Exception { 240 | if (mDb != null && mDb.isOpen) { 241 | try { 242 | List resTables = mDb.tables(); 243 | String[] tableArray = resTables.toArray(new String[resTables.size()]); 244 | return tableArray; 245 | } catch (Exception e) { 246 | throw new Exception(e.getMessage()); 247 | } 248 | } else { 249 | throw new Exception("mDb is not opened or null"); 250 | } 251 | } 252 | 253 | public void deleteTable(String table) throws Exception { 254 | if (mDb != null && mDb.isOpen) { 255 | try { 256 | mDb.deleteTable(table); 257 | return; 258 | } catch (Exception e) { 259 | throw new Exception(e.getMessage()); 260 | } 261 | } else { 262 | throw new Exception("mDb is not opened or null"); 263 | } 264 | } 265 | 266 | public void deleteStore(String dbName) throws Exception { 267 | try { 268 | context.deleteDatabase(dbName + "SQLite.db"); 269 | context.deleteFile(dbName + "SQLite.db"); 270 | File databaseFile = context.getDatabasePath(dbName + "SQLite.db"); 271 | if (databaseFile.exists()) { 272 | throw new Exception("failed to delete the store"); 273 | } else { 274 | return; 275 | } 276 | } catch (Exception e) { 277 | throw new Exception(e.getMessage()); 278 | } 279 | } 280 | 281 | public boolean isStoreExists(String dbName) throws Exception { 282 | boolean ret = false; 283 | try { 284 | File databaseFile = context.getDatabasePath(dbName + "SQLite.db"); 285 | if (databaseFile.exists()) ret = true; 286 | return ret; 287 | } catch (Exception e) { 288 | throw new Exception(e.getMessage()); 289 | } 290 | } 291 | 292 | public Boolean isJsonValid(String parsingData) throws Exception { 293 | try { 294 | JSObject jsonObject = new JSObject(parsingData); 295 | JsonStore jsonSQL = new JsonStore(); 296 | Boolean isValid = jsonSQL.isJsonStore(jsonObject); 297 | return isValid; 298 | } catch (Exception e) { 299 | throw new Exception(e.getMessage()); 300 | } 301 | } 302 | 303 | public JSObject importFromJson(String parsingData) throws Exception { 304 | try { 305 | JSObject retObj = new JSObject(); 306 | JSObject jsonObject = new JSObject(parsingData); 307 | JsonStore jsonSQL = new JsonStore(); 308 | Boolean isValid = jsonSQL.isJsonStore(jsonObject); 309 | if (!isValid) { 310 | String msg = "Stringify Json Object not Valid"; 311 | throw new Exception(msg); 312 | } 313 | int totalChanges = 0; 314 | String dbName = jsonSQL.getDatabase(); 315 | Boolean encrypted = jsonSQL.getEncrypted(); 316 | String inMode = ""; 317 | if (encrypted) { 318 | inMode = "secret"; 319 | } 320 | ArrayList tables = jsonSQL.getTables(); 321 | for (JsonTable table : tables) { 322 | // open the database 323 | mDb = new StorageDatabaseHelper( 324 | context, 325 | dbName + "SQLite.db", 326 | table.getName(), 327 | encrypted, 328 | inMode, 329 | 1 330 | ); 331 | if (mDb != null) { 332 | mDb.open(); 333 | if (mDb.isOpen) { 334 | int changes = mDb.importFromJson(table.getValues()); 335 | mDb.close(); 336 | if (changes < 1) { 337 | throw new Exception("changes < 1"); 338 | } else { 339 | totalChanges += changes; 340 | } 341 | } else { 342 | throw new Exception("mDb is not opened"); 343 | } 344 | } else { 345 | throw new Exception("mDb is null"); 346 | } 347 | } 348 | retObj.put("changes", totalChanges); 349 | return retObj; 350 | } catch (Exception e) { 351 | String msg = "importFromJson : " + e.getMessage(); 352 | throw new Exception(msg); 353 | } 354 | } 355 | 356 | public JSObject exportToJson() throws Exception { 357 | if (mDb != null && mDb.isOpen) { 358 | try { 359 | JSObject ret = mDb.exportToJson(); 360 | JsonStore jsonSQL = new JsonStore(); 361 | Boolean isValid = jsonSQL.isJsonStore(ret); 362 | if (isValid) { 363 | return ret; 364 | } else { 365 | String msg = "ExportToJson: return Obj is not a JsonStore Obj"; 366 | throw new Exception(msg); 367 | } 368 | } catch (Exception e) { 369 | String msg = "ExportToJson " + e.getMessage(); 370 | throw new Exception(msg); 371 | } 372 | } else { 373 | String msg = "mDb is not opened or null "; 374 | throw new Exception(msg); 375 | } 376 | } 377 | } 378 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/CapgoCapacitorDataStorageSqlitePlugin.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite; 2 | 3 | import android.content.Context; 4 | import com.getcapacitor.JSArray; 5 | import com.getcapacitor.JSObject; 6 | import com.getcapacitor.Plugin; 7 | import com.getcapacitor.PluginCall; 8 | import com.getcapacitor.PluginMethod; 9 | import com.getcapacitor.annotation.CapacitorPlugin; 10 | 11 | @CapacitorPlugin(name = "CapgoCapacitorDataStorageSqlite") 12 | public class CapgoCapacitorDataStorageSqlitePlugin extends Plugin { 13 | 14 | private CapgoCapacitorDataStorageSqlite implementation; 15 | private RetHandler rHandler = new RetHandler(); 16 | private Context context; 17 | 18 | /** 19 | * Load Method 20 | * Load the context 21 | */ 22 | public void load() { 23 | context = getContext(); 24 | implementation = new CapgoCapacitorDataStorageSqlite(context); 25 | } 26 | 27 | @PluginMethod 28 | public void openStore(PluginCall call) { 29 | String dbName = call.getString("database", "storage"); 30 | String tableName = call.getString("table", "storage_table"); 31 | Boolean encrypted = call.getBoolean("encrypted", false); 32 | String secret = null; 33 | String newsecret = null; 34 | String inMode = null; 35 | 36 | if (encrypted) { 37 | inMode = call.getString("mode", "no-encryption"); 38 | if ( 39 | !inMode.equals("no-encryption") && 40 | !inMode.equals("encryption") && 41 | !inMode.equals("secret") && 42 | !inMode.equals("newsecret") && 43 | !inMode.equals("wrongsecret") 44 | ) { 45 | String msg = 46 | "OpenStore: Error inMode must be in ['encryption','secret'," + 47 | "'newsecret']"; 48 | rHandler.retResult(call, null, msg); 49 | return; 50 | } 51 | } else { 52 | inMode = "no-encryption"; 53 | } 54 | try { 55 | implementation.openStore(dbName, tableName, encrypted, inMode, 1); 56 | rHandler.retResult(call, null, null); 57 | return; 58 | } catch (Exception e) { 59 | String msg = "OpenStore: " + e.getMessage(); 60 | rHandler.retResult(call, null, msg); 61 | return; 62 | } 63 | } 64 | 65 | @PluginMethod 66 | public void closeStore(PluginCall call) { 67 | if (!call.getData().has("database")) { 68 | rHandler.retResult(call, false, "closeStore: Must provide a database"); 69 | return; 70 | } 71 | String dbName = call.getString("database"); 72 | try { 73 | implementation.closeStore(dbName); 74 | rHandler.retResult(call, null, null); 75 | return; 76 | } catch (Exception e) { 77 | String msg = "Close: " + e.getMessage(); 78 | rHandler.retResult(call, null, msg); 79 | return; 80 | } 81 | } 82 | 83 | @PluginMethod 84 | public void isStoreOpen(PluginCall call) { 85 | boolean ret = false; 86 | if (!call.getData().has("database")) { 87 | rHandler.retResult(call, false, "IsStoreOpen: Must provide a database"); 88 | return; 89 | } 90 | String dbName = call.getString("database"); 91 | try { 92 | ret = implementation.isStoreOpen(dbName); 93 | rHandler.retResult(call, ret, null); 94 | return; 95 | } catch (Exception e) { 96 | String msg = "IsStoreOpen: " + e.getMessage(); 97 | rHandler.retResult(call, false, msg); 98 | return; 99 | } 100 | } 101 | 102 | @PluginMethod 103 | public void isStoreExists(PluginCall call) { 104 | boolean ret = false; 105 | if (!call.getData().has("database")) { 106 | rHandler.retResult(call, false, "IsStoreExists: Must provide a database"); 107 | return; 108 | } 109 | String dbName = call.getString("database"); 110 | try { 111 | ret = implementation.isStoreExists(dbName); 112 | rHandler.retResult(call, ret, null); 113 | return; 114 | } catch (Exception e) { 115 | String msg = "IsStoreExists: " + e.getMessage(); 116 | rHandler.retResult(call, false, msg); 117 | return; 118 | } 119 | } 120 | 121 | @PluginMethod 122 | public void set(PluginCall call) { 123 | if (!call.getData().has("key")) { 124 | rHandler.retResult(call, null, "Set: Must provide a key"); 125 | return; 126 | } 127 | String key = call.getString("key"); 128 | if (!call.getData().has("value")) { 129 | rHandler.retResult(call, null, "Set: Must provide a value"); 130 | return; 131 | } 132 | String value = call.getString("value"); 133 | try { 134 | implementation.set(key, value); 135 | rHandler.retResult(call, null, null); 136 | return; 137 | } catch (Exception e) { 138 | String msg = "Set: " + e.getMessage(); 139 | rHandler.retResult(call, null, msg); 140 | return; 141 | } 142 | } 143 | 144 | @PluginMethod 145 | public void get(PluginCall call) { 146 | if (!call.getData().has("key")) { 147 | rHandler.retValue(call, null, "Get: Must provide a key"); 148 | return; 149 | } 150 | String key = call.getString("key"); 151 | try { 152 | String value = implementation.get(key); 153 | rHandler.retValue(call, value, null); 154 | return; 155 | } catch (Exception e) { 156 | String msg = "Get: " + e.getMessage(); 157 | rHandler.retValue(call, null, msg); 158 | return; 159 | } 160 | } 161 | 162 | @PluginMethod 163 | public void remove(PluginCall call) { 164 | if (!call.getData().has("key")) { 165 | rHandler.retResult(call, null, "Remove: Must provide a key"); 166 | return; 167 | } 168 | String key = call.getString("key"); 169 | try { 170 | implementation.remove(key); 171 | rHandler.retResult(call, null, null); 172 | return; 173 | } catch (Exception e) { 174 | String msg = "Remove: " + e.getMessage(); 175 | rHandler.retResult(call, null, msg); 176 | return; 177 | } 178 | } 179 | 180 | @PluginMethod 181 | public void clear(PluginCall call) { 182 | try { 183 | implementation.clear(); 184 | rHandler.retResult(call, null, null); 185 | return; 186 | } catch (Exception e) { 187 | String msg = "Clear: " + e.getMessage(); 188 | rHandler.retResult(call, null, msg); 189 | return; 190 | } 191 | } 192 | 193 | @PluginMethod 194 | public void iskey(PluginCall call) { 195 | boolean ret = false; 196 | if (!call.getData().has("key")) { 197 | rHandler.retResult(call, false, "Iskey: Must provide a key"); 198 | return; 199 | } 200 | String key = call.getString("key"); 201 | try { 202 | ret = implementation.iskey(key); 203 | rHandler.retResult(call, ret, null); 204 | return; 205 | } catch (Exception e) { 206 | String msg = "Iskey: " + e.getMessage(); 207 | rHandler.retResult(call, false, msg); 208 | return; 209 | } 210 | } 211 | 212 | @PluginMethod 213 | public void keys(PluginCall call) { 214 | try { 215 | String[] keyArray = implementation.keys(); 216 | JSObject ret = new JSObject(); 217 | ret.put("keys", new JSArray(keyArray)); 218 | rHandler.retJSObject(call, ret, null); 219 | return; 220 | } catch (Exception e) { 221 | String msg = "Keys: " + e.getMessage(); 222 | rHandler.retJSObject(call, new JSObject(), msg); 223 | return; 224 | } 225 | } 226 | 227 | @PluginMethod 228 | public void values(PluginCall call) { 229 | try { 230 | String[] valueArray = implementation.values(); 231 | JSObject ret = new JSObject(); 232 | ret.put("values", new JSArray(valueArray)); 233 | rHandler.retJSObject(call, ret, null); 234 | return; 235 | } catch (Exception e) { 236 | String msg = "Values: " + e.getMessage(); 237 | rHandler.retJSObject(call, new JSObject(), msg); 238 | return; 239 | } 240 | } 241 | 242 | @PluginMethod 243 | public void keysvalues(PluginCall call) { 244 | try { 245 | JSObject[] jsObjArray = implementation.keysvalues(); 246 | JSObject ret = new JSObject(); 247 | ret.put("keysvalues", new JSArray(jsObjArray)); 248 | rHandler.retJSObject(call, ret, null); 249 | return; 250 | } catch (Exception e) { 251 | String msg = "KeysValues: " + e.getMessage(); 252 | rHandler.retJSObject(call, new JSObject(), msg); 253 | return; 254 | } 255 | } 256 | 257 | @PluginMethod 258 | public void filtervalues(PluginCall call) { 259 | if (!call.getData().has("filter")) { 260 | rHandler.retJSObject( 261 | call, 262 | new JSObject(), 263 | "Filtervalues: Must provide a filter" 264 | ); 265 | return; 266 | } 267 | String filter = call.getString("filter"); 268 | try { 269 | String[] valueArray = implementation.filtervalues(filter); 270 | JSObject ret = new JSObject(); 271 | ret.put("values", new JSArray(valueArray)); 272 | rHandler.retJSObject(call, ret, null); 273 | return; 274 | } catch (Exception e) { 275 | String msg = "Filtervalues: " + e.getMessage(); 276 | rHandler.retJSObject(call, new JSObject(), msg); 277 | return; 278 | } 279 | } 280 | 281 | @PluginMethod 282 | public void setTable(PluginCall call) { 283 | if (!call.getData().has("table")) { 284 | rHandler.retResult(call, false, "SetTable: Must provide a table"); 285 | return; 286 | } 287 | String table = call.getString("table"); 288 | try { 289 | implementation.setTable(table); 290 | rHandler.retResult(call, null, null); 291 | return; 292 | } catch (Exception e) { 293 | String msg = "SetTable: " + e.getMessage(); 294 | rHandler.retResult(call, null, msg); 295 | return; 296 | } 297 | } 298 | 299 | @PluginMethod 300 | public void isTable(PluginCall call) { 301 | boolean ret = false; 302 | if (!call.getData().has("table")) { 303 | rHandler.retResult(call, false, "IsTable: Must provide a table"); 304 | return; 305 | } 306 | String table = call.getString("table"); 307 | try { 308 | ret = implementation.isTable(table); 309 | rHandler.retResult(call, ret, null); 310 | return; 311 | } catch (Exception e) { 312 | String msg = "IsTable: " + e.getMessage(); 313 | rHandler.retResult(call, false, msg); 314 | return; 315 | } 316 | } 317 | 318 | @PluginMethod 319 | public void tables(PluginCall call) { 320 | try { 321 | String[] tableArray = implementation.tables(); 322 | JSObject ret = new JSObject(); 323 | ret.put("tables", new JSArray(tableArray)); 324 | rHandler.retJSObject(call, ret, null); 325 | return; 326 | } catch (Exception e) { 327 | String msg = "Tables: " + e.getMessage(); 328 | rHandler.retJSObject(call, new JSObject(), msg); 329 | return; 330 | } 331 | } 332 | 333 | @PluginMethod 334 | public void deleteTable(PluginCall call) { 335 | if (!call.getData().has("table")) { 336 | rHandler.retResult(call, null, "DeleteTable: Must provide a table"); 337 | return; 338 | } 339 | String table = call.getString("table"); 340 | try { 341 | implementation.deleteTable(table); 342 | rHandler.retResult(call, null, null); 343 | return; 344 | } catch (Exception e) { 345 | String msg = "DeleteTable: " + e.getMessage(); 346 | rHandler.retResult(call, null, msg); 347 | return; 348 | } 349 | } 350 | 351 | @PluginMethod 352 | public void deleteStore(PluginCall call) { 353 | if (!call.getData().has("database")) { 354 | rHandler.retResult(call, null, "DeleteStore: Must provide a database"); 355 | return; 356 | } 357 | String dbName = call.getString("database"); 358 | try { 359 | implementation.deleteStore(dbName); 360 | rHandler.retResult(call, null, null); 361 | return; 362 | } catch (Exception e) { 363 | String msg = "DeleteStore: " + e.getMessage(); 364 | rHandler.retResult(call, null, msg); 365 | return; 366 | } 367 | } 368 | 369 | /** 370 | * IsJsonValid 371 | * Check the validity of a given Json object 372 | * @param call 373 | */ 374 | @PluginMethod 375 | public void isJsonValid(PluginCall call) { 376 | if (!call.getData().has("jsonstring")) { 377 | String msg = "IsJsonValid: Must provide a Stringify Json Object"; 378 | rHandler.retResult(call, false, msg); 379 | return; 380 | } 381 | String parsingData = call.getString("jsonstring"); 382 | try { 383 | Boolean res = implementation.isJsonValid(parsingData); 384 | rHandler.retResult(call, res, null); 385 | return; 386 | } catch (Exception e) { 387 | String msg = "isJsonValid: " + e.getMessage(); 388 | rHandler.retResult(call, false, msg); 389 | return; 390 | } 391 | } 392 | 393 | /** 394 | * ImportFromJson Method 395 | * Import from a given Json object 396 | * @param call 397 | */ 398 | @PluginMethod 399 | public void importFromJson(PluginCall call) { 400 | JSObject retRes = new JSObject(); 401 | retRes.put("changes", Integer.valueOf(-1)); 402 | if (!call.getData().has("jsonstring")) { 403 | String msg = "ImportFromJson: Must provide a Stringify Json Object"; 404 | rHandler.retChanges(call, retRes, msg); 405 | return; 406 | } 407 | String parsingData = call.getString("jsonstring"); 408 | try { 409 | JSObject res = implementation.importFromJson(parsingData); 410 | rHandler.retChanges(call, res, null); 411 | return; 412 | } catch (Exception e) { 413 | String msg = "ImportFromJson: " + e.getMessage(); 414 | rHandler.retChanges(call, retRes, msg); 415 | return; 416 | } 417 | } 418 | 419 | /** 420 | * ExportToJson Method 421 | * Export the database to Json Object 422 | * @param call 423 | */ 424 | @PluginMethod 425 | public void exportToJson(PluginCall call) { 426 | JSObject retObj = new JSObject(); 427 | 428 | try { 429 | JSObject res = implementation.exportToJson(); 430 | rHandler.retJsonObject(call, res, null); 431 | return; 432 | } catch (Exception e) { 433 | String msg = "ExportToJson: " + e.getMessage(); 434 | rHandler.retJsonObject(call, retObj, msg); 435 | return; 436 | } 437 | } 438 | } 439 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/RetHandler.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite; 2 | 3 | import android.util.Log; 4 | import com.getcapacitor.JSArray; 5 | import com.getcapacitor.JSObject; 6 | import com.getcapacitor.PluginCall; 7 | 8 | public class RetHandler { 9 | 10 | private static final String TAG = RetHandler.class.getName(); 11 | 12 | /** 13 | * RetResult Method 14 | * Create and return the capSQLiteResult object 15 | * 16 | * @param call 17 | * @param res 18 | * @param message 19 | */ 20 | public void retResult(PluginCall call, Boolean res, String message) { 21 | JSObject ret = new JSObject(); 22 | if (message != null) { 23 | ret.put("message", message); 24 | Log.v(TAG, "*** ERROR " + message); 25 | call.reject(message); 26 | return; 27 | } 28 | if (res != null) { 29 | ret.put("result", res); 30 | call.resolve(ret); 31 | return; 32 | } else { 33 | call.resolve(); 34 | return; 35 | } 36 | } 37 | 38 | /** 39 | * RetValue Method 40 | * Create and return a value 41 | * @param call 42 | * @param res 43 | * @param message 44 | */ 45 | public void retValue(PluginCall call, String res, String message) { 46 | JSObject ret = new JSObject(); 47 | if (message != null) { 48 | ret.put("message", message); 49 | Log.v(TAG, "*** ERROR " + message); 50 | call.reject(message); 51 | return; 52 | } else { 53 | ret.put("value", res); 54 | call.resolve(ret); 55 | return; 56 | } 57 | } 58 | 59 | /** 60 | * RetJSObject Method 61 | * Create and return the capSQLiteJson object 62 | * @param call 63 | * @param res 64 | * @param message 65 | */ 66 | public void retJSObject(PluginCall call, JSObject res, String message) { 67 | if (message != null) { 68 | call.reject(message); 69 | return; 70 | } else { 71 | call.resolve(res); 72 | return; 73 | } 74 | } 75 | 76 | /** 77 | * RetChanges Method 78 | * Create and return the capSQLiteChanges object 79 | * @param call 80 | * @param res 81 | * @param message 82 | */ 83 | public void retChanges(PluginCall call, JSObject res, String message) { 84 | JSObject ret = new JSObject(); 85 | if (message != null) { 86 | ret.put("message", message); 87 | Log.v(TAG, "*** ERROR " + message); 88 | call.reject(message); 89 | return; 90 | } else { 91 | ret.put("changes", res); 92 | call.resolve(ret); 93 | return; 94 | } 95 | } 96 | 97 | /** 98 | * RetJSObject Method 99 | * Create and return the capSQLiteJson object 100 | * @param call 101 | * @param res 102 | * @param message 103 | */ 104 | public void retJsonObject(PluginCall call, JSObject res, String message) { 105 | JSObject ret = new JSObject(); 106 | if (message != null) { 107 | ret.put("message", message); 108 | Log.v(TAG, "*** ERROR " + message); 109 | call.reject(message); 110 | return; 111 | } else { 112 | ret.put("export", res); 113 | call.resolve(ret); 114 | return; 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/Data.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils; 2 | 3 | public class Data { 4 | 5 | public Long id; 6 | public String name; 7 | public String value; 8 | } 9 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/Global.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils; 2 | 3 | public class Global { 4 | 5 | public String secret = "test secret"; 6 | public String newsecret = "test new secret"; 7 | } 8 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonStore.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.ImportExportJson; 2 | 3 | import android.util.Log; 4 | import com.getcapacitor.JSArray; 5 | import com.getcapacitor.JSObject; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | import org.json.JSONArray; 11 | import org.json.JSONException; 12 | 13 | public class JsonStore { 14 | 15 | private static final String TAG = "JsonStore"; 16 | 17 | private String database = ""; 18 | private Boolean encrypted = null; 19 | private ArrayList tables = new ArrayList(); 20 | 21 | private static final List keyFirstLevel = new ArrayList( 22 | Arrays.asList("database", "encrypted", "tables") 23 | ); 24 | 25 | // Getter 26 | public String getDatabase() { 27 | return database; 28 | } 29 | 30 | public Boolean getEncrypted() { 31 | return encrypted; 32 | } 33 | 34 | public ArrayList getTables() { 35 | return tables; 36 | } 37 | 38 | // Setter 39 | public void setDatabase(String newDatabase) { 40 | this.database = newDatabase; 41 | } 42 | 43 | public void setEncrypted(Boolean newEncrypted) { 44 | this.encrypted = newEncrypted; 45 | } 46 | 47 | public void setTables(ArrayList newTables) { 48 | this.tables = newTables; 49 | } 50 | 51 | public ArrayList getKeys() { 52 | ArrayList retArray = new ArrayList(); 53 | if (getDatabase().length() > 0) retArray.add("database"); 54 | if (getEncrypted() != null) retArray.add("encrypted"); 55 | if (getTables().size() > 0) retArray.add("tables"); 56 | return retArray; 57 | } 58 | 59 | public boolean isJsonStore(JSObject jsObj) { 60 | if (jsObj == null || jsObj.length() == 0) return false; 61 | Iterator keys = jsObj.keys(); 62 | while (keys.hasNext()) { 63 | String key = keys.next(); 64 | if (!keyFirstLevel.contains(key)) return false; 65 | try { 66 | Object value = jsObj.get(key); 67 | 68 | if (key.equals("database")) { 69 | if (!(value instanceof String)) { 70 | return false; 71 | } else { 72 | database = (String) value; 73 | } 74 | } 75 | if (key.equals("encrypted")) { 76 | if (!(value instanceof Boolean)) { 77 | return false; 78 | } else { 79 | encrypted = jsObj.getBool(key); 80 | } 81 | } 82 | if (key.equals("tables")) { 83 | if (!(value instanceof JSONArray)) { 84 | String msg = "value: not instance of JSONArray 1"; 85 | Log.d(TAG, msg); 86 | 87 | return false; 88 | } else { 89 | if (value instanceof JSONArray) { 90 | JSONArray arrJS = jsObj.getJSONArray(key); 91 | tables = new ArrayList<>(); 92 | 93 | for (int i = 0; i < arrJS.length(); i++) { 94 | JsonTable table = new JsonTable(); 95 | boolean retTable = table.isTable(arrJS.getJSONObject(i)); 96 | 97 | if (!retTable) return false; 98 | tables.add(table); 99 | } 100 | } else { 101 | String msg = "value: not instance of "; 102 | msg += "JSONArray 2"; 103 | Log.d(TAG, msg); 104 | } 105 | } 106 | } 107 | } catch (JSONException e) { 108 | e.printStackTrace(); 109 | return false; 110 | } 111 | } 112 | return true; 113 | } 114 | 115 | public void print() { 116 | Log.d(TAG, "database: " + this.getDatabase()); 117 | Log.d(TAG, "encrypted: " + this.getEncrypted()); 118 | Log.d(TAG, "number of Tables: " + this.getTables().size()); 119 | for (JsonTable table : this.getTables()) { 120 | table.print(); 121 | } 122 | } 123 | 124 | public JSArray getTablesAsJSObject() { 125 | JSArray JSTables = new JSArray(); 126 | for (JsonTable table : this.tables) { 127 | JSTables.put(table.getTableAsJSObject()); 128 | } 129 | return JSTables; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonTable.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.ImportExportJson; 2 | 3 | import android.util.Log; 4 | import com.getcapacitor.JSObject; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import org.json.JSONArray; 10 | import org.json.JSONException; 11 | import org.json.JSONObject; 12 | 13 | public class JsonTable { 14 | 15 | private static final String TAG = "JsonTable"; 16 | private static final List keyTableLevel = new ArrayList( 17 | Arrays.asList("name", "values") 18 | ); 19 | 20 | private String name = ""; 21 | private ArrayList values = new ArrayList(); 22 | 23 | // Getter 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public ArrayList getValues() { 29 | return values; 30 | } 31 | 32 | // Setter 33 | public void setName(String newName) { 34 | this.name = newName; 35 | } 36 | 37 | public void setValues(ArrayList newValues) { 38 | this.values = newValues; 39 | } 40 | 41 | public ArrayList getKeys() { 42 | ArrayList retArray = new ArrayList(); 43 | if (getName().length() > 0) retArray.add("names"); 44 | if (getValues().size() > 0) retArray.add("values"); 45 | return retArray; 46 | } 47 | 48 | public boolean isTable(JSONObject jsObj) { 49 | if (jsObj == null || jsObj.length() == 0) return false; 50 | Iterator keys = jsObj.keys(); 51 | while (keys.hasNext()) { 52 | String key = keys.next(); 53 | if (!keyTableLevel.contains(key)) return false; 54 | try { 55 | Object value = jsObj.get(key); 56 | if (key.equals("name")) { 57 | if (!(value instanceof String)) { 58 | return false; 59 | } else { 60 | name = (String) value; 61 | } 62 | } 63 | if (key.equals("values")) { 64 | if (!(value instanceof JSONArray) && !(value instanceof ArrayList)) { 65 | return false; 66 | } else { 67 | values = new ArrayList(); 68 | JSONArray arr = jsObj.getJSONArray(key); 69 | for (int i = 0; i < arr.length(); i++) { 70 | JSONObject row = arr.getJSONObject(i); 71 | JsonValue arrRow = new JsonValue(); 72 | arrRow.setKey(row.getString("key")); 73 | arrRow.setValue(row.getString("value")); 74 | values.add(arrRow); 75 | } 76 | } 77 | } 78 | } catch (JSONException e) { 79 | e.printStackTrace(); 80 | return false; 81 | } 82 | } 83 | return true; 84 | } 85 | 86 | public void print() { 87 | Log.d(TAG, "name: " + this.getName()); 88 | Log.d(TAG, "number of Values: " + this.getValues().size()); 89 | for (JsonValue row : this.getValues()) { 90 | Log.d(TAG, "row: " + row); 91 | } 92 | } 93 | 94 | public JSObject getTableAsJSObject() { 95 | JSObject retObj = new JSObject(); 96 | retObj.put("name", getName()); 97 | JSONArray JSValues = new JSONArray(); 98 | if (this.values.size() > 0) { 99 | if (this.values.size() > 0) { 100 | for (JsonValue jVal : this.values) { 101 | JSValues.put(jVal.getValueAsJSObject()); 102 | } 103 | retObj.put("values", JSValues); 104 | } 105 | retObj.put("values", JSValues); 106 | } 107 | 108 | return retObj; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/ImportExportJson/JsonValue.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils.ImportExportJson; 2 | 3 | import android.util.Log; 4 | import com.getcapacitor.JSObject; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Iterator; 8 | import java.util.List; 9 | import org.json.JSONException; 10 | import org.json.JSONObject; 11 | 12 | public class JsonValue { 13 | 14 | private static final String TAG = "JsonValue"; 15 | private static final List keySchemaLevel = new ArrayList( 16 | Arrays.asList("key", "value") 17 | ); 18 | private String key = null; 19 | private String value = null; 20 | 21 | // Getter 22 | public String getKey() { 23 | return key; 24 | } 25 | 26 | public String getValue() { 27 | return value; 28 | } 29 | 30 | // Setter 31 | public void setKey(String newKey) { 32 | this.key = newKey; 33 | } 34 | 35 | public void setValue(String newValue) { 36 | this.value = newValue; 37 | } 38 | 39 | public ArrayList getKeys() { 40 | ArrayList retArray = new ArrayList(); 41 | if (getKey() != null && getKey().length() > 0) retArray.add("key"); 42 | if (getValue() != null && getValue().length() > 0) retArray.add("value"); 43 | return retArray; 44 | } 45 | 46 | public boolean isValue(JSONObject jsObj) { 47 | if (jsObj == null || jsObj.length() == 0) return false; 48 | Iterator keys = jsObj.keys(); 49 | while (keys.hasNext()) { 50 | String key = keys.next(); 51 | if (!keySchemaLevel.contains(key)) return false; 52 | try { 53 | Object val = jsObj.get(key); 54 | 55 | if (key.equals("key")) { 56 | if (!(val instanceof String)) { 57 | return false; 58 | } else { 59 | key = (String) val; 60 | } 61 | } 62 | if (key.equals("value")) { 63 | if (!(val instanceof String)) { 64 | return false; 65 | } else { 66 | value = (String) val; 67 | } 68 | } 69 | } catch (JSONException e) { 70 | e.printStackTrace(); 71 | return false; 72 | } 73 | } 74 | return true; 75 | } 76 | 77 | public void print() { 78 | String row = ""; 79 | if (this.getKey() != null) row = "key: " + this.getKey(); 80 | Log.d(TAG, row + " value: " + this.getValue()); 81 | } 82 | 83 | public JSObject getValueAsJSObject() { 84 | JSObject retObj = new JSObject(); 85 | if (this.key != null) retObj.put("key", this.key); 86 | retObj.put("value", this.value); 87 | return retObj; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /android/src/main/java/com/jeep/plugin/capacitor/capgocapacitordatastoragesqlite/cdssUtils/UtilsSQLCipher.java: -------------------------------------------------------------------------------- 1 | package com.jeep.plugin.capacitor.capgocapacitordatastoragesqlite.cdssUtils; 2 | 3 | import android.content.Context; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import net.sqlcipher.database.SQLiteDatabase; 8 | import net.sqlcipher.database.SQLiteException; 9 | import net.sqlcipher.database.SQLiteStatement; 10 | 11 | public class UtilsSQLCipher { 12 | 13 | private static final String TAG = UtilsSQLCipher.class.getName(); 14 | 15 | /** 16 | * The detected state of the database, based on whether we can 17 | * open it without a passphrase, with the passphrase 'secret'. 18 | */ 19 | public enum State { 20 | DOES_NOT_EXIST, 21 | UNENCRYPTED, 22 | ENCRYPTED_SECRET, 23 | ENCRYPTED_NEW_SECRET, 24 | } 25 | 26 | /** 27 | * Determine whether or not this database appears to be encrypted, 28 | * based on whether we can open it without a passphrase or with 29 | * the passphrase 'secret'. 30 | * 31 | * @param dbPath a File pointing to the database 32 | * @param globVar an instance of Global 33 | * @return the detected state of the database 34 | */ 35 | public State getDatabaseState(File dbPath, Global globVar) { 36 | if (dbPath.exists()) { 37 | SQLiteDatabase db = null; 38 | 39 | try { 40 | db = SQLiteDatabase.openDatabase( 41 | dbPath.getAbsolutePath(), 42 | "", 43 | null, 44 | SQLiteDatabase.OPEN_READONLY 45 | ); 46 | 47 | db.getVersion(); 48 | 49 | return (State.UNENCRYPTED); 50 | } catch (Exception e) { 51 | try { 52 | db = SQLiteDatabase.openDatabase( 53 | dbPath.getAbsolutePath(), 54 | globVar.secret, 55 | null, 56 | SQLiteDatabase.OPEN_READONLY 57 | ); 58 | return (State.ENCRYPTED_SECRET); 59 | } catch (Exception e1) { 60 | return (State.ENCRYPTED_NEW_SECRET); 61 | } 62 | } finally { 63 | if (db != null) { 64 | db.close(); 65 | } 66 | } 67 | } 68 | 69 | return (State.DOES_NOT_EXIST); 70 | } 71 | 72 | /** 73 | * Replaces this database with a version encrypted with the supplied 74 | * passphrase, deleting the original. 75 | * Do not call this while the database is open. 76 | * 77 | * The passphrase is untouched in this call. 78 | * 79 | * @param ctxt a Context 80 | * @param originalFile a File pointing to the database 81 | * @param passphrase the passphrase from the user 82 | * @throws IOException 83 | */ 84 | public void encrypt(Context ctxt, File originalFile, byte[] passphrase) 85 | throws IOException { 86 | SQLiteDatabase.loadLibs(ctxt); 87 | 88 | if (originalFile.exists()) { 89 | File newFile = File.createTempFile( 90 | "sqlcipherutils", 91 | "tmp", 92 | ctxt.getCacheDir() 93 | ); 94 | SQLiteDatabase db = SQLiteDatabase.openDatabase( 95 | originalFile.getAbsolutePath(), 96 | "", 97 | null, 98 | SQLiteDatabase.OPEN_READWRITE 99 | ); 100 | int version = db.getVersion(); 101 | 102 | db.close(); 103 | 104 | db = SQLiteDatabase.openDatabase( 105 | newFile.getAbsolutePath(), 106 | passphrase, 107 | null, 108 | SQLiteDatabase.OPEN_READWRITE, 109 | null, 110 | null 111 | ); 112 | StringBuilder sql = new StringBuilder(); 113 | sql.append("ATTACH DATABASE ? AS plaintext KEY "); 114 | sql.append("'';"); 115 | final SQLiteStatement st = db.compileStatement(sql.toString()); 116 | 117 | st.bindString(1, originalFile.getAbsolutePath()); 118 | st.execute(); 119 | 120 | db.rawExecSQL("SELECT sqlcipher_export('main', 'plaintext')"); 121 | db.rawExecSQL("DETACH DATABASE plaintext"); 122 | db.setVersion(version); 123 | st.close(); 124 | db.close(); 125 | 126 | originalFile.delete(); 127 | newFile.renameTo(originalFile); 128 | } else { 129 | throw new FileNotFoundException( 130 | originalFile.getAbsolutePath() + " not found" 131 | ); 132 | } 133 | } 134 | 135 | public void changePassword( 136 | Context ctxt, 137 | File file, 138 | String password, 139 | String nwpassword 140 | ) throws IOException { 141 | SQLiteDatabase.loadLibs(ctxt); 142 | 143 | if (file.exists()) { 144 | SQLiteDatabase db = SQLiteDatabase.openDatabase( 145 | file.getAbsolutePath(), 146 | password, 147 | null, 148 | SQLiteDatabase.OPEN_READWRITE 149 | ); 150 | 151 | if (!db.isOpen()) { 152 | throw new SQLiteException( 153 | "database " + file.getAbsolutePath() + " open failed" 154 | ); 155 | } 156 | db.changePassword(nwpassword); 157 | db.close(); 158 | } else { 159 | throw new FileNotFoundException(file.getAbsolutePath() + " not found"); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /android/src/main/res/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cap-go/capacitor-data-storage-sqlite/ee052dc1f263bd9a0ec9ef0f8e2f2f364a5948a3/android/src/main/res/.gitkeep -------------------------------------------------------------------------------- /android/src/test/java/com/getcapacitor/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.getcapacitor; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | 14 | @Test 15 | public void addition_isCorrect() throws Exception { 16 | assertEquals(4, 2 + 2); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cap-go/capacitor-data-storage-sqlite/ee052dc1f263bd9a0ec9ef0f8e2f2f364a5948a3/bun.lockb -------------------------------------------------------------------------------- /dist/esm/definitions.d.ts: -------------------------------------------------------------------------------- 1 | export interface CapgoCapacitorDataStorageSqlitePlugin { 2 | /** 3 | * Open a store 4 | * @param options: capOpenStorageOptions 5 | * @returns Promise 6 | * @since 0.0.1 7 | */ 8 | openStore(options: capOpenStorageOptions): Promise; 9 | /** 10 | * Close the Store 11 | * @param options: capStorageOptions 12 | * @returns Promise 13 | * @since 3.0.0 14 | */ 15 | closeStore(options: capStorageOptions): Promise; 16 | /** 17 | * Check if the Store is opened 18 | * @param options: capStorageOptions 19 | * @returns Promise 20 | * @since 3.0.0 21 | */ 22 | isStoreOpen(options: capStorageOptions): Promise; 23 | /** 24 | * Check if the Store exists 25 | * @param options: capStorageOptions 26 | * @returns Promise 27 | * @since 3.0.0 28 | */ 29 | isStoreExists(options: capStorageOptions): Promise; 30 | /** 31 | * Delete a store 32 | * @param options: capOpenStorageOptions 33 | * @returns Promise 34 | * @since 0.0.1 35 | */ 36 | deleteStore(options: capOpenStorageOptions): Promise; 37 | /** 38 | * Set or Add a table to an existing store 39 | * @param options: capTableStorageOptions 40 | * @returns Promise 41 | * @since 0.0.1 42 | */ 43 | setTable(options: capTableStorageOptions): Promise; 44 | /** 45 | * Store a data with given key and value 46 | * @param options: capDataStorageOptions 47 | * @returns Promise 48 | * @since 0.0.1 49 | */ 50 | set(options: capDataStorageOptions): Promise; 51 | /** 52 | * Retrieve a data value for a given data key 53 | * @param options: capDataStorageOptions 54 | * @returns Promise 55 | * @since 0.0.1 56 | */ 57 | get(options: capDataStorageOptions): Promise; 58 | /** 59 | * Remove a data with given key 60 | * @param options: capDataStorageOptions 61 | * @returns Promise 62 | * @since 0.0.1 63 | */ 64 | remove(options: capDataStorageOptions): Promise; 65 | /** 66 | * Clear the Data Store (delete all keys) 67 | * @returns Promise 68 | * @since 0.0.1 69 | */ 70 | clear(): Promise; 71 | /** 72 | * Check if a data key exists 73 | * @param options: capDataStorageOptions 74 | * @returns Promise 75 | * @since 0.0.1 76 | */ 77 | iskey(options: capDataStorageOptions): Promise; 78 | /** 79 | * Get the data key list 80 | * @returns Promise 81 | * @since 0.0.1 82 | */ 83 | keys(): Promise; 84 | /** 85 | * Get the data value list 86 | * @returns Promise 87 | * @since 0.0.1 88 | */ 89 | values(): Promise; 90 | /** 91 | * Get the data value list for filter keys 92 | * @param options: capFilterStorageOptions 93 | * @returns Promise 94 | * @since 2.4.2 95 | */ 96 | filtervalues(options: capFilterStorageOptions): Promise; 97 | /** 98 | * Get the data key/value pair list 99 | * @returns Promise 100 | * @since 0.0.1 101 | */ 102 | keysvalues(): Promise; 103 | /** 104 | * Check if a table exists 105 | * @param options: capTableStorageOptions 106 | * @returns Promise 107 | * @since 3.0.0 108 | */ 109 | isTable(options: capTableStorageOptions): Promise; 110 | /** 111 | * Get the table list for the current store 112 | * @returns Promise 113 | * @since 3.0.0 114 | */ 115 | tables(): Promise; 116 | /** 117 | * Delete a table 118 | * @param options: capTableStorageOptions 119 | * @returns Promise 120 | * @since 3.0.0 121 | */ 122 | deleteTable(options: capTableStorageOptions): Promise; 123 | /** 124 | * Import a database From a JSON 125 | * @param jsonstring string 126 | * @returns Promise 127 | * @since 3.2.0 128 | */ 129 | importFromJson(options: capStoreImportOptions): Promise; 130 | /** 131 | * Check the validity of a JSON Object 132 | * @param jsonstring string 133 | * @returns Promise 134 | * @since 3.2.0 135 | */ 136 | isJsonValid(options: capStoreImportOptions): Promise; 137 | /** 138 | * Export the given database to a JSON Object 139 | * @returns Promise 140 | * @since 3.2.0 141 | */ 142 | exportToJson(): Promise; 143 | } 144 | export interface capOpenStorageOptions { 145 | /** 146 | * The storage database name 147 | */ 148 | database?: string; 149 | /** 150 | * The storage table name 151 | */ 152 | table?: string; 153 | /** 154 | * Set to true for database encryption 155 | */ 156 | encrypted?: boolean; 157 | /*** 158 | * Set the mode for database encryption 159 | * ["encryption", "secret","newsecret"] 160 | */ 161 | mode?: string; 162 | } 163 | export interface capDataStorageOptions { 164 | /** 165 | * The data name 166 | */ 167 | key: string; 168 | /** 169 | * The data value when required 170 | */ 171 | value?: string; 172 | } 173 | export interface capStorageOptions { 174 | /** 175 | * The storage name 176 | */ 177 | database: string; 178 | } 179 | export interface capTableStorageOptions { 180 | /** 181 | * The storage table name 182 | */ 183 | table: string; 184 | } 185 | export interface capFilterStorageOptions { 186 | /** 187 | * The filter data for filtering keys 188 | * 189 | * ['%filter', 'filter', 'filter%'] for 190 | * [starts with filter, contains filter, ends with filter] 191 | */ 192 | filter: string; 193 | } 194 | export interface capDataStorageResult { 195 | /** 196 | * result set to true when successful else false 197 | */ 198 | result?: boolean; 199 | /** 200 | * a returned message 201 | */ 202 | message?: string; 203 | } 204 | export interface capValueResult { 205 | /** 206 | * the data value for a given data key 207 | */ 208 | value: string; 209 | } 210 | export interface capKeysResult { 211 | /** 212 | * the data key list as an Array 213 | */ 214 | keys: string[]; 215 | } 216 | export interface capValuesResult { 217 | /** 218 | * the data values list as an Array 219 | */ 220 | values: string[]; 221 | } 222 | export interface capKeysValuesResult { 223 | /** 224 | * the data keys/values list as an Array of {key:string,value:string} 225 | */ 226 | keysvalues: any[]; 227 | } 228 | export interface capTablesResult { 229 | /** 230 | * the tables list as an Array 231 | */ 232 | tables: string[]; 233 | } 234 | export interface JsonStore { 235 | /** 236 | * The database name 237 | */ 238 | database: string; 239 | /** 240 | * Set to true (database encryption) / false 241 | * iOS & Android only 242 | */ 243 | encrypted: boolean; 244 | /*** 245 | * Array of Table (JsonTable) 246 | */ 247 | tables: JsonTable[]; 248 | } 249 | export interface JsonTable { 250 | /** 251 | * The database name 252 | */ 253 | name: string; 254 | /*** 255 | * Array of Values (capDataStorageOptions) 256 | */ 257 | values?: capDataStorageOptions[]; 258 | } 259 | export interface capDataStorageChanges { 260 | /** 261 | * the number of changes from an importFromJson command 262 | */ 263 | changes?: number; 264 | } 265 | export interface capStoreImportOptions { 266 | /** 267 | * Set the JSON object to import 268 | * 269 | */ 270 | jsonstring?: string; 271 | } 272 | export interface capStoreJson { 273 | /** 274 | * an export JSON object 275 | */ 276 | export?: JsonStore; 277 | } 278 | -------------------------------------------------------------------------------- /dist/esm/definitions.js: -------------------------------------------------------------------------------- 1 | export {}; 2 | //# sourceMappingURL=definitions.js.map -------------------------------------------------------------------------------- /dist/esm/definitions.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["export interface CapgoCapacitorDataStorageSqlitePlugin {\n /**\n * Open a store\n * @param options: capOpenStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n openStore(options: capOpenStorageOptions): Promise;\n /**\n * Close the Store\n * @param options: capStorageOptions\n * @returns Promise\n * @since 3.0.0\n */\n closeStore(options: capStorageOptions): Promise;\n /**\n * Check if the Store is opened\n * @param options: capStorageOptions\n * @returns Promise\n * @since 3.0.0\n */\n isStoreOpen(options: capStorageOptions): Promise;\n /**\n * Check if the Store exists\n * @param options: capStorageOptions\n * @returns Promise\n * @since 3.0.0\n */\n isStoreExists(options: capStorageOptions): Promise;\n /**\n * Delete a store\n * @param options: capOpenStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n deleteStore(options: capOpenStorageOptions): Promise;\n /**\n * Set or Add a table to an existing store\n * @param options: capTableStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n setTable(options: capTableStorageOptions): Promise;\n /**\n * Store a data with given key and value\n * @param options: capDataStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n set(options: capDataStorageOptions): Promise;\n /**\n * Retrieve a data value for a given data key\n * @param options: capDataStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n get(options: capDataStorageOptions): Promise;\n /**\n * Remove a data with given key\n * @param options: capDataStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n remove(options: capDataStorageOptions): Promise;\n /**\n * Clear the Data Store (delete all keys)\n * @returns Promise\n * @since 0.0.1\n */\n clear(): Promise;\n /**\n * Check if a data key exists\n * @param options: capDataStorageOptions\n * @returns Promise\n * @since 0.0.1\n */\n iskey(options: capDataStorageOptions): Promise;\n /**\n * Get the data key list\n * @returns Promise\n * @since 0.0.1\n */\n keys(): Promise;\n /**\n * Get the data value list\n * @returns Promise\n * @since 0.0.1\n */\n values(): Promise;\n /**\n * Get the data value list for filter keys\n * @param options: capFilterStorageOptions\n * @returns Promise\n * @since 2.4.2\n */\n filtervalues(options: capFilterStorageOptions): Promise;\n /**\n * Get the data key/value pair list\n * @returns Promise\n * @since 0.0.1\n */\n keysvalues(): Promise;\n /**\n * Check if a table exists\n * @param options: capTableStorageOptions\n * @returns Promise\n * @since 3.0.0\n */\n isTable(options: capTableStorageOptions): Promise;\n /**\n * Get the table list for the current store\n * @returns Promise\n * @since 3.0.0\n */\n tables(): Promise;\n /**\n * Delete a table\n * @param options: capTableStorageOptions\n * @returns Promise\n * @since 3.0.0\n */\n deleteTable(options: capTableStorageOptions): Promise;\n /**\n * Import a database From a JSON\n * @param jsonstring string\n * @returns Promise\n * @since 3.2.0\n */\n importFromJson(\n options: capStoreImportOptions,\n ): Promise;\n /**\n * Check the validity of a JSON Object\n * @param jsonstring string\n * @returns Promise\n * @since 3.2.0\n */\n isJsonValid(options: capStoreImportOptions): Promise;\n /**\n * Export the given database to a JSON Object\n * @returns Promise\n * @since 3.2.0\n */\n exportToJson(): Promise;\n}\n\nexport interface capOpenStorageOptions {\n /**\n * The storage database name\n */\n database?: string; // default:\n // ios, android: storageSQLite\n // web : storageIDB\n /**\n * The storage table name\n */\n table?: string; // default:\n // ios, android: storage_table\n // web: storage_store\n /**\n * Set to true for database encryption\n */\n encrypted?: boolean; // only for ios and android\n /***\n * Set the mode for database encryption\n * [\"encryption\", \"secret\",\"newsecret\"]\n */\n mode?: string; // only for ios and android\n}\nexport interface capDataStorageOptions {\n /**\n * The data name\n */\n key: string;\n /**\n * The data value when required\n */\n value?: string;\n}\nexport interface capStorageOptions {\n /**\n * The storage name\n */\n database: string;\n}\n\nexport interface capTableStorageOptions {\n /**\n * The storage table name\n */\n table: string;\n}\nexport interface capFilterStorageOptions {\n /**\n * The filter data for filtering keys\n *\n * ['%filter', 'filter', 'filter%'] for\n * [starts with filter, contains filter, ends with filter]\n */\n filter: string;\n}\n\nexport interface capDataStorageResult {\n /**\n * result set to true when successful else false\n */\n result?: boolean;\n /**\n * a returned message\n */\n message?: string;\n}\nexport interface capValueResult {\n /**\n * the data value for a given data key\n */\n value: string;\n}\nexport interface capKeysResult {\n /**\n * the data key list as an Array\n */\n keys: string[];\n}\nexport interface capValuesResult {\n /**\n * the data values list as an Array\n */\n values: string[];\n}\nexport interface capKeysValuesResult {\n /**\n * the data keys/values list as an Array of {key:string,value:string}\n */\n keysvalues: any[];\n}\nexport interface capTablesResult {\n /**\n * the tables list as an Array\n */\n tables: string[];\n}\nexport interface JsonStore {\n /**\n * The database name\n */\n database: string;\n /**\n * Set to true (database encryption) / false\n * iOS & Android only\n */\n encrypted: boolean;\n /***\n * Array of Table (JsonTable)\n */\n tables: JsonTable[];\n}\nexport interface JsonTable {\n /**\n * The database name\n */\n name: string;\n /***\n * Array of Values (capDataStorageOptions)\n */\n values?: capDataStorageOptions[];\n}\n\nexport interface capDataStorageChanges {\n /**\n * the number of changes from an importFromJson command\n */\n changes?: number;\n}\nexport interface capStoreImportOptions {\n /**\n * Set the JSON object to import\n *\n */\n jsonstring?: string;\n}\nexport interface capStoreJson {\n /**\n * an export JSON object\n */\n export?: JsonStore;\n}\n"]} -------------------------------------------------------------------------------- /dist/esm/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { CapgoCapacitorDataStorageSqlitePlugin } from "./definitions"; 2 | declare const CapgoCapacitorDataStorageSqlite: CapgoCapacitorDataStorageSqlitePlugin; 3 | export * from "./definitions"; 4 | export { CapgoCapacitorDataStorageSqlite }; 5 | -------------------------------------------------------------------------------- /dist/esm/index.js: -------------------------------------------------------------------------------- 1 | import { registerPlugin } from "@capacitor/core"; 2 | const CapgoCapacitorDataStorageSqlite = registerPlugin("CapgoCapacitorDataStorageSqlite", { 3 | web: () => import("./web").then((m) => new m.CapgoCapacitorDataStorageSqliteWeb()), 4 | electron: () => window.CapacitorCustomPlatform.plugins 5 | .CapacitorDataStorageSqlite, 6 | }); 7 | export * from "./definitions"; 8 | export { CapgoCapacitorDataStorageSqlite }; 9 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/esm/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,+BAA+B,GACnC,cAAc,CACZ,iCAAiC,EACjC;IACE,GAAG,EAAE,GAAG,EAAE,CACR,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,kCAAkC,EAAE,CAAC;IACzE,QAAQ,EAAE,GAAG,EAAE,CACZ,MAAc,CAAC,uBAAuB,CAAC,OAAO;SAC5C,0BAA0B;CAChC,CACF,CAAC;AAEJ,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,+BAA+B,EAAE,CAAC","sourcesContent":["import { registerPlugin } from \"@capacitor/core\";\n\nimport type { CapgoCapacitorDataStorageSqlitePlugin } from \"./definitions\";\n\nconst CapgoCapacitorDataStorageSqlite =\n registerPlugin(\n \"CapgoCapacitorDataStorageSqlite\",\n {\n web: () =>\n import(\"./web\").then((m) => new m.CapgoCapacitorDataStorageSqliteWeb()),\n electron: () =>\n (window as any).CapacitorCustomPlatform.plugins\n .CapacitorDataStorageSqlite,\n },\n );\n\nexport * from \"./definitions\";\nexport { CapgoCapacitorDataStorageSqlite };\n"]} -------------------------------------------------------------------------------- /dist/esm/web.d.ts: -------------------------------------------------------------------------------- 1 | import { WebPlugin } from "@capacitor/core"; 2 | import type { CapgoCapacitorDataStorageSqlitePlugin, capDataStorageOptions, capDataStorageResult, capFilterStorageOptions, capKeysResult, capKeysValuesResult, capTablesResult, capOpenStorageOptions, capTableStorageOptions, capValueResult, capValuesResult, capStorageOptions, capStoreJson, capDataStorageChanges, capStoreImportOptions } from "./definitions"; 3 | export declare class CapgoCapacitorDataStorageSqliteWeb extends WebPlugin implements CapgoCapacitorDataStorageSqlitePlugin { 4 | private mDb; 5 | openStore(options: capOpenStorageOptions): Promise; 6 | closeStore(options: capStorageOptions): Promise; 7 | isStoreOpen(options: capStorageOptions): Promise; 8 | isStoreExists(options: capStorageOptions): Promise; 9 | setTable(options: capTableStorageOptions): Promise; 10 | set(options: capDataStorageOptions): Promise; 11 | get(options: capDataStorageOptions): Promise; 12 | remove(options: capDataStorageOptions): Promise; 13 | clear(): Promise; 14 | iskey(options: capDataStorageOptions): Promise; 15 | keys(): Promise; 16 | values(): Promise; 17 | filtervalues(options: capFilterStorageOptions): Promise; 18 | keysvalues(): Promise; 19 | deleteStore(options: capOpenStorageOptions): Promise; 20 | isTable(options: capTableStorageOptions): Promise; 21 | tables(): Promise; 22 | deleteTable(options: capTableStorageOptions): Promise; 23 | importFromJson(options: capStoreImportOptions): Promise; 24 | isJsonValid(options: capStoreImportOptions): Promise; 25 | exportToJson(): Promise; 26 | } 27 | -------------------------------------------------------------------------------- /dist/esm/web.js: -------------------------------------------------------------------------------- 1 | import { WebPlugin } from "@capacitor/core"; 2 | import { Data } from "./web-utils/Data"; 3 | import { StorageDatabaseHelper } from "./web-utils/StorageDatabaseHelper"; 4 | import { isJsonStore } from "./web-utils/json-utils"; 5 | export class CapgoCapacitorDataStorageSqliteWeb extends WebPlugin { 6 | async openStore(options) { 7 | const dbName = options.database ? `${options.database}IDB` : "storageIDB"; 8 | const tableName = options.table ? options.table : "storage_store"; 9 | try { 10 | this.mDb = new StorageDatabaseHelper(dbName, tableName); 11 | return Promise.resolve(); 12 | } 13 | catch (err) { 14 | return Promise.reject(`OpenStore: ${err.message}`); 15 | } 16 | } 17 | async closeStore(options) { 18 | throw new Error(`Method closeStore not implemented. ${options}`); 19 | } 20 | async isStoreOpen(options) { 21 | throw new Error(`Method isStoreOpen not implemented. ${options}`); 22 | } 23 | async isStoreExists(options) { 24 | throw new Error(`Method isStoreExists not implemented. ${options}`); 25 | } 26 | async setTable(options) { 27 | const tableName = options.table; 28 | if (tableName == null) { 29 | return Promise.reject("SetTable: Must provide a table name"); 30 | } 31 | if (this.mDb) { 32 | try { 33 | await this.mDb.setTable(tableName); 34 | return Promise.resolve(); 35 | } 36 | catch (err) { 37 | return Promise.reject(`SetTable: ${err.message}`); 38 | } 39 | } 40 | else { 41 | return Promise.reject("SetTable: Must open a store first"); 42 | } 43 | } 44 | async set(options) { 45 | const key = options.key; 46 | if (key == null || typeof key != "string") { 47 | return Promise.reject("Set: Must provide key as string"); 48 | } 49 | const value = options.value ? options.value : null; 50 | if (value == null || typeof value != "string") { 51 | return Promise.reject("Set: Must provide value as string"); 52 | } 53 | const data = new Data(); 54 | data.name = key; 55 | data.value = value; 56 | try { 57 | await this.mDb.set(data); 58 | return Promise.resolve(); 59 | } 60 | catch (err) { 61 | return Promise.reject(`Set: ${err.message}`); 62 | } 63 | } 64 | async get(options) { 65 | const key = options.key; 66 | if (key == null || typeof key != "string") { 67 | return Promise.reject("Get: Must provide key as string"); 68 | } 69 | try { 70 | const data = await this.mDb.get(key); 71 | if ((data === null || data === void 0 ? void 0 : data.value) != null) { 72 | return Promise.resolve({ value: data.value }); 73 | } 74 | else { 75 | return Promise.resolve({ value: "" }); 76 | } 77 | } 78 | catch (err) { 79 | return Promise.reject(`Get: ${err.message}`); 80 | } 81 | } 82 | async remove(options) { 83 | const key = options.key; 84 | if (key == null || typeof key != "string") { 85 | return Promise.reject("Remove: Must provide key as string"); 86 | } 87 | try { 88 | await this.mDb.remove(key); 89 | return Promise.resolve(); 90 | } 91 | catch (err) { 92 | return Promise.reject(`Remove: ${err.message}`); 93 | } 94 | } 95 | async clear() { 96 | try { 97 | await this.mDb.clear(); 98 | return Promise.resolve(); 99 | } 100 | catch (err) { 101 | return Promise.reject(`Clear: ${err.message}`); 102 | } 103 | } 104 | async iskey(options) { 105 | const key = options.key; 106 | if (key == null || typeof key != "string") { 107 | return Promise.reject("Iskey: Must provide key as string"); 108 | } 109 | try { 110 | const ret = await this.mDb.iskey(key); 111 | return Promise.resolve({ result: ret }); 112 | } 113 | catch (err) { 114 | return Promise.reject(`Iskey: ${err.message}`); 115 | } 116 | } 117 | async keys() { 118 | try { 119 | const ret = await this.mDb.keys(); 120 | return Promise.resolve({ keys: ret }); 121 | } 122 | catch (err) { 123 | return Promise.reject(`Keys: ${err.message}`); 124 | } 125 | } 126 | async values() { 127 | try { 128 | const ret = await this.mDb.values(); 129 | return Promise.resolve({ values: ret }); 130 | } 131 | catch (err) { 132 | return Promise.reject(`Values: ${err.message}`); 133 | } 134 | } 135 | async filtervalues(options) { 136 | const filter = options.filter; 137 | if (filter == null || typeof filter != "string") { 138 | return Promise.reject("Filtervalues: Must provide filter as string"); 139 | } 140 | let regFilter; 141 | if (filter.startsWith("%")) { 142 | regFilter = new RegExp("^" + filter.substring(1), "i"); 143 | } 144 | else if (filter.endsWith("%")) { 145 | regFilter = new RegExp(filter.slice(0, -1) + "$", "i"); 146 | } 147 | else { 148 | regFilter = new RegExp(filter, "i"); 149 | } 150 | try { 151 | const ret = []; 152 | const results = await this.mDb.keysvalues(); 153 | for (const result of results) { 154 | if (result.name != null && regFilter.test(result.name)) { 155 | if (result.value != null) { 156 | ret.push(result.value); 157 | } 158 | else { 159 | return Promise.reject(`Filtervalues: result.value is null`); 160 | } 161 | } 162 | } 163 | return Promise.resolve({ values: ret }); 164 | } 165 | catch (err) { 166 | return Promise.reject(`Filtervalues: ${err.message}`); 167 | } 168 | } 169 | async keysvalues() { 170 | try { 171 | const ret = []; 172 | const results = await this.mDb.keysvalues(); 173 | for (const result of results) { 174 | if (result.name != null && result.value != null) { 175 | const res = { key: result.name, value: result.value }; 176 | ret.push(res); 177 | } 178 | else { 179 | return Promise.reject(`Keysvalues: result.name/value are null`); 180 | } 181 | } 182 | return Promise.resolve({ keysvalues: ret }); 183 | } 184 | catch (err) { 185 | return Promise.reject(`Keysvalues: ${err.message}`); 186 | } 187 | } 188 | async deleteStore(options) { 189 | throw new Error(`Method deleteStore not implemented. ${options}`); 190 | } 191 | async isTable(options) { 192 | const table = options.table; 193 | if (table == null) { 194 | return Promise.reject("Must provide a Table Name"); 195 | } 196 | try { 197 | const ret = await this.mDb.isTable(table); 198 | return Promise.resolve({ result: ret }); 199 | } 200 | catch (err) { 201 | return Promise.reject(err); 202 | } 203 | } 204 | async tables() { 205 | try { 206 | const ret = await this.mDb.tables(); 207 | return Promise.resolve({ tables: ret }); 208 | } 209 | catch (err) { 210 | return Promise.reject(err); 211 | } 212 | } 213 | async deleteTable(options) { 214 | throw new Error(`Method deleteTable not implemented. ${options}`); 215 | } 216 | async importFromJson(options) { 217 | const keys = Object.keys(options); 218 | if (!keys.includes("jsonstring")) { 219 | return Promise.reject("Must provide a json object"); 220 | } 221 | let totalChanges = 0; 222 | if (options === null || options === void 0 ? void 0 : options.jsonstring) { 223 | const jsonStrObj = options.jsonstring; 224 | const jsonObj = JSON.parse(jsonStrObj); 225 | const isValid = isJsonStore(jsonObj); 226 | if (!isValid) { 227 | return Promise.reject("Must provide a valid JsonSQLite Object"); 228 | } 229 | const vJsonObj = jsonObj; 230 | const dbName = vJsonObj.database 231 | ? `${vJsonObj.database}IDB` 232 | : "storageIDB"; 233 | for (const table of vJsonObj.tables) { 234 | const tableName = table.name ? table.name : "storage_store"; 235 | try { 236 | this.mDb = new StorageDatabaseHelper(dbName, tableName); 237 | // Open the database 238 | const bRet = this.mDb.openStore(dbName, tableName); 239 | if (bRet) { 240 | // Import the JsonSQLite Object 241 | if (table === null || table === void 0 ? void 0 : table.values) { 242 | const changes = await this.mDb.importJson(table.values); 243 | totalChanges += changes; 244 | } 245 | } 246 | else { 247 | return Promise.reject(`Open store: ${dbName} : table: ${tableName} failed`); 248 | } 249 | } 250 | catch (err) { 251 | return Promise.reject(`ImportFromJson: ${err.message}`); 252 | } 253 | } 254 | return Promise.resolve({ changes: totalChanges }); 255 | } 256 | else { 257 | return Promise.reject("Must provide a json object"); 258 | } 259 | } 260 | async isJsonValid(options) { 261 | const keys = Object.keys(options); 262 | if (!keys.includes("jsonstring")) { 263 | return Promise.reject("Must provide a json object"); 264 | } 265 | if (options === null || options === void 0 ? void 0 : options.jsonstring) { 266 | const jsonStrObj = options.jsonstring; 267 | const jsonObj = JSON.parse(jsonStrObj); 268 | const isValid = isJsonStore(jsonObj); 269 | if (!isValid) { 270 | return Promise.reject("Stringify Json Object not Valid"); 271 | } 272 | else { 273 | return Promise.resolve({ result: true }); 274 | } 275 | } 276 | else { 277 | return Promise.reject("Must provide in options a stringify Json Object"); 278 | } 279 | } 280 | async exportToJson() { 281 | try { 282 | const ret = await this.mDb.exportJson(); 283 | return Promise.resolve({ export: ret }); 284 | } 285 | catch (err) { 286 | return Promise.reject(`exportToJson: ${err}`); 287 | } 288 | } 289 | } 290 | //# sourceMappingURL=web.js.map -------------------------------------------------------------------------------- /docs/ImportExportJson.md: -------------------------------------------------------------------------------- 1 |


2 |

JSON Import/Export DOCUMENTATION

3 |

capacitor-data-storage-sqlite

4 |
5 |

CAPACITOR 3


6 | 7 |

8 | Capacitor Data Storage SQlite Plugin is a custom Native Capacitor plugin providing a key-value permanent store for simple data of type string only to SQLite on IOS, Android and Electron platforms and to IndexDB for the Web platform.

9 | 10 | ## Index 11 | 12 | - [`Methods`](#methods) 13 | - [`Import From JSON`](#importfromjson) 14 | - [`Export To JSON`](#exporttojson) 15 | - [`Is JSON Valid`](#isjsonvalid) 16 | - [`Json Object`](#json-object) 17 | - [`JSON Template Examples`](#json-template-examples) 18 | 19 | ## Methods 20 | 21 | 22 | ### importFromJson 23 | 24 | This method allow to create a database from a JSON Object. 25 | The created database can be encrypted or not based on the value of the name **_encrypted_**" of the JSON Object. 26 | 27 | ### exportToJson 28 | 29 | This method allow to download a database to a Json object. 30 | 31 | ### isJsonValid 32 | 33 | this method allow to check if the Json Object is valid before processing an import or validating the resulting Json Object from an export. 34 | 35 | ## JSON Object 36 | 37 | The JSON object is built up using the following types 38 | 39 | 40 | ```js 41 | export type jsonStore = { 42 | database: string, 43 | encrypted: boolean, 44 | tables: Array, 45 | }; 46 | export type jsonTable = { 47 | name: string, 48 | values?: Array, 49 | }; 50 | export type jsonValue = { 51 | key: string, 52 | value: string 53 | }; 54 | ``` 55 | 56 | ## JSON Template Examples 57 | 58 | ```js 59 | const jsonData1 = { 60 | database: "testImport", 61 | encrypted: false, 62 | tables: [ 63 | { 64 | name: "myStore1", 65 | values: [ 66 | {key: "test1", value: "my first test"}, 67 | {key: "test2", value: JSON.stringify({a: 10, b: 'my second test', c:{k:'hello',l: 15}})}, 68 | ] 69 | }, 70 | { 71 | name: "myStore2", 72 | values: [ 73 | {key: "test1", value: "my first test in store2"}, 74 | {key: "test2", value: JSON.stringify({a: 20, b: 'my second test in store2 ', d:{k:'hello',l: 15}})}, 75 | {key: "test3", value: "100"}, 76 | ] 77 | }, 78 | ] 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /electron/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /electron/.npmignore: -------------------------------------------------------------------------------- 1 | src 2 | -------------------------------------------------------------------------------- /electron/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import commonjs from '@rollup/plugin-commonjs'; 2 | import nodeResolve from '@rollup/plugin-node-resolve'; 3 | 4 | export default { 5 | input: 'electron/build/electron/src/index.js', 6 | output: [ 7 | { 8 | file: 'electron/dist/plugin.js', 9 | format: 'cjs', 10 | sourcemap: true, 11 | inlineDynamicImports: true, 12 | exports: 'named', 13 | }, 14 | ], 15 | external: ['@capacitor/core', 'sqlite3'], 16 | plugins: [nodeResolve(), commonjs()], 17 | }; 18 | -------------------------------------------------------------------------------- /electron/src/electron-utils/Data.ts: -------------------------------------------------------------------------------- 1 | export class Data { 2 | id?: number; 3 | name?: string; 4 | value?: string; 5 | } 6 | -------------------------------------------------------------------------------- /electron/src/electron-utils/UtilsSQLite.ts: -------------------------------------------------------------------------------- 1 | export class UtilsSQLite { 2 | public pathDB = "./DataStorage"; 3 | Path: any = null; 4 | NodeFs: any = null; 5 | SQLite3: any = null; 6 | 7 | constructor() { 8 | this.Path = require("path"); 9 | this.NodeFs = require("fs"); 10 | this.SQLite3 = require("sqlite3"); 11 | } 12 | public async connection( 13 | dbName: string, 14 | readOnly?: boolean, 15 | /*,key?:string*/ 16 | ): Promise { 17 | const flags = readOnly 18 | ? this.SQLite3.OPEN_READONLY 19 | : this.SQLite3.OPEN_CREATE | this.SQLite3.OPEN_READWRITE; 20 | 21 | // get the path for the database 22 | try { 23 | const dbPath = await this.getDBPath(dbName); 24 | const dbOpen = new this.SQLite3.Database(dbPath, flags); 25 | return Promise.resolve(dbOpen); 26 | } catch (err) { 27 | return Promise.reject(err); 28 | } 29 | } 30 | 31 | public async getWritableDatabase( 32 | dbName: string, 33 | /*, secret: string*/ 34 | ): Promise { 35 | const db: any = await this.connection(dbName, false /*,secret*/); 36 | return db; 37 | } 38 | 39 | public async getReadableDatabase( 40 | dbName: string, 41 | /*, secret: string*/ 42 | ): Promise { 43 | const db: any = await this.connection(dbName, true /*,secret*/); 44 | return db; 45 | } 46 | public isFileExists(dbName: string): Promise { 47 | const dbFolder: string = this.pathDB; 48 | const path = this.Path.join(dbFolder, dbName); 49 | let ret = false; 50 | try { 51 | if (this.NodeFs.existsSync(path)) { 52 | ret = true; 53 | } 54 | return Promise.resolve(ret); 55 | } catch (err) { 56 | return Promise.reject(err); 57 | } 58 | } 59 | private async getDBPath(dbName: string): Promise { 60 | let retPath: string = null; 61 | const dbFolder: string = this.pathDB; 62 | retPath = this.Path.join(dbFolder, dbName); 63 | 64 | try { 65 | if (!this.NodeFs.existsSync(dbFolder)) { 66 | await this.mkdirSyncRecursive(dbFolder); 67 | } 68 | return Promise.resolve(retPath); 69 | } catch (err) { 70 | return Promise.reject(err); 71 | } 72 | } 73 | private async mkdirSyncRecursive(directory: string): Promise { 74 | const path = directory.replace(/\/$/, "").split("/"); 75 | for (let i = 1; i <= path.length; i++) { 76 | const segment = path.slice(0, i).join("/"); 77 | segment.length > 0 && !this.NodeFs.existsSync(segment) 78 | ? this.NodeFs.mkdirSync(segment) 79 | : null; 80 | } 81 | return; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /electron/src/electron-utils/json-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * IsJsonSQLite 3 | * @param obj 4 | */ 5 | export const isJsonStore = (obj: any): boolean => { 6 | const keyFirstLevel: string[] = ["database", "encrypted", "tables"]; 7 | if ( 8 | obj == null || 9 | (Object.keys(obj).length === 0 && obj.constructor === Object) 10 | ) 11 | return false; 12 | for (const key of Object.keys(obj)) { 13 | if (keyFirstLevel.indexOf(key) === -1) return false; 14 | if (key === "database" && typeof obj[key] != "string") return false; 15 | if (key === "encrypted" && typeof obj[key] != "boolean") return false; 16 | if (key === "tables" && typeof obj[key] != "object") return false; 17 | if (key === "tables") { 18 | for (const oKey of obj[key]) { 19 | const retTable: boolean = isTable(oKey); 20 | if (!retTable) return false; 21 | } 22 | } 23 | } 24 | return true; 25 | }; 26 | /** 27 | * IsTable 28 | * @param obj 29 | */ 30 | export const isTable = (obj: any): boolean => { 31 | const keyTableLevel: string[] = ["name", "values"]; 32 | if ( 33 | obj == null || 34 | (Object.keys(obj).length === 0 && obj.constructor === Object) 35 | ) { 36 | return false; 37 | } 38 | for (const key of Object.keys(obj)) { 39 | if (keyTableLevel.indexOf(key) === -1) return false; 40 | if (key === "name" && typeof obj[key] != "string") return false; 41 | if (key === "values" && typeof obj[key] != "object") return false; 42 | if (key === "values") { 43 | for (const oKey of obj[key]) { 44 | const retValue: boolean = isValue(oKey); 45 | if (!retValue) return false; 46 | } 47 | } 48 | } 49 | return true; 50 | }; 51 | /** 52 | * IsValue 53 | * @param obj 54 | */ 55 | export const isValue = (obj: any): boolean => { 56 | const keyTableLevel: string[] = ["key", "value"]; 57 | if ( 58 | obj == null || 59 | (Object.keys(obj).length === 0 && obj.constructor === Object) 60 | ) { 61 | return false; 62 | } 63 | for (const key of Object.keys(obj)) { 64 | if (keyTableLevel.indexOf(key) === -1) return false; 65 | if (key === "key" && typeof obj[key] != "string") return false; 66 | if (key === "value" && typeof obj[key] != "string") return false; 67 | } 68 | return true; 69 | }; 70 | -------------------------------------------------------------------------------- /electron/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | CapgoCapacitorDataStorageSqlitePlugin, 3 | capEchoOptions, 4 | capEchoResult, 5 | capDataStorageOptions, 6 | capDataStorageResult, 7 | capFilterStorageOptions, 8 | capKeysResult, 9 | capKeysValuesResult, 10 | capTablesResult, 11 | capOpenStorageOptions, 12 | capTableStorageOptions, 13 | capValueResult, 14 | capValuesResult, 15 | capStorageOptions, 16 | JsonStore, 17 | capStoreJson, 18 | capDataStorageChanges, 19 | capStoreImportOptions, 20 | } from "../../src/definitions"; 21 | 22 | import { Data } from "./electron-utils/Data"; 23 | import { StorageDatabaseHelper } from "./electron-utils/StorageDatabaseHelper"; 24 | import { isJsonStore } from "./electron-utils/json-utils"; 25 | 26 | export class CapgoCapacitorDataStorageSqlite 27 | implements CapgoCapacitorDataStorageSqlitePlugin 28 | { 29 | mDb: StorageDatabaseHelper; 30 | constructor() { 31 | this.mDb = new StorageDatabaseHelper(); 32 | } 33 | async echo(options: capEchoOptions): Promise { 34 | const ret: capEchoResult = {} as capEchoResult; 35 | ret.value = options.value ? options.value : ""; 36 | return Promise.resolve(ret); 37 | } 38 | async openStore(options: capOpenStorageOptions): Promise { 39 | const dbName = options.database 40 | ? `${options.database}SQLite.db` 41 | : "storageSQLite.db"; 42 | const tableName = options.table ? options.table : "storage_store"; 43 | try { 44 | await this.mDb.openStore(dbName, tableName); 45 | return Promise.resolve(); 46 | } catch (err) { 47 | return Promise.reject(err); 48 | } 49 | } 50 | async closeStore(options: capStorageOptions): Promise { 51 | const dbName = options.database 52 | ? `${options.database}SQLite.db` 53 | : "storageSQLite.db"; 54 | if (this.mDb.dbName === dbName && this.mDb.isOpen) { 55 | try { 56 | await this.mDb.closeStore(dbName); 57 | return Promise.resolve(); 58 | } catch (err) { 59 | return Promise.reject(err); 60 | } 61 | } else { 62 | return Promise.resolve(); 63 | } 64 | } 65 | async isStoreOpen(options: capStorageOptions): Promise { 66 | const dbName = options.database 67 | ? `${options.database}SQLite.db` 68 | : "storageSQLite.db"; 69 | let ret = false; 70 | if (this.mDb.dbName === dbName && this.mDb.isOpen) { 71 | ret = true; 72 | } 73 | return Promise.resolve({ result: ret }); 74 | } 75 | async isStoreExists( 76 | options: capStorageOptions, 77 | ): Promise { 78 | const dbName = options.database 79 | ? `${options.database}SQLite.db` 80 | : "storageSQLite.db"; 81 | let ret = false; 82 | try { 83 | ret = await this.mDb.isStoreExists(dbName); 84 | return Promise.resolve({ result: ret }); 85 | } catch (err) { 86 | return Promise.reject(err); 87 | } 88 | } 89 | async setTable(options: capTableStorageOptions): Promise { 90 | const tableName = options.table; 91 | if (tableName == null) { 92 | return Promise.reject("Must provide a table name"); 93 | } 94 | try { 95 | await this.mDb.setTable(tableName); 96 | return Promise.resolve(); 97 | } catch (err) { 98 | return Promise.reject("Must open a store first"); 99 | } 100 | } 101 | async set(options: capDataStorageOptions): Promise { 102 | const key: string = options.key; 103 | if (key == null) { 104 | return Promise.reject("Must provide key"); 105 | } 106 | const value: string = options.value; 107 | if (value == null) { 108 | return Promise.reject("Must provide value"); 109 | } 110 | const data: Data = new Data(); 111 | data.name = key; 112 | data.value = value; 113 | try { 114 | await this.mDb.set(data); 115 | return Promise.resolve(); 116 | } catch (err) { 117 | return Promise.reject(err); 118 | } 119 | } 120 | async get(options: capDataStorageOptions): Promise { 121 | let ret: string; 122 | const key: string = options.key; 123 | if (key == null) { 124 | return Promise.reject("Must provide key"); 125 | } 126 | try { 127 | const data: Data = await this.mDb.get(key); 128 | ret = data?.id != null ? data.value : ""; 129 | return Promise.resolve({ value: ret }); 130 | } catch (err) { 131 | return Promise.reject(err); 132 | } 133 | } 134 | async remove(options: capDataStorageOptions): Promise { 135 | try { 136 | const key: string = options.key; 137 | if (key == null) { 138 | return Promise.reject("Must provide key"); 139 | } 140 | await this.mDb.remove(key); 141 | return Promise.resolve(); 142 | } catch (err) { 143 | return Promise.reject(err); 144 | } 145 | } 146 | async clear(): Promise { 147 | try { 148 | await this.mDb.clear(); 149 | return Promise.resolve(); 150 | } catch (err) { 151 | return Promise.reject(err); 152 | } 153 | } 154 | async iskey(options: capDataStorageOptions): Promise { 155 | let ret: boolean; 156 | const key: string = options.key; 157 | if (key == null) { 158 | return Promise.reject("Must provide key"); 159 | } 160 | try { 161 | ret = await this.mDb.iskey(key); 162 | return Promise.resolve({ result: ret }); 163 | } catch (err) { 164 | return Promise.reject(err); 165 | } 166 | } 167 | async keys(): Promise { 168 | try { 169 | const ret: string[] = await this.mDb.keys(); 170 | return Promise.resolve({ keys: ret }); 171 | } catch (err) { 172 | return Promise.reject(err); 173 | } 174 | } 175 | async values(): Promise { 176 | try { 177 | const ret: string[] = await this.mDb.values(); 178 | return Promise.resolve({ values: ret }); 179 | } catch (err) { 180 | return Promise.reject(err); 181 | } 182 | } 183 | async filtervalues( 184 | options: capFilterStorageOptions, 185 | ): Promise { 186 | const filter: string = options.filter; 187 | if (filter == null || typeof filter != "string") { 188 | return Promise.reject("Must Must provide filter as string"); 189 | } 190 | try { 191 | const ret: string[] = await this.mDb.filtervalues(filter); 192 | return Promise.resolve({ values: ret }); 193 | } catch (err) { 194 | return Promise.reject(err); 195 | } 196 | } 197 | async keysvalues(): Promise { 198 | const ret: any[] = []; 199 | try { 200 | const results: Data[] = await this.mDb.keysvalues(); 201 | for (const result of results) { 202 | const res: any = { key: result.name, value: result.value }; 203 | ret.push(res); 204 | } 205 | return Promise.resolve({ keysvalues: ret }); 206 | } catch (err) { 207 | return Promise.reject(err); 208 | } 209 | } 210 | async deleteStore(options: capOpenStorageOptions): Promise { 211 | let dbName = options.database; 212 | if (dbName == null) { 213 | return Promise.reject("Must provide a Database Name"); 214 | } 215 | dbName = `${options.database}SQLite.db`; 216 | try { 217 | await this.mDb.deleteStore(dbName); 218 | return Promise.resolve(); 219 | } catch (err) { 220 | return Promise.reject(err); 221 | } 222 | } 223 | async isTable( 224 | options: capTableStorageOptions, 225 | ): Promise { 226 | const table = options.table; 227 | if (table == null) { 228 | return Promise.reject("Must provide a Table Name"); 229 | } 230 | try { 231 | const ret = await this.mDb.isTable(table); 232 | return Promise.resolve({ result: ret }); 233 | } catch (err) { 234 | return Promise.reject(err); 235 | } 236 | } 237 | async tables(): Promise { 238 | try { 239 | const ret = await this.mDb.tables(); 240 | return Promise.resolve({ tables: ret }); 241 | } catch (err) { 242 | return Promise.reject(err); 243 | } 244 | } 245 | async deleteTable(options: capTableStorageOptions): Promise { 246 | const table = options.table; 247 | if (table == null) { 248 | return Promise.reject("Must provide a Table Name"); 249 | } 250 | try { 251 | await this.mDb.deleteTable(table); 252 | return Promise.resolve(); 253 | } catch (err) { 254 | return Promise.reject(err); 255 | } 256 | } 257 | async importFromJson( 258 | options: capStoreImportOptions, 259 | ): Promise { 260 | const keys = Object.keys(options); 261 | if (!keys.includes("jsonstring")) { 262 | return Promise.reject("Must provide a json object"); 263 | } 264 | let totalChanges = 0; 265 | 266 | if (options?.jsonstring) { 267 | const jsonStrObj: string = options.jsonstring; 268 | const jsonObj = JSON.parse(jsonStrObj); 269 | const isValid = isJsonStore(jsonObj); 270 | if (!isValid) { 271 | return Promise.reject("Must provide a valid JsonSQLite Object"); 272 | } 273 | const vJsonObj: JsonStore = jsonObj; 274 | const dbName = vJsonObj.database 275 | ? `${vJsonObj.database}SQLite.db` 276 | : "storageSQLite.db"; 277 | for (const table of vJsonObj.tables) { 278 | const tableName = table.name ? table.name : "storage_store"; 279 | try { 280 | // Open the database 281 | await this.mDb.openStore(dbName, tableName); 282 | // Import the JsonSQLite Object 283 | if (table?.values) { 284 | const changes = await this.mDb.importJson(table.values); 285 | totalChanges += changes; 286 | } 287 | } catch (err) { 288 | return Promise.reject(`ImportFromJson: ${err}`); 289 | } finally { 290 | await this.mDb.closeStore(dbName); 291 | } 292 | } 293 | return Promise.resolve({ changes: totalChanges }); 294 | } else { 295 | return Promise.reject("Must provide a json object"); 296 | } 297 | } 298 | async isJsonValid( 299 | options: capStoreImportOptions, 300 | ): Promise { 301 | const keys = Object.keys(options); 302 | if (!keys.includes("jsonstring")) { 303 | return Promise.reject("Must provide a json object"); 304 | } 305 | if (options?.jsonstring) { 306 | const jsonStrObj: string = options.jsonstring; 307 | const jsonObj = JSON.parse(jsonStrObj); 308 | const isValid = isJsonStore(jsonObj); 309 | if (!isValid) { 310 | return Promise.reject("Stringify Json Object not Valid"); 311 | } else { 312 | return Promise.resolve({ result: true }); 313 | } 314 | } else { 315 | return Promise.reject("Must provide in options a stringify Json Object"); 316 | } 317 | } 318 | async exportToJson(): Promise { 319 | try { 320 | const ret: JsonStore = await this.mDb.exportJson(); 321 | return Promise.resolve({ export: ret }); 322 | } catch (err) { 323 | return Promise.reject(`exportToJson: ${err.message}`); 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /electron/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "declaration": true, 5 | "experimentalDecorators": true, 6 | "noEmitHelpers": true, 7 | "importHelpers": true, 8 | "lib": ["dom", "es2020"], 9 | "module": "commonjs", 10 | "noImplicitAny": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "outDir": "build", 14 | "sourceMap": true, 15 | "strict": false, 16 | "target": "ES2017" 17 | }, 18 | "include": ["src/**/*"] 19 | } -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/xcshareddata/xcschemes/Plugin.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /ios/Plugin.xcodeproj/xcshareddata/xcschemes/PluginTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 53 | 54 | 60 | 61 | 63 | 64 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /ios/Plugin.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Plugin.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/Plugin/Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Data.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 08/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | // swiftlint:disable identifier_name 11 | struct Data { 12 | var id: Int64? 13 | var name: String? 14 | var value: String? 15 | } 16 | // swiftlint:enable identifier_name 17 | -------------------------------------------------------------------------------- /ios/Plugin/Global.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Global.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 08/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | struct Global { 11 | var secret: String = "test secret" 12 | var newsecret: String = "test new secret" 13 | } 14 | -------------------------------------------------------------------------------- /ios/Plugin/ImportExportJson/JsonStore.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JsonStore.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 05/09/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | public struct JsonStore: Codable { 11 | let database: String 12 | let encrypted: Bool 13 | let tables: [JsonTable] 14 | 15 | public func show() { 16 | print("databaseName: \(database) ") 17 | print("encrypted: \(encrypted) ") 18 | print("Number of Tables: \(tables.count) ") 19 | for table in tables { 20 | table.show() 21 | } 22 | } 23 | } 24 | 25 | public struct JsonTable: Codable { 26 | let name: String 27 | let values: [JsonValue] 28 | 29 | public func show() { 30 | print("name: \(name) ") 31 | if values.count > 0 { 32 | print("Number of Values: \(values.count) ") 33 | for val in values { 34 | val.show() 35 | } 36 | } 37 | } 38 | } 39 | 40 | public struct JsonValue: Codable { 41 | let key: String 42 | let value: String 43 | 44 | public func show() { 45 | print("key: \(key) value: \(value)") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ios/Plugin/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/Plugin/ReturnHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReturnHandler.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 08/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Capacitor 11 | 12 | class ReturnHandler { 13 | 14 | // MARK: - rResult 15 | 16 | func rResult(call: CAPPluginCall, ret: Bool? = nil, 17 | message: String? = nil) { 18 | if let intMessage = message { 19 | call.reject(intMessage) 20 | return 21 | } else { 22 | if let res = ret { 23 | call.resolve(["result": res]) 24 | return 25 | 26 | } else { 27 | call.resolve() 28 | return 29 | } 30 | } 31 | } 32 | 33 | // MARK: - rValue 34 | 35 | func rValue(call: CAPPluginCall, ret: String, 36 | message: String? = nil) { 37 | if let intMessage = message { 38 | call.reject(intMessage) 39 | return 40 | } else { 41 | call.resolve(["value": ret]) 42 | return 43 | } 44 | } 45 | 46 | // MARK: - rDict 47 | 48 | func rDict(call: CAPPluginCall, ret: [String: [Any]], 49 | message: String? = nil) { 50 | if let intMessage = message { 51 | call.reject(intMessage) 52 | return 53 | } else { 54 | call.resolve(ret) 55 | return 56 | } 57 | } 58 | 59 | // MARK: - rChanges 60 | 61 | func rChanges(call: CAPPluginCall, ret: [String: Any], 62 | message: String? = nil) { 63 | if let intMessage = message { 64 | call.reject(intMessage) 65 | return 66 | } else { 67 | call.resolve(["changes": ret]) 68 | return 69 | } 70 | } 71 | 72 | // MARK: - rJsonStore 73 | 74 | func rJsonStore(call: CAPPluginCall, ret: [String: Any], 75 | message: String? = nil) { 76 | if let intMessage = message { 77 | call.reject(intMessage) 78 | return 79 | } else { 80 | call.resolve(["export": ret]) 81 | return 82 | } 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /ios/Plugin/Utils/Blob.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Blob.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 08/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct Blob { 12 | 13 | public let bytes: [UInt8] 14 | 15 | public init(bytes: [UInt8]) { 16 | self.bytes = bytes 17 | } 18 | 19 | public init(bytes: UnsafeRawPointer, length: Int) { 20 | let i8bufptr = UnsafeBufferPointer(start: bytes.assumingMemoryBound(to: UInt8.self), count: length) 21 | self.init(bytes: [UInt8](i8bufptr)) 22 | } 23 | 24 | public func toHex() -> String { 25 | return bytes.map {($0 < 16 ? "0" : "") + String($0, radix: 16, uppercase: false) 26 | }.joined(separator: "") 27 | } 28 | 29 | } 30 | 31 | extension Blob: CustomStringConvertible { 32 | 33 | public var description: String { 34 | return "x'\(toHex())'" 35 | } 36 | 37 | } 38 | 39 | public func == (lhs: Blob, rhs: Blob) -> Bool { 40 | return lhs.bytes == rhs.bytes 41 | } 42 | -------------------------------------------------------------------------------- /ios/Plugin/Utils/UtilsBinding.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UtilsBinding.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 12/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SQLCipher 11 | 12 | let SQLITETRANSIENT = unsafeBitCast(-1, to: 13 | sqlite3_destructor_type.self) 14 | 15 | class UtilsBinding { 16 | class func bindValues( handle: OpaquePointer?, values: [String]) 17 | -> String { 18 | var message: String = "" 19 | var idx: Int = 1 20 | for value in values { 21 | do { 22 | if let selStmt = handle { 23 | try UtilsBinding.bind(handle: selStmt, 24 | value: value, idx: idx) 25 | idx += 1 26 | } else { 27 | message = "Error: querySQL bind failed " 28 | } 29 | } catch let error as NSError { 30 | message = "Error: querySQL bind failed " 31 | message.append("\(error.localizedDescription)") 32 | } 33 | if message.count > 0 { break } 34 | } 35 | return message 36 | } 37 | class func bind( handle: OpaquePointer?, value: Any?, idx: Int) 38 | throws { 39 | if value == nil { 40 | sqlite3_bind_null(handle, Int32(idx)) 41 | } else if (value as? NSNull) != nil { 42 | sqlite3_bind_null(handle, Int32(idx)) 43 | } else if let value = value as? Double { 44 | sqlite3_bind_double(handle, Int32(idx), value) 45 | } else if let value = value as? Int64 { 46 | sqlite3_bind_int64(handle, Int32(idx), value) 47 | } else if let value = value as? String { 48 | if value.contains("base64") { 49 | // case Base64 string as Blob 50 | // sqlite3_bind_blob(handle, Int32(idx), [value], 51 | // Int32(value.count), SQLITETRANSIENT) 52 | sqlite3_bind_text(handle, Int32(idx), value, -1, 53 | SQLITETRANSIENT) 54 | 55 | } else if value.uppercased() == "NULL" { 56 | // case NULL 57 | sqlite3_bind_null(handle, Int32(idx)) 58 | } else { 59 | sqlite3_bind_text(handle, Int32(idx), value, -1, 60 | SQLITETRANSIENT) 61 | } 62 | } else if let value = value as? Int { 63 | sqlite3_bind_int64(handle, Int32(idx), Int64(value)) 64 | } else if let value = value as? Bool { 65 | var bInt: Int32 = Int32(0) 66 | if value {bInt = Int32(1)} 67 | sqlite3_bind_int(handle, Int32(idx), Int32(bInt)) 68 | } else { 69 | throw UtilsSQLCipherError.bindFailed 70 | } 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ios/Plugin/Utils/UtilsEncryption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UtilsEncryption.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 12/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SQLCipher 11 | 12 | enum UtilsEncryptionError: Error { 13 | case encryptionFailed(message: String) 14 | } 15 | class UtilsEncryption { 16 | 17 | // MARK: - EncryptDatabase 18 | // swiftlint:disable function_body_length 19 | class func encryptDatabase(filePath: String, password: String) 20 | throws -> Bool { 21 | var ret: Bool = false 22 | var oDB: OpaquePointer? 23 | do { 24 | if UtilsFile.isFileExist(filePath: filePath) { 25 | do { 26 | let tempPath: String = try UtilsFile.getFilePath( 27 | fileName: "temp.db") 28 | try UtilsFile.renameFile(filePath: filePath, 29 | toFilePath: tempPath) 30 | oDB = try UtilsSQLCipher 31 | .openOrCreateDatabase(filename: tempPath, 32 | password: "", 33 | readonly: false) 34 | try _ = UtilsSQLCipher 35 | .openOrCreateDatabase(filename: filePath, 36 | password: password, 37 | readonly: false) 38 | 39 | var stmt: String = "ATTACH DATABASE '\(filePath)' " 40 | stmt.append("AS encrypted KEY '\(password)';") 41 | stmt.append("SELECT sqlcipher_export('encrypted');") 42 | stmt.append("DETACH DATABASE encrypted;") 43 | if sqlite3_exec(oDB, stmt, nil, nil, nil) == 44 | SQLITE_OK { 45 | try UtilsFile.deleteFile( 46 | fileName: "temp.db") 47 | ret = true 48 | } 49 | // close the db 50 | try UtilsSQLCipher.close(oDB: oDB) 51 | 52 | } catch UtilsFileError.getFilePathFailed { 53 | throw UtilsEncryptionError 54 | .encryptionFailed(message: "file path failed") 55 | } catch UtilsFileError.renameFileFailed { 56 | throw UtilsEncryptionError 57 | .encryptionFailed(message: "file rename failed") 58 | } catch UtilsSQLCipherError.openOrCreateDatabase(_) { 59 | throw UtilsEncryptionError 60 | .encryptionFailed(message: "open failed") 61 | } catch UtilsSQLCipherError.close(_) { 62 | throw UtilsEncryptionError 63 | .encryptionFailed(message: "close failed") 64 | } catch let error { 65 | print("Error: \(error)") 66 | throw UtilsEncryptionError 67 | .encryptionFailed(message: "Error: \(error)") 68 | } 69 | } 70 | } catch let error { 71 | print("Error: \(error)") 72 | throw UtilsEncryptionError 73 | .encryptionFailed(message: "Error: \(error)") 74 | } 75 | return ret 76 | } 77 | 78 | } 79 | // swiftlint:enable function_body_length 80 | -------------------------------------------------------------------------------- /ios/Plugin/Utils/UtilsFile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UtilsFile.swift 3 | // Plugin 4 | // 5 | // Created by Quéau Jean Pierre on 12/04/2021. 6 | // Copyright © 2021 Max Lynch. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | enum UtilsFileError: Error { 11 | case getFilePathFailed 12 | case copyFileFailed 13 | case renameFileFailed 14 | case deleteFileFailed 15 | case getAssetsDatabasesPathFailed 16 | case getDatabasesPathFailed 17 | case getDatabasesURLFailed 18 | case getApplicationPathFailed 19 | case getApplicationURLFailed 20 | case getLibraryPathFailed 21 | case getLibraryURLFailed 22 | case getFileListFailed 23 | case copyFromAssetToDatabaseFailed 24 | case copyFromNamesFailed 25 | } 26 | 27 | class UtilsFile { 28 | 29 | // MARK: - IsFileExist 30 | 31 | class func isDirExist(dirPath: String) -> Bool { 32 | var isDir: ObjCBool = true 33 | let fileManager = FileManager.default 34 | let exists = fileManager.fileExists(atPath: dirPath, isDirectory: &isDir) 35 | return exists && isDir.boolValue 36 | } 37 | 38 | // MARK: - IsFileExist 39 | 40 | class func isFileExist(filePath: String) -> Bool { 41 | var ret: Bool = false 42 | let fileManager = FileManager.default 43 | if fileManager.fileExists(atPath: filePath) { 44 | ret = true 45 | } 46 | return ret 47 | } 48 | class func isFileExist(fileName: String) -> Bool { 49 | var ret: Bool = false 50 | do { 51 | let filePath: String = 52 | try UtilsFile.getFilePath( 53 | fileName: fileName) 54 | ret = UtilsFile.isFileExist(filePath: filePath) 55 | return ret 56 | } catch UtilsFileError.getFilePathFailed { 57 | return false 58 | } catch _ { 59 | return false 60 | } 61 | } 62 | 63 | // MARK: - GetFilePath 64 | 65 | class func getFilePath(fileName: String) throws -> String { 66 | do { 67 | let url = try getDatabasesUrl() 68 | return url.appendingPathComponent("\(fileName)").path 69 | } catch UtilsFileError.getDatabasesURLFailed { 70 | print("Error: getDatabasesUrl Failed") 71 | throw UtilsFileError.getFilePathFailed 72 | } 73 | } 74 | 75 | // MARK: - getDatabasesUrl 76 | 77 | class func getDatabasesUrl() throws -> URL { 78 | if let path: String = NSSearchPathForDirectoriesInDomains( 79 | .documentDirectory, .userDomainMask, true 80 | ).first { 81 | return NSURL(fileURLWithPath: path) as URL 82 | } else { 83 | print("Error: getDatabasesURL did not find the document folder") 84 | throw UtilsFileError.getDatabasesURLFailed 85 | } 86 | } 87 | 88 | // MARK: - getDatabasesPath 89 | class func getDatabasesPath() throws -> String { 90 | if let path: String = NSSearchPathForDirectoriesInDomains( 91 | .documentDirectory, .userDomainMask, true 92 | ).first { 93 | return path 94 | } else { 95 | print("Error: getDatabasesPath did not find the document folder") 96 | throw UtilsFileError.getDatabasesPathFailed 97 | } 98 | } 99 | 100 | // MARK: - GetFileList 101 | 102 | class func getFileList(path: String) throws -> [String] { 103 | do { 104 | var dbs: [String] = [] 105 | let filenames = try FileManager.default 106 | .contentsOfDirectory(atPath: path) 107 | let ext: String = ".db" 108 | for file in filenames { 109 | if file.hasSuffix(ext) { 110 | dbs.append(file) 111 | } 112 | } 113 | return dbs 114 | } catch let error { 115 | print("Error: \(error)") 116 | throw UtilsFileError.getFileListFailed 117 | } 118 | } 119 | 120 | // MARK: - CopyFromNames 121 | 122 | class func copyFromNames(dbPathURL: URL, fromFile: String, databaseURL: URL, 123 | toFile: String) throws { 124 | do { 125 | let uFrom: URL = dbPathURL.appendingPathComponent(fromFile) 126 | let uTo: URL = databaseURL.appendingPathComponent(toFile) 127 | let pFrom: String = uFrom.path 128 | let pTo: String = uTo.path 129 | let bRet: Bool = try copyFile(pathName: pFrom, toPathName: pTo) 130 | if bRet { 131 | return 132 | } else { 133 | print("Error: FromNames return false") 134 | throw UtilsFileError.copyFromNamesFailed 135 | } 136 | } catch UtilsFileError.copyFileFailed { 137 | print("Error: copyFile Failed") 138 | throw UtilsFileError.copyFromNamesFailed 139 | } 140 | 141 | } 142 | 143 | // MARK: - CopyFile 144 | 145 | class func copyFile(pathName: String, toPathName: String) throws -> Bool { 146 | if pathName.count > 0 && toPathName.count > 0 { 147 | let isPath = isFileExist(filePath: pathName) 148 | if isPath { 149 | do { 150 | if isFileExist(filePath: toPathName) { 151 | _ = try deleteFile(filePath: toPathName) 152 | } 153 | let fileManager = FileManager.default 154 | try fileManager.copyItem(atPath: pathName, 155 | toPath: toPathName) 156 | return true 157 | } catch let error { 158 | print("Error: \(error)") 159 | throw UtilsFileError.copyFileFailed 160 | } 161 | } else { 162 | print("Error: CopyFilePath Failed pathName does not exist") 163 | throw UtilsFileError.copyFileFailed 164 | } 165 | } else { 166 | print("Error: CopyFilePath Failed paths count = 0") 167 | throw UtilsFileError.copyFileFailed 168 | } 169 | } 170 | 171 | // MARK: - CopyFile 172 | 173 | class func copyFile(fileName: String, toFileName: String) 174 | throws -> Bool { 175 | var ret: Bool = false 176 | do { 177 | let fromPath: String = try getFilePath(fileName: fileName) 178 | let toPath: String = try getFilePath(fileName: toFileName) 179 | ret = try copyFile(pathName: fromPath, toPathName: toPath) 180 | return ret 181 | } catch UtilsFileError.getFilePathFailed { 182 | print("Error: getFilePath Failed") 183 | throw UtilsFileError.copyFileFailed 184 | } catch let error { 185 | print("Error: \(error)") 186 | throw UtilsFileError.copyFileFailed 187 | } 188 | } 189 | 190 | // MARK: - DeleteFile 191 | 192 | class func deleteFile(filePath: String) throws { 193 | do { 194 | if isFileExist(filePath: filePath) { 195 | let fileManager = FileManager.default 196 | do { 197 | try fileManager.removeItem(atPath: filePath) 198 | } catch let error { 199 | print("Error: \(error)") 200 | throw UtilsFileError.deleteFileFailed 201 | } 202 | } 203 | return 204 | } catch let error { 205 | print("Error: \(error)") 206 | throw UtilsFileError.deleteFileFailed 207 | } 208 | } 209 | 210 | // MARK: - DeleteFile 211 | 212 | class func deleteFile(fileName: String) throws { 213 | do { 214 | let filePath: String = try getFilePath(fileName: fileName) 215 | try deleteFile(filePath: filePath) 216 | return 217 | } catch let error { 218 | print("Error: \(error)") 219 | throw UtilsFileError.deleteFileFailed 220 | } 221 | } 222 | 223 | // MARK: - RenameFile 224 | 225 | class func renameFile (filePath: String, toFilePath: String) 226 | throws { 227 | let fileManager = FileManager.default 228 | do { 229 | if isFileExist(filePath: toFilePath) { 230 | let fileName = URL( 231 | fileURLWithPath: toFilePath).lastPathComponent 232 | try deleteFile(fileName: fileName) 233 | } 234 | try fileManager.moveItem(atPath: filePath, 235 | toPath: toFilePath) 236 | } catch UtilsFileError.deleteFileFailed { 237 | print("Error: Failed in delete file") 238 | throw UtilsFileError.renameFileFailed 239 | } catch let error { 240 | print("Error: \(error)") 241 | throw UtilsFileError.renameFileFailed 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /ios/PluginTests/CapacitorDataStorageSqlitePluginTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Plugin 3 | 4 | class CapgoCapacitorDataStorageSqliteTests: XCTestCase { 5 | 6 | func testEcho() { 7 | // This is an example of a functional test case for a plugin. 8 | // Use XCTAssert and related functions to verify your tests produce the correct results. 9 | 10 | let implementation = CapgoCapacitorDataStorageSqlite() 11 | let value = "Hello, World!" 12 | let result = implementation.echo(value) 13 | 14 | XCTAssertEqual(value, result) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ios/PluginTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '14.0' 2 | 3 | def capacitor_pods 4 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 5 | use_frameworks! 6 | pod 'Capacitor', :path => '../node_modules/@capacitor/ios' 7 | pod 'CapacitorCordova', :path => '../node_modules/@capacitor/ios' 8 | pod 'SQLite.swift/SQLCipher' 9 | end 10 | 11 | target 'Plugin' do 12 | capacitor_pods 13 | end 14 | 15 | target 'PluginTests' do 16 | capacitor_pods 17 | end 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@capgo/capacitor-data-storage-sqlite", 3 | "version": "7.0.0", 4 | "description": "SQLite Storage of key/value strings pair", 5 | "main": "dist/plugin.cjs.js", 6 | "module": "dist/esm/index.js", 7 | "types": "dist/esm/index.d.ts", 8 | "unpkg": "dist/plugin.js", 9 | "files": [ 10 | "android/src/main/", 11 | "android/build.gradle", 12 | "dist/", 13 | "ios/Plugin/", 14 | "electron/", 15 | "CapgoCapacitorDataStorageSqlite.podspec" 16 | ], 17 | "author": "Martin Donadieu ", 18 | "license": "MIT", 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/Cap-go/capacitor-data-storage-sqlite.git" 22 | }, 23 | "bugs": { 24 | "url": "https://github.com/Cap-go/capacitor-data-storage-sqlite.git/issues" 25 | }, 26 | "keywords": [ 27 | "capacitor", 28 | "plugin", 29 | "native", 30 | "sqlite", 31 | "storage", 32 | "data" 33 | ], 34 | "scripts": { 35 | "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", 36 | "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -sdk iphoneos -scheme Plugin && cd ..", 37 | "verify:android": "cd android && ./gradlew clean build test && cd ..", 38 | "verify:web": "npm run build", 39 | "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", 40 | "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --autocorrect --format", 41 | "eslint": "eslint .", 42 | "prettier": "prettier --config .prettierrc.js \"**/*.{css,html,ts,js,java}\"", 43 | "swiftlint": "node-swiftlint", 44 | "docgen": "docgen --api CapgoCapacitorDataStorageSqlitePlugin --output-readme readme.md --output-json dist/docs.json", 45 | "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs", 46 | "clean": "rimraf ./dist", 47 | "watch": "tsc --watch", 48 | "prepublishOnly": "npm run build" 49 | }, 50 | "dependencies": { 51 | "localforage": "^1.10.0" 52 | }, 53 | "devDependencies": { 54 | "@capacitor/android": "^7.0.0", 55 | "@capacitor/cli": "^7.0.0", 56 | "@capacitor/core": "^7.0.0", 57 | "@capacitor/docgen": "^0.3.0", 58 | "@capacitor/ios": "^7.0.0", 59 | "@ionic/eslint-config": "^0.4.0", 60 | "@ionic/prettier-config": "^4.0.0", 61 | "@ionic/swiftlint-config": "^2.0.0", 62 | "@types/node": "^22.13.1", 63 | "eslint": "^8.57.0", 64 | "eslint-plugin-import": "^2.31.0", 65 | "husky": "^9.1.7", 66 | "prettier": "^3.4.2", 67 | "prettier-plugin-java": "^2.6.7", 68 | "rimraf": "^6.0.1", 69 | "rollup": "^4.34.6", 70 | "swiftlint": "^2.0.0", 71 | "typescript": "^5.7.3" 72 | }, 73 | "peerDependencies": { 74 | "@capacitor/core": ">=7.0.0", 75 | "localforage": "^1.10.0" 76 | }, 77 | "eslintConfig": { 78 | "extends": "@ionic/eslint-config/recommended" 79 | }, 80 | "prettier": "@ionic/prettier-config", 81 | "swiftlint": "@ionic/swiftlint-config", 82 | "capacitor": { 83 | "ios": { 84 | "src": "ios" 85 | }, 86 | "android": { 87 | "src": "android" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Capgo - Instant updates for capacitor 2 | 3 | 7 | 8 |


9 |

DATA STORAGE SQLITE

10 |

@capgo/capacitor-data-storage-sqlite

11 |
12 |

CAPACITOR 6


13 |
14 | 15 |

Note from the Owner

16 | 17 |
18 | 19 |

This Plugin has been transfered to Capgo org after his original creator @jepiqueau decide to retire. 20 |
We will forever be thankful for the work he did.

21 |
22 |

23 | Capacitor Data Storage SQlite Plugin is a custom Native Capacitor plugin providing a key-value permanent store for simple data of type string only to SQLite on IOS, Android and Electron platforms and to IndexDB for the Web platform.

24 | 25 |

26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |

36 | 37 | ## Maintainers 38 | 39 | | Maintainer | GitHub | Social | 40 | | ----------------- | ----------------------------------------- | ------ | 41 | | Martin Donadieu | [riderx](https://github.com/riderx) | | 42 | | Quéau Jean Pierre | [jepiqueau](https://github.com/jepiqueau) | | 43 | 44 | ## Browser Support 45 | 46 | The plugin follows the guidelines from the `Capacitor Team`, 47 | 48 | - [Capacitor Browser Support](https://capacitorjs.com/docs/v3/web#browser-support) 49 | 50 | meaning that it will not work in IE11 without additional JavaScript transformations, e.g. with [Babel](https://babeljs.io/). 51 | 52 | ## Installation 53 | 54 | ```bash 55 | npm install --save @capgo/capacitor-data-storage-sqlite 56 | npx cap sync 57 | ``` 58 | 59 | - On iOS, no further steps are needed. 60 | 61 | - On Android, no further steps are needed. 62 | 63 | - On Web, 64 | ```bash 65 | npm install --save localforage 66 | ``` 67 | 68 | - On Electron 69 | ```bash 70 | npm install --save @capacitor-community/electron 71 | npx cap add @capacitor-community/electron 72 | ``` 73 | Go to the Electron folder of your application 74 | 75 | ```bash 76 | cd electron 77 | npm install --save sqlite3 78 | npm install --save-dev @types/sqlite3 79 | npm run build 80 | cd .. 81 | npx cap sync @capacitor-community/electron 82 | ``` 83 | 84 | Then build YOUR_APPLICATION 85 | 86 | ``` 87 | npm run build 88 | npx cap copy 89 | npx cap copy @capacitor-community/electron 90 | npx cap open ios 91 | npx cap open android 92 | npx cap open @capacitor-community/electron 93 | ionic serve 94 | ``` 95 | 96 | ## Configuration 97 | 98 | No configuration required for this plugin 99 | 100 | ## Supported methods 101 | 102 | | Name | Android | iOS | Electron | Web | 103 | | :--------------------------- | :------ | :-- | :------- | :-- | 104 | | openStore (non-encrypted DB) | ✅ | ✅ | ✅ | ✅ | 105 | | openStore (encrypted DB) | ✅ | ✅ | ❌ | ❌ | 106 | | closeStore | ✅ | ✅ | ✅ | ❌ | 107 | | isStoreOpen | ✅ | ✅ | ✅ | ❌ | 108 | | isStoreExists | ✅ | ✅ | ✅ | ❌ | 109 | | deleteStore | ✅ | ✅ | ✅ | ❌ | 110 | | setTable | ✅ | ✅ | ✅ | ✅ | 111 | | set | ✅ | ✅ | ✅ | ✅ | 112 | | get | ✅ | ✅ | ✅ | ✅ | 113 | | iskey | ✅ | ✅ | ✅ | ✅ | 114 | | keys | ✅ | ✅ | ✅ | ✅ | 115 | | values | ✅ | ✅ | ✅ | ✅ | 116 | | filtervalues | ✅ | ✅ | ✅ | ✅ | 117 | | keysvalues | ✅ | ✅ | ✅ | ✅ | 118 | | remove | ✅ | ✅ | ✅ | ✅ | 119 | | clear | ✅ | ✅ | ✅ | ✅ | 120 | | isTable | ✅ | ✅ | ✅ | ✅ | 121 | | tables | ✅ | ✅ | ✅ | ✅ | 122 | | deleteTable | ✅ | ✅ | ✅ | ❌ | 123 | | isJsonValid | ✅ | ✅ | ✅ | ✅ | 124 | | importFromJson | ✅ | ✅ | ✅ | ✅ | 125 | | exportToJson | ✅ | ✅ | ✅ | ✅ | 126 | 127 | ## Documentation 128 | 129 | - [API_Documentation](docs/API.md) 130 | 131 | - [USAGE_Documentation](docs/USAGE.md) 132 | 133 | ## Applications demonstrating the use of the plugin 134 | 135 | ### Ionic/Angular 136 | 137 | - [angular-data-storage-sqlite-app-starter](https://github.com/Cap-go/angular-data-storage-sqlite-app-starter) 138 | 139 | ### Ionic/React 140 | 141 | - [react-data-storage-sqlite-app-starter](https://github.com/Cap-go/react-data-storage-sqlite-app-starter) 142 | 143 | ### React 144 | 145 | - [react-datastoragesqlite-app](https://github.com/Cap-go/react-datastoragesqlite-app) 146 | 147 | ### Ionic/Vue 148 | 149 | - [vue-data-storage-sqlite-app-starter](https://github.com/Cap-go/vue-data-storage-sqlite-app-starter) 150 | 151 | ### Vue 152 | 153 | - [vue-datastoragesqlite-app](https://github.com/Cap-go/vue-datastoragesqlite-app) 154 | 155 | ## Usage 156 | 157 | - [see capacitor documentation](https://capacitor.ionicframework.com/docs/getting-started/with-ionic) 158 | 159 | - [see USAGE_Documentation](https://github.com/Cap-go/capacitor-data-storage-sqlite/blob/master/docs/USAGE.md) 160 | 161 | ## Dependencies 162 | 163 | The IOS & Android code use SQLCipher allowing for database encryption. 164 | The Android code is now based on `androidx.sqlite`. The database is not closed anymore after each transaction for performance improvement. 165 | You must manage the `close` of the database before opening a new database. 166 | The Web code use `localforage` package to store the datastore in the Browser. 167 | The Electron code use `sqlite3`package 168 | 169 | ## Contributors ✨ 170 | 171 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 |

Jean Pierre Quéau

💻

Matthew Burke

📖

Kevin van Schaijk

💻

Andy Garbett

📖
185 | 186 | 187 | 188 | 189 | 190 | 191 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 192 | 193 |

Retirement message of @jepiqueau -->

194 |
195 |

196 | I have been dedicated to developing and maintaining this plugin for many years since the inception of Ionic Capacitor. Now, at 73+ years old, and with my MacBook Pro becoming obsolete for running Capacitor 6 for iOS, I have made the decision to cease maintenance of the plugin. If anyone wishes to take ownership of this plugin, they are welcome to do so. 197 |

198 |
199 |

200 | It has been a great honor to be part of this development journey alongside the developer community. I am grateful to see many of you following me on this path and incorporating the plugin into your applications. Your comments and suggestions have motivated me to continuously improve it. 201 |

202 |
203 |

204 | I have made this decision due to several family-related troubles that require my full attention and time. Therefore, I will not be stepping back. Thank you to all of you for your support. 205 |

206 |
207 |

End <--

208 | 209 |
210 | 211 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base", 5 | "schedule:earlyMondays" 6 | ], 7 | "lockFileMaintenance": { 8 | "enabled": true, 9 | "automerge": true, 10 | "automergeType": "branch", 11 | "platformAutomerge": true 12 | }, 13 | "packageRules": [ 14 | { 15 | "matchUpdateTypes": ["minor", "patch"], 16 | "matchCurrentVersion": "!/^0/", 17 | "automerge": true 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /rollup.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | input: 'dist/esm/index.js', 3 | output: [ 4 | { 5 | file: 'dist/plugin.js', 6 | format: 'iife', 7 | name: 'capacitorCapgoCapacitorDataStorageSqlite', 8 | globals: { 9 | '@capacitor/core': 'capacitorExports', 10 | localforage: 'localForage', 11 | }, 12 | sourcemap: true, 13 | inlineDynamicImports: true, 14 | }, 15 | { 16 | file: 'dist/plugin.cjs.js', 17 | format: 'cjs', 18 | sourcemap: true, 19 | inlineDynamicImports: true, 20 | }, 21 | ], 22 | external: ['@capacitor/core', 'localforage'], 23 | }; 24 | -------------------------------------------------------------------------------- /src/definitions.ts: -------------------------------------------------------------------------------- 1 | export interface CapgoCapacitorDataStorageSqlitePlugin { 2 | /** 3 | * Open a store 4 | * @param options: capOpenStorageOptions 5 | * @returns Promise 6 | * @since 0.0.1 7 | */ 8 | openStore(options: capOpenStorageOptions): Promise; 9 | /** 10 | * Close the Store 11 | * @param options: capStorageOptions 12 | * @returns Promise 13 | * @since 3.0.0 14 | */ 15 | closeStore(options: capStorageOptions): Promise; 16 | /** 17 | * Check if the Store is opened 18 | * @param options: capStorageOptions 19 | * @returns Promise 20 | * @since 3.0.0 21 | */ 22 | isStoreOpen(options: capStorageOptions): Promise; 23 | /** 24 | * Check if the Store exists 25 | * @param options: capStorageOptions 26 | * @returns Promise 27 | * @since 3.0.0 28 | */ 29 | isStoreExists(options: capStorageOptions): Promise; 30 | /** 31 | * Delete a store 32 | * @param options: capOpenStorageOptions 33 | * @returns Promise 34 | * @since 0.0.1 35 | */ 36 | deleteStore(options: capOpenStorageOptions): Promise; 37 | /** 38 | * Set or Add a table to an existing store 39 | * @param options: capTableStorageOptions 40 | * @returns Promise 41 | * @since 0.0.1 42 | */ 43 | setTable(options: capTableStorageOptions): Promise; 44 | /** 45 | * Store a data with given key and value 46 | * @param options: capDataStorageOptions 47 | * @returns Promise 48 | * @since 0.0.1 49 | */ 50 | set(options: capDataStorageOptions): Promise; 51 | /** 52 | * Retrieve a data value for a given data key 53 | * @param options: capDataStorageOptions 54 | * @returns Promise 55 | * @since 0.0.1 56 | */ 57 | get(options: capDataStorageOptions): Promise; 58 | /** 59 | * Remove a data with given key 60 | * @param options: capDataStorageOptions 61 | * @returns Promise 62 | * @since 0.0.1 63 | */ 64 | remove(options: capDataStorageOptions): Promise; 65 | /** 66 | * Clear the Data Store (delete all keys) 67 | * @returns Promise 68 | * @since 0.0.1 69 | */ 70 | clear(): Promise; 71 | /** 72 | * Check if a data key exists 73 | * @param options: capDataStorageOptions 74 | * @returns Promise 75 | * @since 0.0.1 76 | */ 77 | iskey(options: capDataStorageOptions): Promise; 78 | /** 79 | * Get the data key list 80 | * @returns Promise 81 | * @since 0.0.1 82 | */ 83 | keys(): Promise; 84 | /** 85 | * Get the data value list 86 | * @returns Promise 87 | * @since 0.0.1 88 | */ 89 | values(): Promise; 90 | /** 91 | * Get the data value list for filter keys 92 | * @param options: capFilterStorageOptions 93 | * @returns Promise 94 | * @since 2.4.2 95 | */ 96 | filtervalues(options: capFilterStorageOptions): Promise; 97 | /** 98 | * Get the data key/value pair list 99 | * @returns Promise 100 | * @since 0.0.1 101 | */ 102 | keysvalues(): Promise; 103 | /** 104 | * Check if a table exists 105 | * @param options: capTableStorageOptions 106 | * @returns Promise 107 | * @since 3.0.0 108 | */ 109 | isTable(options: capTableStorageOptions): Promise; 110 | /** 111 | * Get the table list for the current store 112 | * @returns Promise 113 | * @since 3.0.0 114 | */ 115 | tables(): Promise; 116 | /** 117 | * Delete a table 118 | * @param options: capTableStorageOptions 119 | * @returns Promise 120 | * @since 3.0.0 121 | */ 122 | deleteTable(options: capTableStorageOptions): Promise; 123 | /** 124 | * Import a database From a JSON 125 | * @param jsonstring string 126 | * @returns Promise 127 | * @since 3.2.0 128 | */ 129 | importFromJson( 130 | options: capStoreImportOptions, 131 | ): Promise; 132 | /** 133 | * Check the validity of a JSON Object 134 | * @param jsonstring string 135 | * @returns Promise 136 | * @since 3.2.0 137 | */ 138 | isJsonValid(options: capStoreImportOptions): Promise; 139 | /** 140 | * Export the given database to a JSON Object 141 | * @returns Promise 142 | * @since 3.2.0 143 | */ 144 | exportToJson(): Promise; 145 | } 146 | 147 | export interface capOpenStorageOptions { 148 | /** 149 | * The storage database name 150 | */ 151 | database?: string; // default: 152 | // ios, android: storageSQLite 153 | // web : storageIDB 154 | /** 155 | * The storage table name 156 | */ 157 | table?: string; // default: 158 | // ios, android: storage_table 159 | // web: storage_store 160 | /** 161 | * Set to true for database encryption 162 | */ 163 | encrypted?: boolean; // only for ios and android 164 | /*** 165 | * Set the mode for database encryption 166 | * ["encryption", "secret","newsecret"] 167 | */ 168 | mode?: string; // only for ios and android 169 | } 170 | export interface capDataStorageOptions { 171 | /** 172 | * The data name 173 | */ 174 | key: string; 175 | /** 176 | * The data value when required 177 | */ 178 | value?: string; 179 | } 180 | export interface capStorageOptions { 181 | /** 182 | * The storage name 183 | */ 184 | database: string; 185 | } 186 | 187 | export interface capTableStorageOptions { 188 | /** 189 | * The storage table name 190 | */ 191 | table: string; 192 | } 193 | export interface capFilterStorageOptions { 194 | /** 195 | * The filter data for filtering keys 196 | * 197 | * ['%filter', 'filter', 'filter%'] for 198 | * [starts with filter, contains filter, ends with filter] 199 | */ 200 | filter: string; 201 | } 202 | 203 | export interface capDataStorageResult { 204 | /** 205 | * result set to true when successful else false 206 | */ 207 | result?: boolean; 208 | /** 209 | * a returned message 210 | */ 211 | message?: string; 212 | } 213 | export interface capValueResult { 214 | /** 215 | * the data value for a given data key 216 | */ 217 | value: string; 218 | } 219 | export interface capKeysResult { 220 | /** 221 | * the data key list as an Array 222 | */ 223 | keys: string[]; 224 | } 225 | export interface capValuesResult { 226 | /** 227 | * the data values list as an Array 228 | */ 229 | values: string[]; 230 | } 231 | export interface capKeysValuesResult { 232 | /** 233 | * the data keys/values list as an Array of {key:string,value:string} 234 | */ 235 | keysvalues: any[]; 236 | } 237 | export interface capTablesResult { 238 | /** 239 | * the tables list as an Array 240 | */ 241 | tables: string[]; 242 | } 243 | export interface JsonStore { 244 | /** 245 | * The database name 246 | */ 247 | database: string; 248 | /** 249 | * Set to true (database encryption) / false 250 | * iOS & Android only 251 | */ 252 | encrypted: boolean; 253 | /*** 254 | * Array of Table (JsonTable) 255 | */ 256 | tables: JsonTable[]; 257 | } 258 | export interface JsonTable { 259 | /** 260 | * The database name 261 | */ 262 | name: string; 263 | /*** 264 | * Array of Values (capDataStorageOptions) 265 | */ 266 | values?: capDataStorageOptions[]; 267 | } 268 | 269 | export interface capDataStorageChanges { 270 | /** 271 | * the number of changes from an importFromJson command 272 | */ 273 | changes?: number; 274 | } 275 | export interface capStoreImportOptions { 276 | /** 277 | * Set the JSON object to import 278 | * 279 | */ 280 | jsonstring?: string; 281 | } 282 | export interface capStoreJson { 283 | /** 284 | * an export JSON object 285 | */ 286 | export?: JsonStore; 287 | } 288 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { registerPlugin } from "@capacitor/core"; 2 | 3 | import type { CapgoCapacitorDataStorageSqlitePlugin } from "./definitions"; 4 | 5 | const CapgoCapacitorDataStorageSqlite = 6 | registerPlugin( 7 | "CapgoCapacitorDataStorageSqlite", 8 | { 9 | web: () => 10 | import("./web").then((m) => new m.CapgoCapacitorDataStorageSqliteWeb()), 11 | electron: () => 12 | (window as any).CapacitorCustomPlatform.plugins 13 | .CapacitorDataStorageSqlite, 14 | }, 15 | ); 16 | 17 | export * from "./definitions"; 18 | export { CapgoCapacitorDataStorageSqlite }; 19 | -------------------------------------------------------------------------------- /src/web-utils/Data.ts: -------------------------------------------------------------------------------- 1 | export class Data { 2 | id?: number; 3 | name?: string; 4 | value?: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/web-utils/StorageDatabaseHelper.ts: -------------------------------------------------------------------------------- 1 | //import LocalForage from 'jeep-localforage'; 2 | import localForage from "localforage"; 3 | 4 | import type { 5 | capDataStorageOptions, 6 | JsonStore, 7 | JsonTable, 8 | } from "../definitions"; 9 | 10 | import { Data } from "./Data"; 11 | 12 | //const DATABASE: string = "storageIDB"; 13 | //const STORAGESTORE: string = "storage_store"; 14 | export class StorageDatabaseHelper { 15 | private _db: any = null; 16 | private _dbName: string; 17 | private _tableName: string; 18 | 19 | constructor(dbName: string, tableName: string) { 20 | const res: boolean = this.openStore(dbName, tableName); 21 | if (res) { 22 | this._dbName = dbName; 23 | this._tableName = tableName; 24 | } else { 25 | this._dbName = ""; 26 | this._tableName = ""; 27 | throw new Error("openStore return false"); 28 | } 29 | } 30 | openStore(dbName: string, tableName: string): boolean { 31 | let ret = false; 32 | const config: any = this.setConfig(dbName, tableName); 33 | this._db = localForage.createInstance(config); 34 | if (this._db != null) { 35 | this._dbName = dbName; 36 | ret = true; 37 | } 38 | return ret; 39 | } 40 | setConfig(dbName: string, tableName: string): any { 41 | const config: any = { 42 | name: dbName, 43 | storeName: tableName, 44 | driver: [localForage.INDEXEDDB, localForage.WEBSQL], 45 | version: 1, 46 | }; 47 | return config; 48 | } 49 | async setTable(tableName: string): Promise { 50 | const res: boolean = this.openStore(this._dbName, tableName); 51 | if (res) { 52 | return Promise.resolve(); 53 | } else { 54 | return Promise.reject(new Error("openStore return false")); 55 | } 56 | } 57 | async isTable(table: string): Promise { 58 | if (this._db == null) { 59 | return Promise.reject(`isTable: this.db is null`); 60 | } 61 | try { 62 | let ret = false; 63 | const tables: string[] = await this.tables(); 64 | if (tables.includes(table)) ret = true; 65 | return Promise.resolve(ret); 66 | } catch (err) { 67 | return Promise.reject(err); 68 | } 69 | } 70 | 71 | async tables(): Promise { 72 | return new Promise((resolve, reject) => { 73 | // Let us open our database 74 | const DBOpenRequest = window.indexedDB.open(this._dbName); 75 | // these two event handlers act on the database being opened successfully, or not 76 | DBOpenRequest.onerror = () => { 77 | return reject(`Error loading database ${this._dbName}`); 78 | }; 79 | 80 | DBOpenRequest.onsuccess = () => { 81 | let result: string[] = []; 82 | const db = DBOpenRequest.result; 83 | const retList = db.objectStoreNames; 84 | const values = Object.values(retList); 85 | for (const val of values) { 86 | if (val.substring(0, 12) != "local-forage") { 87 | result = [...result, val]; 88 | } 89 | } 90 | return resolve(result); 91 | }; 92 | }); 93 | } 94 | async set(data: Data): Promise { 95 | try { 96 | await this._db.setItem(data.name, data.value); 97 | return Promise.resolve(); 98 | } catch (err) { 99 | return Promise.reject(err); 100 | } 101 | } 102 | 103 | async get(name: string): Promise { 104 | try { 105 | const value: string = await this._db.getItem(name); 106 | const data: Data = new Data(); 107 | data.name = name; 108 | data.value = value; 109 | return Promise.resolve(data); 110 | } catch (err) { 111 | return Promise.reject(err); 112 | } 113 | } 114 | 115 | async remove(name: string): Promise { 116 | return this._db 117 | .removeItem(name) 118 | .then(() => { 119 | return Promise.resolve(); 120 | }) 121 | .catch((error: string) => { 122 | return Promise.reject(error); 123 | }); 124 | } 125 | 126 | async clear(): Promise { 127 | return this._db 128 | .clear() 129 | .then(() => { 130 | return Promise.resolve(); 131 | }) 132 | .catch((error: string) => { 133 | return Promise.reject(error); 134 | }); 135 | } 136 | 137 | async keys(): Promise { 138 | return this._db 139 | .keys() 140 | .then((keys: string[]) => { 141 | return Promise.resolve(keys); 142 | }) 143 | .catch((error: string) => { 144 | return Promise.reject(error); 145 | }); 146 | } 147 | 148 | async values(): Promise { 149 | const values: string[] = []; 150 | return this._db 151 | .iterate((value: string) => { 152 | values.push(value); 153 | }) 154 | .then(() => { 155 | return Promise.resolve(values); 156 | }) 157 | .catch((error: string) => { 158 | return Promise.reject(error); 159 | }); 160 | } 161 | 162 | async keysvalues(): Promise { 163 | const keysvalues: Data[] = []; 164 | return this._db 165 | .iterate((value: string, key: string) => { 166 | const data: Data = new Data(); 167 | data.name = key; 168 | data.value = value; 169 | keysvalues.push(data); 170 | }) 171 | .then(() => { 172 | return Promise.resolve(keysvalues); 173 | }) 174 | .catch((error: string) => { 175 | return Promise.reject(error); 176 | }); 177 | } 178 | 179 | async iskey(name: string): Promise { 180 | return this.get(name) 181 | .then((data) => { 182 | if (data.value != null) { 183 | return Promise.resolve(true); 184 | } else { 185 | return Promise.resolve(false); 186 | } 187 | }) 188 | .catch((error: string) => { 189 | return Promise.reject(error); 190 | }); 191 | } 192 | async importJson(values: capDataStorageOptions[]): Promise { 193 | let changes = 0; 194 | for (const val of values) { 195 | try { 196 | const data: Data = new Data(); 197 | data.name = val.key; 198 | data.value = val.value; 199 | await this.set(data); 200 | changes += 1; 201 | } catch (err) { 202 | return Promise.reject(err); 203 | } 204 | } 205 | return Promise.resolve(changes); 206 | } 207 | async exportJson(): Promise { 208 | const retJson: JsonStore = {} as JsonStore; 209 | const prevTableName: string = this._tableName; 210 | try { 211 | retJson.database = this._dbName.slice(0, -3); 212 | retJson.encrypted = false; 213 | retJson.tables = []; 214 | // get the table list 215 | const tables: string[] = await this.tables(); 216 | for (const table of tables) { 217 | this._tableName = table; 218 | const retTable: JsonTable = {} as JsonTable; 219 | retTable.name = table; 220 | retTable.values = []; 221 | const res: boolean = this.openStore(this._dbName, this._tableName); 222 | if (res) { 223 | const dataTable: Data[] = await this.keysvalues(); 224 | for (const tdata of dataTable) { 225 | const retData: capDataStorageOptions = {} as capDataStorageOptions; 226 | if (tdata.name != null) { 227 | retData.key = tdata.name; 228 | retData.value = tdata.value; 229 | retTable.values = [...retTable.values, retData]; 230 | } else { 231 | return Promise.reject("Data.name is undefined"); 232 | } 233 | } 234 | retJson.tables = [...retJson.tables, retTable]; 235 | } else { 236 | const msg = `Could not open ${this._dbName} ${this._tableName} `; 237 | this._tableName = prevTableName; 238 | return Promise.reject(msg); 239 | } 240 | } 241 | this._tableName = prevTableName; 242 | const res: boolean = this.openStore(this._dbName, this._tableName); 243 | if (res) { 244 | return Promise.resolve(retJson); 245 | } else { 246 | const msg = `Could not open ${this._dbName} ${this._tableName} `; 247 | return Promise.reject(msg); 248 | } 249 | } catch (err) { 250 | this._tableName = prevTableName; 251 | return Promise.reject(err); 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /src/web-utils/json-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * IsJsonSQLite 3 | * @param obj 4 | */ 5 | export const isJsonStore = (obj: any): boolean => { 6 | const keyFirstLevel: string[] = ["database", "encrypted", "tables"]; 7 | if ( 8 | obj == null || 9 | (Object.keys(obj).length === 0 && obj.constructor === Object) 10 | ) 11 | return false; 12 | for (const key of Object.keys(obj)) { 13 | if (keyFirstLevel.indexOf(key) === -1) return false; 14 | if (key === "database" && typeof obj[key] != "string") return false; 15 | if (key === "encrypted" && typeof obj[key] != "boolean") return false; 16 | if (key === "tables" && typeof obj[key] != "object") return false; 17 | if (key === "tables") { 18 | for (const oKey of obj[key]) { 19 | const retTable: boolean = isTable(oKey); 20 | if (!retTable) return false; 21 | } 22 | } 23 | } 24 | return true; 25 | }; 26 | /** 27 | * IsTable 28 | * @param obj 29 | */ 30 | export const isTable = (obj: any): boolean => { 31 | const keyTableLevel: string[] = ["name", "values"]; 32 | if ( 33 | obj == null || 34 | (Object.keys(obj).length === 0 && obj.constructor === Object) 35 | ) { 36 | return false; 37 | } 38 | for (const key of Object.keys(obj)) { 39 | if (keyTableLevel.indexOf(key) === -1) return false; 40 | if (key === "name" && typeof obj[key] != "string") return false; 41 | if (key === "values" && typeof obj[key] != "object") return false; 42 | if (key === "values") { 43 | for (const oKey of obj[key]) { 44 | const retValue: boolean = isValue(oKey); 45 | if (!retValue) return false; 46 | } 47 | } 48 | } 49 | return true; 50 | }; 51 | /** 52 | * IsValue 53 | * @param obj 54 | */ 55 | export const isValue = (obj: any): boolean => { 56 | const keyTableLevel: string[] = ["key", "value"]; 57 | if ( 58 | obj == null || 59 | (Object.keys(obj).length === 0 && obj.constructor === Object) 60 | ) { 61 | return false; 62 | } 63 | for (const key of Object.keys(obj)) { 64 | if (keyTableLevel.indexOf(key) === -1) return false; 65 | if (key === "key" && typeof obj[key] != "string") return false; 66 | if (key === "value" && typeof obj[key] != "string") return false; 67 | } 68 | return true; 69 | }; 70 | -------------------------------------------------------------------------------- /src/web.ts: -------------------------------------------------------------------------------- 1 | import { WebPlugin } from "@capacitor/core"; 2 | 3 | import type { 4 | CapgoCapacitorDataStorageSqlitePlugin, 5 | capDataStorageOptions, 6 | capDataStorageResult, 7 | capFilterStorageOptions, 8 | capKeysResult, 9 | capKeysValuesResult, 10 | capTablesResult, 11 | capOpenStorageOptions, 12 | capTableStorageOptions, 13 | capValueResult, 14 | capValuesResult, 15 | capStorageOptions, 16 | JsonStore, 17 | capStoreJson, 18 | capDataStorageChanges, 19 | capStoreImportOptions, 20 | } from "./definitions"; 21 | import { Data } from "./web-utils/Data"; 22 | import { StorageDatabaseHelper } from "./web-utils/StorageDatabaseHelper"; 23 | import { isJsonStore } from "./web-utils/json-utils"; 24 | 25 | export class CapgoCapacitorDataStorageSqliteWeb 26 | extends WebPlugin 27 | implements CapgoCapacitorDataStorageSqlitePlugin 28 | { 29 | private mDb!: StorageDatabaseHelper; 30 | 31 | async openStore(options: capOpenStorageOptions): Promise { 32 | const dbName = options.database ? `${options.database}IDB` : "storageIDB"; 33 | const tableName = options.table ? options.table : "storage_store"; 34 | try { 35 | this.mDb = new StorageDatabaseHelper(dbName, tableName); 36 | return Promise.resolve(); 37 | } catch (err: any) { 38 | return Promise.reject(`OpenStore: ${err.message}`); 39 | } 40 | } 41 | async closeStore(options: capStorageOptions): Promise { 42 | throw new Error(`Method closeStore not implemented. ${options}`); 43 | } 44 | async isStoreOpen(options: capStorageOptions): Promise { 45 | throw new Error(`Method isStoreOpen not implemented. ${options}`); 46 | } 47 | async isStoreExists( 48 | options: capStorageOptions, 49 | ): Promise { 50 | throw new Error(`Method isStoreExists not implemented. ${options}`); 51 | } 52 | async setTable(options: capTableStorageOptions): Promise { 53 | const tableName = options.table; 54 | if (tableName == null) { 55 | return Promise.reject("SetTable: Must provide a table name"); 56 | } 57 | if (this.mDb) { 58 | try { 59 | await this.mDb.setTable(tableName); 60 | return Promise.resolve(); 61 | } catch (err: any) { 62 | return Promise.reject(`SetTable: ${err.message}`); 63 | } 64 | } else { 65 | return Promise.reject("SetTable: Must open a store first"); 66 | } 67 | } 68 | async set(options: capDataStorageOptions): Promise { 69 | const key: string = options.key; 70 | if (key == null || typeof key != "string") { 71 | return Promise.reject("Set: Must provide key as string"); 72 | } 73 | 74 | const value = options.value ? options.value : null; 75 | if (value == null || typeof value != "string") { 76 | return Promise.reject("Set: Must provide value as string"); 77 | } 78 | const data: Data = new Data(); 79 | data.name = key; 80 | data.value = value; 81 | try { 82 | await this.mDb.set(data); 83 | return Promise.resolve(); 84 | } catch (err: any) { 85 | return Promise.reject(`Set: ${err.message}`); 86 | } 87 | } 88 | async get(options: capDataStorageOptions): Promise { 89 | const key: string = options.key; 90 | if (key == null || typeof key != "string") { 91 | return Promise.reject("Get: Must provide key as string"); 92 | } 93 | try { 94 | const data: Data = await this.mDb.get(key); 95 | if (data?.value != null) { 96 | return Promise.resolve({ value: data.value }); 97 | } else { 98 | return Promise.resolve({ value: "" }); 99 | } 100 | } catch (err: any) { 101 | return Promise.reject(`Get: ${err.message}`); 102 | } 103 | } 104 | async remove(options: capDataStorageOptions): Promise { 105 | const key: string = options.key; 106 | if (key == null || typeof key != "string") { 107 | return Promise.reject("Remove: Must provide key as string"); 108 | } 109 | try { 110 | await this.mDb.remove(key); 111 | return Promise.resolve(); 112 | } catch (err: any) { 113 | return Promise.reject(`Remove: ${err.message}`); 114 | } 115 | } 116 | async clear(): Promise { 117 | try { 118 | await this.mDb.clear(); 119 | return Promise.resolve(); 120 | } catch (err: any) { 121 | return Promise.reject(`Clear: ${err.message}`); 122 | } 123 | } 124 | async iskey(options: capDataStorageOptions): Promise { 125 | const key: string = options.key; 126 | if (key == null || typeof key != "string") { 127 | return Promise.reject("Iskey: Must provide key as string"); 128 | } 129 | try { 130 | const ret: boolean = await this.mDb.iskey(key); 131 | return Promise.resolve({ result: ret }); 132 | } catch (err: any) { 133 | return Promise.reject(`Iskey: ${err.message}`); 134 | } 135 | } 136 | async keys(): Promise { 137 | try { 138 | const ret: string[] = await this.mDb.keys(); 139 | return Promise.resolve({ keys: ret }); 140 | } catch (err: any) { 141 | return Promise.reject(`Keys: ${err.message}`); 142 | } 143 | } 144 | async values(): Promise { 145 | try { 146 | const ret: string[] = await this.mDb.values(); 147 | return Promise.resolve({ values: ret }); 148 | } catch (err: any) { 149 | return Promise.reject(`Values: ${err.message}`); 150 | } 151 | } 152 | async filtervalues( 153 | options: capFilterStorageOptions, 154 | ): Promise { 155 | const filter: string = options.filter; 156 | if (filter == null || typeof filter != "string") { 157 | return Promise.reject("Filtervalues: Must provide filter as string"); 158 | } 159 | let regFilter: RegExp; 160 | if (filter.startsWith("%")) { 161 | regFilter = new RegExp("^" + filter.substring(1), "i"); 162 | } else if (filter.endsWith("%")) { 163 | regFilter = new RegExp(filter.slice(0, -1) + "$", "i"); 164 | } else { 165 | regFilter = new RegExp(filter, "i"); 166 | } 167 | try { 168 | const ret: string[] = []; 169 | 170 | const results: Data[] = await this.mDb.keysvalues(); 171 | for (const result of results) { 172 | if (result.name != null && regFilter.test(result.name)) { 173 | if (result.value != null) { 174 | ret.push(result.value); 175 | } else { 176 | return Promise.reject(`Filtervalues: result.value is null`); 177 | } 178 | } 179 | } 180 | return Promise.resolve({ values: ret }); 181 | } catch (err: any) { 182 | return Promise.reject(`Filtervalues: ${err.message}`); 183 | } 184 | } 185 | async keysvalues(): Promise { 186 | try { 187 | const ret: any[] = []; 188 | const results: Data[] = await this.mDb.keysvalues(); 189 | for (const result of results) { 190 | if (result.name != null && result.value != null) { 191 | const res: any = { key: result.name, value: result.value }; 192 | ret.push(res); 193 | } else { 194 | return Promise.reject(`Keysvalues: result.name/value are null`); 195 | } 196 | } 197 | return Promise.resolve({ keysvalues: ret }); 198 | } catch (err: any) { 199 | return Promise.reject(`Keysvalues: ${err.message}`); 200 | } 201 | } 202 | async deleteStore(options: capOpenStorageOptions): Promise { 203 | throw new Error(`Method deleteStore not implemented. ${options}`); 204 | } 205 | async isTable( 206 | options: capTableStorageOptions, 207 | ): Promise { 208 | const table = options.table; 209 | if (table == null) { 210 | return Promise.reject("Must provide a Table Name"); 211 | } 212 | try { 213 | const ret = await this.mDb.isTable(table); 214 | return Promise.resolve({ result: ret }); 215 | } catch (err) { 216 | return Promise.reject(err); 217 | } 218 | } 219 | async tables(): Promise { 220 | try { 221 | const ret = await this.mDb.tables(); 222 | return Promise.resolve({ tables: ret }); 223 | } catch (err) { 224 | return Promise.reject(err); 225 | } 226 | } 227 | async deleteTable(options: capTableStorageOptions): Promise { 228 | throw new Error(`Method deleteTable not implemented. ${options}`); 229 | } 230 | async importFromJson( 231 | options: capStoreImportOptions, 232 | ): Promise { 233 | const keys = Object.keys(options); 234 | if (!keys.includes("jsonstring")) { 235 | return Promise.reject("Must provide a json object"); 236 | } 237 | let totalChanges = 0; 238 | 239 | if (options?.jsonstring) { 240 | const jsonStrObj: string = options.jsonstring; 241 | const jsonObj = JSON.parse(jsonStrObj); 242 | const isValid = isJsonStore(jsonObj); 243 | if (!isValid) { 244 | return Promise.reject("Must provide a valid JsonSQLite Object"); 245 | } 246 | const vJsonObj: JsonStore = jsonObj; 247 | const dbName = vJsonObj.database 248 | ? `${vJsonObj.database}IDB` 249 | : "storageIDB"; 250 | for (const table of vJsonObj.tables) { 251 | const tableName = table.name ? table.name : "storage_store"; 252 | try { 253 | this.mDb = new StorageDatabaseHelper(dbName, tableName); 254 | // Open the database 255 | const bRet: boolean = this.mDb.openStore(dbName, tableName); 256 | if (bRet) { 257 | // Import the JsonSQLite Object 258 | if (table?.values) { 259 | const changes = await this.mDb.importJson(table.values); 260 | totalChanges += changes; 261 | } 262 | } else { 263 | return Promise.reject( 264 | `Open store: ${dbName} : table: ${tableName} failed`, 265 | ); 266 | } 267 | } catch (err: any) { 268 | return Promise.reject(`ImportFromJson: ${err.message}`); 269 | } 270 | } 271 | return Promise.resolve({ changes: totalChanges }); 272 | } else { 273 | return Promise.reject("Must provide a json object"); 274 | } 275 | } 276 | async isJsonValid( 277 | options: capStoreImportOptions, 278 | ): Promise { 279 | const keys = Object.keys(options); 280 | if (!keys.includes("jsonstring")) { 281 | return Promise.reject("Must provide a json object"); 282 | } 283 | if (options?.jsonstring) { 284 | const jsonStrObj: string = options.jsonstring; 285 | const jsonObj = JSON.parse(jsonStrObj); 286 | const isValid = isJsonStore(jsonObj); 287 | if (!isValid) { 288 | return Promise.reject("Stringify Json Object not Valid"); 289 | } else { 290 | return Promise.resolve({ result: true }); 291 | } 292 | } else { 293 | return Promise.reject("Must provide in options a stringify Json Object"); 294 | } 295 | } 296 | async exportToJson(): Promise { 297 | try { 298 | const ret: JsonStore = await this.mDb.exportJson(); 299 | return Promise.resolve({ export: ret }); 300 | } catch (err) { 301 | return Promise.reject(`exportToJson: ${err}`); 302 | } 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnreachableCode": false, 4 | "declaration": true, 5 | "esModuleInterop": true, 6 | "inlineSources": true, 7 | "lib": ["dom", "es2017"], 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "noFallthroughCasesInSwitch": true, 11 | "noUnusedLocals": true, 12 | "noUnusedParameters": true, 13 | "outDir": "dist/esm", 14 | "pretty": true, 15 | "sourceMap": true, 16 | "strict": true, 17 | "target": "es2017" 18 | }, 19 | "files": ["src/index.ts"] 20 | } 21 | --------------------------------------------------------------------------------