nativescript-sqlite icon indicating copy to clipboard operation
nativescript-sqlite copied to clipboard

missing method for backing up database

Open dmatora opened this issue 9 years ago • 7 comments

Each time i deploy app, my database changes are getting lost. Sqlite.copyDatabase is handy for restoring database from a backup, but it would be extremely helpful to have a way to backup it

dmatora avatar May 14 '16 13:05 dmatora

I'm also interested in that feature

thiagoufg avatar May 11 '17 21:05 thiagoufg

Not fully following the feature request now that I am looking into it. What exact issue are you trying to solve?

NathanaelA avatar Dec 07 '17 03:12 NathanaelA

@NathanaelA I also need the same feature. Sqlite.copyDatabase is handy but reverse should also be possible. We want in our apps for example ability for users to backup database/data and restore it after they uninstall app and install again.

sarfraznawaz2005 avatar Sep 09 '18 17:09 sarfraznawaz2005

I urgently require this feature. Every time I install a new version of my App, all existing data in SQLITE will be gone! Please provide a way to retain SQLITE data when install new App version!!!

leungkimming avatar Dec 16 '18 04:12 leungkimming

This is how I am doing it manually, it actually copies database to external storage and then I can restore it from within the app whenever needed. Not using copyDatabase() or any function of this package.

XML:

        <Label text="Backup Data" class="heading text-muted m-t-20" />

        <GridLayout columns="*, *" rows="auto">
            <Button col="0" text="&#xf093; Backup Data" class="btnSuccess" tap="{{ onBackupData }}" />
            <Button col="1" text="&#xf019; Restore Data" class="btnPrimary" tap="{{ onRestoreData }}" />
        </GridLayout>

Backup Restore JS Code:

const observable = require("data/observable");
const appSettings = require("application-settings");
const fileSystemModule = require("file-system");
const Toast = require("nativescript-toast");
const dialogs = require("ui/dialogs");
const permissions = require("nativescript-permissions");

const settings = new observable.Observable();

const packageName = "com.example.myApp";
const dbName = "backupName.db";

settings.onBackupData = function () {

    // ask for needed permissions
    permissions.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, "Please allow storage read permission for backup creation.")
        .then()
        .catch();

    permissions.requestPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, "Please allow storage write permission for backup reading.")
        .then()
        .catch();

    const rootPath = android.os.Environment.getExternalStorageDirectory().getAbsolutePath().toString();
    const path = fileSystemModule.path.join(rootPath, dbName);

    dialogs.confirm("Continue with data backup ?").then((result) => {
        if (result) {
            const source = `/data/data/${packageName}/databases/${dbName}`;

            copyAndroidFileUsingStream(source, path);
        }
    });
};

settings.onRestoreData = function () {

    // ask for needed permissions
    permissions.requestPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE, "Please allow storage read permission for backup creation.")
        .then()
        .catch();

    permissions.requestPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE, "Please allow storage write permission for backup reading.")
        .then()
        .catch();

    dialogs.confirm("Existing data will be lost, continue ?").then((result) => {
        if (result) {

            const rootPath = android.os.Environment.getExternalStorageDirectory().getAbsolutePath().toString();
            const source = fileSystemModule.path.join(rootPath, dbName);
            const path = `/data/data/${packageName}/databases/${dbName}`;
            console.log(source);

            copyAndroidFileUsingStream(source, path);
        }
    });
};

// works in android only
function copyAndroidFileUsingStream(source, dest) {
    let is = null;
    let os = null;

    try {
        is = new java.io.FileInputStream(source);
        os = new java.io.FileOutputStream(dest);
        // let buffer = Array.create("byte", 1024);
        const buffer = Array.create("byte", 4096);
        let length = 0;
        // tslint:disable-next-line:no-conditional-assignment
        while ((length = is.read(buffer)) > 0) {
            os.write(buffer, 0, length);
        }
    }
    catch (e) {
        this.errorService.handleError(e);
    }
    finally {
        console.log("copy done");
        Toast.makeText("Operation Completed!").show();
        is.close();
        os.close();
    }
}

exports.SettingsViewModel = settings;

The code uses two external packages that is nativescript-toast and nativescript-permissions, if you don't need it, modify the above code accordingly.

Also make sure to request for required permissions in manifest file:

	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

Hope that helps.

sarfraznawaz2005 avatar Dec 16 '18 05:12 sarfraznawaz2005

@sarfraznawaz2005 Thanks for your reply. Unfortunately I need to use JavaScript on IOS. Any other suggestion? Or, do you know a way that Nativescript sidekick "run on device" won't clean up my sqlite DB when building and running a new version.

leungkimming avatar Dec 16 '18 06:12 leungkimming

@leungkimming I haven't worked with IOS so I have no idea about it but I am sure there must be some way or command line way of pulling and pushing db in development mode similar to adb pull and adb push in android. So your best bet would be to ask this in IOS forum or support center.

sarfraznawaz2005 avatar Dec 16 '18 07:12 sarfraznawaz2005