",
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 |
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 |
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 |
--------------------------------------------------------------------------------