an-rahulpandey / cordova-plugin-dbcopy

Copy SQLite Database from www folder to default app database location
Apache License 2.0
89 stars 47 forks source link

IsDBOnStorage() #40

Closed rafaellop closed 7 years ago

rafaellop commented 7 years ago

Mentioned in the issue https://github.com/an-rahulpandey/cordova-plugin-dbcopy/issues/38#issuecomment-284993235 here's are my concerns regarding the backup/restore process. What would be great is if there was a function for checking a database exists on a path. The current logic for importing/restoring a database is this:

1) close the currently open sqlite db at location 2) remove the current db from the location 3) copyDbFromStorage to the location 4) open the sqlite db copied from storage at location

And it works until at the step 3 there is the db in the storage. But if there's no db at the path then the default db is already removed and the app crashes.

The solution would be to have a function like isDbInStorage() which could be called before the whole process to check if there's anything to import/restore.

I suppose I could achieve this using the file plugin from cordova, but it seems that the function could be just built in the dbcopy plugin and the file plugin wouldn't be required for just this one function.

What do you think?

an-rahulpandey commented 7 years ago

Yes, that make sense. Let me do a quick edit.

rafaellop commented 7 years ago

By the way, will these both CopyDbToStorage() and CopyDbFromStorage() functions work on iOS? What would you suggest to use for a bullet proof destination path on the storage for this both OSes? Wouldn't be better to use the file plugin to find the paths instead of hardcode?

an-rahulpandey commented 7 years ago

It should work on iOS, but I didn't give much thought on iOS, at the time of creating this two functions.

What would you suggest to use for a bullet proof destination path on the storage for this both OSes? Wouldn't be better to use the file plugin to find the paths instead of hardcode?

let me know what dynamic path you are referring to? The static path ensure that dev know where to store the db and from where to copy the db.

rafaellop commented 7 years ago

The problem is that different Android versions used different paths for sdcards. As far as I'm reading the cordova-plugin-file https://github.com/apache/cordova-plugin-file I start to think that there's no way to avoid using it for finding a secure place for accessing external storage.

an-rahulpandey commented 7 years ago

Yes, I use window.resolveLocalFileSystemURL to get the native path. Also I have updated the code, now you can pass a fourth param called as deleteolddb to plugin. which will delete the old db if set to true, so need to call remove function before.

rafaellop commented 7 years ago

Are you sure the change is correct? First of all the readme says:

window.plugins.sqlDB.copyDbFromStorage(dbname, location, source, deleteolddb, success, error);

The sqlDB.js exports:

exports.copyDbFromStorage = function(dbname,location,source, deletedb, success,error){
  exec(success, error, "sqlDB", "copyDbFromStorage", [dbname, location, source, deletedb]);
};

but the sqlDB.java has:

private void copyDbFromStorage(String db, String src, boolean deletedb, final CallbackContext callbackContext)

Is the parameters inconsistency intended?

an-rahulpandey commented 7 years ago

I changed the readme to deleteolddb later, so that user can understand it better. I will update the rest of the code. Does it work properly?

rafaellop commented 7 years ago

Yes, but I found a function for checking if a file exists is better in the flow. Now I must close the DB before all operation and nevertheless the db file on the storage exists or not, the DB is closed and must be reopened even in the case of an error. It's nicer to check the storage backup copy exists before closing the current db. I have a working code now for the function (basing on yours) plus all the exports. I can publish it in minutes if you want.

an-rahulpandey commented 7 years ago

Yes, share the code. I think I misunderstood you.

rafaellop commented 7 years ago

Unfortunately I have to give up. I have added the code to all my local copies of the sqlDB.java file and also exports to the sqlDB.js and it is never called though I call it properly as the other functions. I'm not good at plugins so maybe you can implement this or maybe I did a small mistake somewhere. However, I cannot make it work. I've send my changes to the PR #42 #41 I don't have idea why it's not even called but the code is OK. Maybe you can make it works. The call for this is:

window.plugins.sqlDB.checkDbOnStorage('appDB.db', 0, '/storage/sdcard1/Android/data/com.appbundleid/' + 'appDB.db', 
   function() {
      console.log('SUCCESS')
   }, 
   function(e) {
      console.log('@@@@ ERROR ', JSON.stringify(e))
   });
an-rahulpandey commented 7 years ago

I have updated the code, check if it works. Also please the Readme file for using the function.

rafaellop commented 7 years ago

It works. Thanks!

By the way, do you plan to update the iOS sources with the recent changes?

an-rahulpandey commented 7 years ago

Yes, will do in a while or tomorrow.

rafaellop commented 7 years ago

Great, no hurry. Just asking if it is possible. I can also help in testing. Thanks!

rafaellop commented 7 years ago

As for a remark, regarding the hardcoded path to the external storage here are some good information about the Android external storage usage: https://mbcdev.com/2013/04/13/using-androids-external-storage-effectively-and-judiciously/

an-rahulpandey commented 7 years ago

Did you find any issue with the current version of plugin on iOS?

rafaellop commented 7 years ago

I haven't tested yet. I've been waiting for the updated version with the same changes as for the Android (to avoid ifdefs).

an-rahulpandey commented 7 years ago

Please test it once, since both are different platforms.

rafaellop commented 7 years ago

Is there a chance for the checkDbOnStorage() to be included? It's a simple function I think. Of course if not possible I'll do my tests too. Probably today.

an-rahulpandey commented 7 years ago

@rafaellop I have added the method for iOS too. Check all the method if it is working properly or not.

rafaellop commented 7 years ago

@an-rahulpandey thanks for the implementation, but I've been stopped at the very beginning. I've tried to use the copyDbToStorage() first to restore the database later with the other functions, but no matter how I try I always get this debug error:

2017-03-10 21:53:59.879 project1[20436:267730] [sqlDB] Dbname = appDB.db
2017-03-10 21:53:59.879 project1[20436:267730] [sqlDB] location = 1
2017-03-10 21:53:59.880 project1[20436:267730] [sqlDB] Source: /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/21FD047A-4E2F-47BC-B6EF-26DBE83E864D/Library/appDB.db
2017-03-10 21:53:59.880 project1[20436:267730] [sqlDB] Destination: Library/NoCloud/com.bundleid/
2017-03-10 21:53:59.885 project1[20436:267730] [sqlDB] Could not copy file from /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/21FD047A-4E2F-47BC-B6EF-26DBE83E864D/Library/appDB.db to Library/NoCloud/com.bundleid/. Error = Error Domain=NSCocoaErrorDomain Code=260 "The file “appDB.db” couldn’t be opened because there is no such file." UserInfo={NSFilePath=/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/21FD047A-4E2F-47BC-B6EF-26DBE83E864D/Library/appDB.db, NSUnderlyingError=0x600000258bd0 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

My code is this:

var storagepath = '/storage/sdcard1/Android/data/' + $scope.appidbundle + '/';
if ($rootScope.isiOSPlatform) {
    storagepath = 'Library/NoCloud/' + $scope.appidbundle + '/';    
}

window.plugins.sqlDB.copyDbToStorage(APP_DBNAME, 1, storagepath, function() {console.log('@@@@ SUCCESS')}, function(e) {console.log('@@@@ ERROR ', JSON.stringify(e))});

I must mention that the second parameter (location) is 1 here, but I tested all of the available values [0,1,2] and for each of them the debug log looks the same.

My database appDB.db is on the device and it is properly open. I can add records to it and read them back also between sessions with the app. So the db is properly working. I use the sqlite plugin and create the database with the code:

window.sqlitePlugin.openDatabase( {name: APP_DBNAME, location: 'default', createFromLocation: 1},  callback);

Waiting for your orders Sir! ;-)

an-rahulpandey commented 7 years ago

/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/21FD047A-4E2F-47BC-B6EF-26DBE83E864D/Library/

Can you open this path in file manager and let me know if the db is present there?

rafaellop commented 7 years ago

No, there's no. The db file is located in:

/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/21FD047A-4E2F-47BC-B6EF-26DBE83E864D/Library/LocalDatabase

an-rahulpandey commented 7 years ago

In New Sqlite Plugin Location is as follow -

default: Library/LocalDatabase subdirectory - NOT visible to iTunes and NOT backed up by iCloud
Library: Library subdirectory - backed up by iCloud, NOT visible to iTunes
Documents: Documents subdirectory - visible to iTunes and backed up by iCloud

However, since I created the plugin when the path was like this -

default: Documents: Documents subdirectory - visible to iTunes and backed up by iCloud
Library: Library subdirectory - backed up by iCloud, NOT visible to iTunes
Library/LocalDatabase subdirectory - NOT visible to iTunes and NOT backed up by iCloud

So you have to pass location = 2 , if you are storing database in Library/LocalDatabase(i.e Default or 0)

window.plugins.sqlDB.copyDbToStorage(APP_DBNAME, 2, storagepath, function() {console.log('@@@@ SUCCESS')}, function(e) {console.log('@@@@ ERROR ', JSON.stringify(e))});

rafaellop commented 7 years ago

I have mentioned in my first report:

I must mention that the second parameter (location) is 1 here, but I tested all of the available values [0,1,2] and for each of them the debug log looks the same.

that I checked all the location values and everytime I see the same error.

an-rahulpandey commented 7 years ago

Get the new plugin, it will work now. Also please see the proper location param. It is working for me.

rafaellop commented 7 years ago

Still not working. I've updated the plugin sources, rebuilt and changed the location parameter to 2. Here's the debug log:

2017-03-14 07:06:48.358 project1[1065:18597] [sqlDB] Dbname = appDB.db
2017-03-14 07:06:48.358 project1[1065:18597] [sqlDB] location = 2
2017-03-14 07:06:48.358 project1[1065:18597] [sqlDB] destination = Library/NoCloud/com.appbundleid/
2017-03-14 07:06:48.359 project1[1065:18597] [sqlDB] destination = Library/NoCloud/com.appbundleid/
2017-03-14 07:06:48.359 project1[1065:18597] [sqlDB] Source: /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/8980873F-9F1B-4F5B-A5FA-45FE3CAC8643/Library/LocalDatabase/appDB.db
2017-03-14 07:06:48.360 project1[1065:18597] [sqlDB] Destination: Library/NoCloud/com.appbundleid/appDB.db
2017-03-14 07:06:48.472 project1[1065:18597] [sqlDB] Could not copy file from /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/8980873F-9F1B-4F5B-A5FA-45FE3CAC8643/Library/LocalDatabase/appDB.db to Library/NoCloud/com.appbundleid/appDB.db. Error = Error Domain=NSCocoaErrorDomain Code=4 "The file “appDB.db” doesn’t exist." UserInfo={NSSourceFilePathErrorKey=/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/8980873F-9F1B-4F5B-A5FA-45FE3CAC8643/Library/LocalDatabase/appDB.db, NSUserStringVariant=(
    Copy
), NSDestinationFilePath=Library/NoCloud/com.appbundleid/appDB.db, NSFilePath=/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/8980873F-9F1B-4F5B-A5FA-45FE3CAC8643/Library/LocalDatabase/appDB.db, NSUnderlyingError=0x610000253740 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}

Maybe it's the destination path which is: storagepath = 'Library/NoCloud/' + $scope.appidbundle + '/'; ?

an-rahulpandey commented 7 years ago

You have to give full absolute path for destination. Use cordova file plugin. In your case, it will be

storagepath = cordova.file.documents-nosync

documents-nosync is in iosExtraFileSystems, so please see the proper tag is included in config.xml. By default all are enabled, so you need not have to be do anything. Still have a look here -

https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/#configuring-the-plugin-optional

rafaellop commented 7 years ago

In your plugin you can find the path to the database. Wouldn't be possible also to find the output location as for the location parameter in the other functions? The destination path could be then relational to the destlocation. I'd like to minimize plugins usage if possible. However I'll test it with the cordova-file-plugin.

an-rahulpandey commented 7 years ago

Wouldn't be possible also to find the output location as for the location parameter in the other functions?

If is good for iOS not for Android. Android has totally different structure. So providing the full path makes sense, since you can use it for both Platforms. In future, if I work on any Windows project, then will update it for Windows too. So it will be easier to maintain for all three platforms.

rafaellop commented 7 years ago

OK, I tested with the file plugin and here are some remarks:

1) It works but I had to use the cordova.file.dataDirectory to save into Library/NoCloud/

2) On Android the copyDbToStorage() works even if the destination file exists. On iOS if the destination file exists the function reports error. It would be better if these functions worked the same way on all platforms or if there's a function to check if destination file exists and a function to remove the file if exists. It might be useful to warn users about data overwrite possibility.

3) The iOS version of the copyDbFromStorage() works differently than Android. On Android it is required to add full path (storagepath + APP_DBNAME) which is OK depending on what the doc for the function says, but on iOS the same method with the same parameters cause the following error.

2017-03-14 09:52:43.422 project1[2899:47126] [sqlDB] Dbname = appDB.db
2017-03-14 09:52:43.422 project1[2899:47126] [sqlDB] location = 2
2017-03-14 09:52:43.423 project1[2899:47126] [sqlDB] Source: /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1/Library/NoCloud/com.appbundleid/appDB.db/appDB.db
2017-03-14 09:52:43.423 project1[2899:47126] [sqlDB] Destination: /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1/Library/LocalDatabase/appDB.db
2017-03-14 09:52:43.433 project1[2899:47126] [sqlDB] Could not copy file from /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1/Library/NoCloud/com.appbundleid/appDB.db/appDB.db to /Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1/Library/LocalDatabase/appDB.db. Error = Error Domain=NSCocoaErrorDomain Code=256 "The file “appDB.db” couldn’t be opened." UserInfo={NSFilePath=/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1**/Library/NoCloud/com.appbundleid/appDB.db/appDB.db**, NSUnderlyingError=0x6080004467e0 {Error Domain=NSPOSIXErrorDomain Code=20 "Not a directory"}}
2017-03-14 09:52:43.437 project1[2899:47126] THREAD WARNING: ['sqlDB'] took '15.036865' ms. Plugin should use a background thread.
2017-03-14 09:52:43.481 project1[2899:47126] @@@@ ERROR  {"message":"Error Domain=NSCocoaErrorDomain Code=256 \"The file “appDB.db” couldn’t be opened.\" UserInfo={NSFilePath=/Users/rafal/Library/Developer/CoreSimulator/Devices/F622E5F7-DC99-430B-AC21-7469EFE50025/data/Containers/Data/Application/CDFBA7A9-16BB-480A-BF97-C29F932F86B1/Library/NoCloud/com.appbundleid/appDB.db/appDB.db, NSUnderlyingError=0x6080004467e0 {Error Domain=NSPOSIXErrorDomain Code=20 \"Not a directory\"}}","code":256}
an-rahulpandey commented 7 years ago

2 Point sounds good, I will implement that. Will also update the 3rd to match with Android.

rafaellop commented 7 years ago

Regarding the 2) it would be enough to have an option in the parameters to overwrite if exists. The file check function is not needed. I can ask a user if he wants to overwrite if exists.

Regarding 3, it would be great if unified on all platforms. I plan to release my app soon on Windows, so I can help too. But not very soon.

Cheers,

an-rahulpandey commented 7 years ago

2) Yeah, adding that also. Add new overwrite param. If it is true, then it will update the destination. If false, then throw error. 3) I do not have access to Windows 10 machine, so can't start. Will see about it on Saturday at home, may be.

an-rahulpandey commented 7 years ago

I have added the overwrite function for Android, check it out. Will see the iOS in a while.

rafaellop commented 7 years ago

If you don't have Windows you can easily get one here: https://developer.microsoft.com/en-us/windows/downloads/virtual-machines

These are preconfigured Windows 10 developer virtual machines and the are trial for 60 days (AFAIR).

an-rahulpandey commented 7 years ago

Thanks for the info, I didn't know they offer virtual machines for free. However, I already have licensed copy of win 10 pro. Its just I never have any task for windows, so never boot it up.

rafaellop commented 7 years ago

They also have there virtual machines that are not trial but require a Windows 10 key. If you prefer not to dedicated a separate machine for Windows you can use your license for the VM version.

Regarding the opened issue, is the iOS version already changed so that I could do tests on both Android and iOS at once?

an-rahulpandey commented 7 years ago

I have pushed the iOS changes too. There are some changes in the location parameters to sync it with the sqlite plugin. Check the Readme.

an-rahulpandey commented 7 years ago

Reopen it, if there are more issues.

rafaellop commented 7 years ago

I just want to let you know that I've finally tested the current version on the iOS and it works perfectly. Thanks for the great plugin!

Do you maybe have an idea how to save to iCloud? I use the cordova.file.syncedDataDirectory path and the dbcopy is saved there, but it seems it is not synced with iCloud though it should according to the file plugin docs. Maybe it's because it doesn't on simulators?

an-rahulpandey commented 7 years ago

According to the docs, we can test the iCloud sync in simulator. You can see how to check here - https://developer.apple.com/library/content/documentation/IDEs/Conceptual/iOS_Simulator_Guide/TestingontheiOSSimulator/TestingontheiOSSimulator.html

The section name is Testing iCloud.

rafaellop commented 7 years ago

Thanks, yes I read this before. Unfortunately I still couldn't make it work. It seems the sync for the app files is only available when app is backuped. It's strange there's no iCloud plugin available which would allow to read/write files to/from the Apple Cloud for apps with proper capabilities. I added Google Drive on Android in minutes, almost the same with Dropbox save, but iCloud is impossible from Cordova. Maybe it's a plugin idea for you? :-)