capacitor-community / sqlite

⚡Capacitor plugin for native & electron SQLite databases.
MIT License
506 stars 121 forks source link

Documentation improvements collection #257

Open tobiasmuecksch opened 2 years ago

tobiasmuecksch commented 2 years ago

In this issue, I want to collect topics and improvements for the documentation.

FAQ:

Maybe we could implement some documentation website with a framework like https://github.com/facebook/docusaurus

tobiasmuecksch commented 2 years ago

Issues to consider for information gathering:

tobiasmuecksch commented 2 years ago

@jepiqueau Could you give me some explanation for this question?

"What is the difference between run, query, execute and executeSet?"

jepiqueau commented 2 years ago

@tobiasmuecksch Query is for select statement Execute is for executing a set of raw statement given in a string. Run is for executing one raw statement Insert, Update, Delete with given values meaning that you prépare the statement and bind the values if any ExecuteSet is to run on or more raw statements and bind them with values or an array of values . Hope this clarify

jepiqueau commented 2 years ago

@tobiasmuecksch on Electron you do not need to use saveToStore. This is only for the Web platform

tobiasmuecksch commented 2 years ago

@tobiasmuecksch on Electron you do not need to use saveToStore. This is only for the Web platform

My bad. I fixed the issue description.

jepiqueau commented 2 years ago

@tobiasmuecksch i just issue a new Ionic/Angular app demonstrating how to use the @capacitor-community/sqlite plugin to synchronize with a remote server database by using the import & export of Json Object. The deleted rows are now well managed. Look at angular-sqlite-synchronize-app, hope this will clarify

rakibul111 commented 2 years ago

@jepiqueau can you please guide me how can I use this sqlite plugin with nextjs-ionic setup. Note: I don't know typescript

jepiqueau commented 2 years ago

@rakibul111 exactely the same way that for react, vue, solidjs or angular.

jepiqueau commented 2 years ago

@rakibul111 Npm i -- save @capacitor/core Npm i --save-dev @capacitor/cli Npm i --save @capacitor/ios and Android Npx cap init yourappname yourappid Npm run build Npx cap add ios Npx cap add android Npx cap sync Npm run build Npx cap copy Npx cap open ios Npx cap open android Thatis it

rakibul111 commented 2 years ago

@jepiqueau where to setup for jeep-sqlite?

rakibul111 commented 2 years ago

@jepiqueau Uncaught (in promise) RuntimeError: Aborted(LinkError: WebAssembly.instantiate(): Import #33 module="a" function="I" error: function import requires a callable). Build with -s ASSERTIONS=1 for more info. at L (jeep-sqlite.entry.js:2591:71) at jeep-sqlite.entry.js:2641:387

tobiasmuecksch commented 2 years ago

This is not the right issue for this discussion. Please open a new issue for that.

jepiqueau commented 2 years ago

@rakibul111 as mentioned by @tobiasmuecksch this is not the right place. Any how delete the sql-wasm.wasm file from your assets folder and copy the one from the node_modules/sql.js/dist/sql_wasm.wasm to your asset folder this should solve the issue

jhuenges commented 1 year ago

I also have a suggestion for the documentation:

What happens if the user deletes the app?

Were is the database stored on the phone?

@jepiqueau If you can answer these questions, I can create a pull request to add this information.

jepiqueau commented 1 year ago

@jhuenges thanks for your question showing à n interest in the plugin i will answer to those questions and you will be free to create a PR for this as i am quite busy by the maintenance and new features implementation

jhuenges commented 1 year ago

I did some research and with my limited knowledge I came to the conclusion that:

What happens if the user deletes the app?

Were is the database stored on the phone?

Disclaimer: This is my first adventure into Swift and Java and the iOS and Android ecosystem. So I have little confidence in what I gathered. Any confirmation or correction is greatly appreciated!

jepiqueau commented 1 year ago

@jhuenges thanks for this and sorry to have not find the time to answer you. Your research is pretty find. The database are stored in the location that you define in the capacitor.config.ts file.on iOS if the folder is Library the databases are not backup on iCloud. If it id Documents they are. On Android read the Android quirks and the change in the manifest file to not backup them.

mburger81 commented 1 year ago

@jepiqueau first of all thx you for this great plugin,

I would like to make a question to you, we need to use the plugin with native encryption. For me it's not clear, even because I don't find the informations on the documentation how is the best practice to encrypt the database.

In the documentation I can see the capacitor configuration parameters, like iosIsEncryption and androidIsEncryption, so i think this is the point where we should decide if a database is encrypted or not?

But at the other way, I see in the createConnection command two parameters, encrypted and mode.

So my first question is, how matters the encrypted parameter of the createConnection command with the iosIsEncryption parameters from the capacitor configuration?

And my second question is, Im not really sure how to use the mode parameter. Do I have to switch this mode between the first DB open and the second DB open? Is it possible to show a best practice workflow to use your plugin with sqlite encrypted?

thx a lot

jepiqueau commented 1 year ago

@mburger81 A documentation has been added DatabaseEncryption. Hope this will help you to understand the workflow

mmouterde commented 1 year ago

I'm just starting with this sqlite plugin, I hope this will be relevant.

My point is about the IncrementalUpgrade feature documentation.

During my tests on web platform my addUpgradeStatement does not throw error, but has no effect ?! As well as with an empty database as with an existing version.

jepiqueau commented 1 year ago

@mmouterde look at ionic7-angular-sqlite-app and at the blog tutorials-app at https://github.com/jepiqueau

mmouterde commented 1 year ago

This tuto is not really easy to follow as the final workflow is split into several services. Anyway, that a great, complete and verbose work that helps me. thanks @jepiqueau !

If it could help someone, Here is my working resulting version in a single file src/services/databaseService. databaseService.init() is simply called from App.vue.

Tested with Quasar+vue3+vite+capacitor (web+android)

import { Platform } from 'quasar';
import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';
import { version1 } from 'src/migrations/version1';
import { JeepSqlite } from 'jeep-sqlite/dist/components/jeep-sqlite';

const DATABASE_NAME = 'db_name'
const DATABASE_CURRENT_VERSION = 1;

const sqlite: SQLiteConnection = new SQLiteConnection(CapacitorSQLite);

export async function init() {
    customElements.define('jeep-sqlite', JeepSqlite);
    window.addEventListener('DOMContentLoaded', async () => {
        try {
            if (!Platform.is.capacitor) {
                const jeepSqlite = document.createElement('jeep-sqlite');
                document.body.appendChild(jeepSqlite);
                await customElements.whenDefined('jeep-sqlite');
                await sqlite.initWebStore();
            }

            await CapacitorSQLite.addUpgradeStatement({ database: DATABASE_NAME, upgrade: [version1] });

            const ret = await sqlite.checkConnectionsConsistency();
            const isConn = (await sqlite.isConnection(DATABASE_NAME, false)).result;
            let db: SQLiteDBConnection;
            if (ret.result && isConn) {
                db = await sqlite.retrieveConnection(DATABASE_NAME, false);
            } else {
                db = await sqlite.createConnection(
                    DATABASE_NAME,
                    false,
                    'no-encryption',
                    DATABASE_CURRENT_VERSION,
                    false,
                );
            }
            await db.open();
        } catch (err) {
            console.log(`Error: ${err}`);
            throw new Error(`Error: ${err}`);
        }
    });
}
<template>
    <q-layout>
        <router-view />
    </q-layout>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { init } from 'src/services/databaseService';
export default defineComponent({ name: 'App'});
init();
</script>

To going back to the goal of this issue, I guess IncrementalUpgrade part is still confusing as :

jepiqueau commented 1 year ago

@mmouterde Sorry the documentation has not been updated. i focus my attention in providing tutorials. look at link to tuorials and specifically for vue3 at Vue3-Web and Vue3-Native. These tutorials are based on the latest version of Ionic7 and are using Vue with Vite. The upgrade statement must be defined prior to any connection to the database and are read and implemented when you make the connection to the database with the desired version number. This should help you to start.

jepiqueau commented 1 year ago

@mmouterde What is important is to define the service as unique throughout your application and i do not know how to do that with Quasar as the App.Vue i s something like this

<template>
  <router-view />
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import { Capacitor } from '@capacitor/core';
import { JeepSqlite } from 'jeep-sqlite/dist/components/jeep-sqlite';

export default defineComponent({
  name: 'App',
});
</script>

so if i define a setup method i cannot use this.

mmouterde commented 1 year ago

Hum, ok, in this case it would be better to use boot files hook from Quasar. from src/boot/sqlite.ts

import { boot } from 'quasar/wrappers';
import { init } from 'src/services/databaseService';

export default boot(() => {
    return init();
});

And then configure boot scripts option in quasar.config.js :

   boot: ['i18n', 'axios', 'sqlite' /*<=*/ ],

According to my tests, the DOMContentLoaded event has already occurred when boot scripts run. I had to remove the window.addEventListener('DOMContentLoaded',...) from my previous init() implementation :

import { Platform } from 'quasar';
import { CapacitorSQLite, SQLiteConnection, SQLiteDBConnection } from '@capacitor-community/sqlite';
import { version1 } from 'src/migrations/version1';
import { JeepSqlite } from 'jeep-sqlite/dist/components/jeep-sqlite';

const DATABASE_NAME = 'db_name'
const DATABASE_CURRENT_VERSION = 1;

const sqlite: SQLiteConnection = new SQLiteConnection(CapacitorSQLite);

export async function init() {
        customElements.define('jeep-sqlite', JeepSqlite);
        try {
            if (!Platform.is.capacitor) {
                const jeepSqlite = document.createElement('jeep-sqlite');
                document.body.appendChild(jeepSqlite);
                await customElements.whenDefined('jeep-sqlite');
                await sqlite.initWebStore();
            }

            await CapacitorSQLite.addUpgradeStatement({ database: DATABASE_NAME, upgrade: [version1] });

            const ret = await sqlite.checkConnectionsConsistency();
            const isConn = (await sqlite.isConnection(DATABASE_NAME, false)).result;
            let db: SQLiteDBConnection;
            if (ret.result && isConn) {
                db = await sqlite.retrieveConnection(DATABASE_NAME, false);
            } else {
                db = await sqlite.createConnection(
                    DATABASE_NAME,
                    false,
                    'no-encryption',
                    DATABASE_CURRENT_VERSION,
                    false,
                );
            }
            await db.open();
        } catch (err) {
            console.log(`Error: ${err}`);
            throw new Error(`Error: ${err}`);
        }
}
jepiqueau commented 1 year ago

@mmouterde In fact i did this and it works

<template>
  <router-view />
</template>

<script lang="ts">
import { defineComponent, createApp, onMounted } from 'vue';
import { Capacitor } from '@capacitor/core';
import { JeepSqlite } from 'jeep-sqlite/dist/components/jeep-sqlite';
import SqliteService from './services/sqliteService';
import DbVersionService from './services/dbVersionService';
import StorageService from './services/storageService';
import InitializeAppService from './services/initializeAppService';

export default defineComponent({
  name: 'App',
  setup() {
    customElements.define('jeep-sqlite', JeepSqlite);
    const app = createApp({});
    const platform = Capacitor.getPlatform();
    // Set the platform as global properties on the app
    app.config.globalProperties.$platform = platform;
    console.log('platform', app.config.globalProperties.$platform);
    // Define and instantiate the required services
    const sqliteServ = new SqliteService();
    const dbVersionServ = new DbVersionService();
    const storageServ = new StorageService(sqliteServ, dbVersionServ);
    // Set the services as global properties on the app
    app.config.globalProperties.$sqliteServ = sqliteServ;
    app.config.globalProperties.$dbVersionServ = dbVersionServ;
    app.config.globalProperties.$storageServ = storageServ;
    //Define and instantiate the InitializeAppService
    const initAppServ = new InitializeAppService(sqliteServ, storageServ);

    const initApp = async () => {
      try {
        await initAppServ.initializeApp();
      } catch (error) {
        console.error('App Initialization error:', error);
      }
    };
    onMounted(async () => {
      if (platform != 'web') {
        await initApp();
      } else {
        window.addEventListener('DOMContentLoaded', async () => {
          const jeepEl = document.createElement('jeep-sqlite');
          document.body.appendChild(jeepEl);
          customElements
            .whenDefined('jeep-sqlite')
            .then(async () => {
              await initApp();
            })
            .catch((err) => {
              console.error('jeep-sqlite creation error:', err);
            });
        });
      }
    });
    return {};
  },
});
</script>

the services are the same than in ionic7-vue-sqlite-app, the models and the upgrades are also the same

jepiqueau commented 1 year ago

@mmouterde you can remove the line window.addEventListener('DOMContentLoaded', async () => {as it is done in the onMounted method it is working too

jepiqueau commented 12 months ago

@mmouterde look at quasar-sqlite-app, For now only the web part is in the tutorial the native part will come next . Hope this will help you

jepiqueau commented 12 months ago

@tobiasmuecksch and all coming to that issue on documentation

To all, I know that the documentation is not up-to-date and part of it will be removed soon as it is difficult to maintain as Capacitor, the plugin and the Frameworks are continuously updated. So i will advise you to visit tutorials which are all compatible with Capacitor 5, Ionic 7 and @capacitor-community/sqlite@5.4.x. If some of you want to see others features, feel free to mention them or to participate in that effort, by creating new tutorials.