From 26f72017760b0909244d74d62713e0e1b418cbb6 Mon Sep 17 00:00:00 2001 From: ospfranco Date: Sat, 11 May 2024 21:26:25 +0200 Subject: [PATCH 1/4] Allow copying databases from custom assets path --- .../main/java/com/op/sqlite/OPSQLiteModule.kt | 9 ++++++--- .../app/src/main/assets/sqlite/sample2.sqlite | Bin 0 -> 12288 bytes example/android/link-assets-manifest.json | 4 ++++ example/assets/sqlite/sample2.sqlite | Bin 0 -> 12288 bytes .../OPSQLiteExample.xcodeproj/project.pbxproj | 4 ++++ example/ios/OPSQLiteExample/Info.plist | 2 +- example/ios/link-assets-manifest.json | 4 ++++ example/src/tests/dbsetup.spec.ts | 11 +++++++++++ ios/OPSQLite.mm | 15 ++++++++------- src/index.ts | 10 +++++----- 10 files changed, 43 insertions(+), 16 deletions(-) create mode 100644 example/android/app/src/main/assets/sqlite/sample2.sqlite create mode 100644 example/assets/sqlite/sample2.sqlite diff --git a/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt b/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt index d7d3dba9..fcf78b45 100644 --- a/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +++ b/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt @@ -4,6 +4,7 @@ import android.util.Log import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReactContextBaseJavaModule +import com.facebook.react.bridge.ReadableMap import java.io.File import java.io.FileOutputStream import java.io.InputStream @@ -48,13 +49,15 @@ internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextB } @ReactMethod(isBlockingSynchronousMethod = true) - fun moveAssetsDatabase(name: String, extension: String): Boolean { + fun moveAssetsDatabase(args: ReadableMap): Boolean { + val filename = args.getString("filename") + val path = args.getString("path") ?: "custom" val context = reactApplicationContext val assetsManager = context.assets try { // Open the input stream for the asset file - val inputStream: InputStream = assetsManager.open("custom/$name.$extension") + val inputStream: InputStream = assetsManager.open("$path/$filename") // Create the output file in the documents directory val databasesFolder = @@ -62,7 +65,7 @@ internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextB .absolutePath .replace("defaultDatabase", "") - val outputFile = File(databasesFolder, "$name.$extension") + val outputFile = File(databasesFolder, filename) if (outputFile.exists()) { return true diff --git a/example/android/app/src/main/assets/sqlite/sample2.sqlite b/example/android/app/src/main/assets/sqlite/sample2.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..8b9b073657512d160315807650584c797a8565ad GIT binary patch literal 12288 zcmeI#ze~eF6bJCTC@Mlpm(cZXRw#lvx){q1!L-rz3U&&oJvG=Sn4Z>2aP+V9-*NO_ zp{|`R--GwUyB`Vn$@E4yY3VFI)Xm&DIumUnrMMsxLP#GwKGuWl-F4xgTyGjuoV2aP+V9-*NO_ zp{|`R--GwUyB`Vn$@E4yY3VFI)Xm&DIumUnrMMsxLP#GwKGuWl-F4xgTyGjuoV NSLocationWhenInUseUsageDescription - + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/example/ios/link-assets-manifest.json b/example/ios/link-assets-manifest.json index 9f1031f0..80e69b45 100644 --- a/example/ios/link-assets-manifest.json +++ b/example/ios/link-assets-manifest.json @@ -4,6 +4,10 @@ { "path": "assets/sample.sqlite", "sha1": "0f1675ac593b261b41a5144bc14f41163bd2a0c2" + }, + { + "path": "assets/sqlite/sample2.sqlite", + "sha1": "0f1675ac593b261b41a5144bc14f41163bd2a0c2" } ] } diff --git a/example/src/tests/dbsetup.spec.ts b/example/src/tests/dbsetup.spec.ts index 3330ae56..f7583974 100644 --- a/example/src/tests/dbsetup.spec.ts +++ b/example/src/tests/dbsetup.spec.ts @@ -3,6 +3,7 @@ import { ANDROID_EXTERNAL_FILES_PATH, IOS_LIBRARY_PATH, isSQLCipher, + moveAssetsDatabase, open, } from '@op-engineering/op-sqlite'; import chai from 'chai'; @@ -91,6 +92,16 @@ export function dbSetupTests() { db.delete(); }); + it('Moves assets database', async () => { + const copied1 = moveAssetsDatabase({filename: 'sample.sqlite'}); + const copied2 = moveAssetsDatabase({ + filename: 'sample2.sqlite', + path: 'sqlite', + }); + expect(copied1).to.equal(true); + expect(copied2).to.equal(true); + }); + // it('Should fail creating in-memory with non-bool arg', async () => { // try { // open({ diff --git a/ios/OPSQLite.mm b/ios/OPSQLite.mm index ea04373b..1d3be907 100644 --- a/ios/OPSQLite.mm +++ b/ios/OPSQLite.mm @@ -88,16 +88,17 @@ - (NSDictionary *)getConstants { } RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(moveAssetsDatabase - : (NSString *)name extension - : (NSString *)extension) { + : (NSDictionary *)args) { NSString *documentPath = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, true) objectAtIndex:0]; - NSString *sourcePath = [[NSBundle mainBundle] pathForResource:name - ofType:extension]; - NSString *destinationPath = [documentPath - stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", name, - extension]]; + NSString *filename = args[@"filename"]; + + NSString *sourcePath = [[NSBundle mainBundle] pathForResource:filename + ofType:nil]; + + NSString *destinationPath + [documentPath stringByAppendingPathComponent:filename]; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:destinationPath]) { diff --git a/src/index.ts b/src/index.ts index 42b7d8e6..0ad3ea7c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -489,11 +489,11 @@ export const open = (options: { }; }; -export const moveAssetsDatabase = ( - dbName: string, - extension: string -): boolean => { - return NativeModules.OPSQLite.moveAssetsDatabase(dbName, extension); +export const moveAssetsDatabase = (args: { + filename: string; + path?: string; +}): boolean => { + return NativeModules.OPSQLite.moveAssetsDatabase(args); }; export const isSQLCipher = (): boolean => { From c4a33373983b90e206864d660d84129d5fcce9ed Mon Sep 17 00:00:00 2001 From: ospfranco Date: Sun, 12 May 2024 08:50:36 +0200 Subject: [PATCH 2/4] Make async, add overwrite --- .../main/java/com/op/sqlite/OPSQLiteModule.kt | 21 +++++++++---- example/src/tests/dbsetup.spec.ts | 23 ++++++++++---- ios/OPSQLite.mm | 30 ++++++++++++++----- src/index.ts | 1 + 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt b/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt index fcf78b45..5f36b625 100644 --- a/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt +++ b/android/src/main/java/com/op/sqlite/OPSQLiteModule.kt @@ -1,6 +1,7 @@ package com.op.sqlite import android.util.Log +import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReactContextBaseJavaModule @@ -9,6 +10,7 @@ import java.io.File import java.io.FileOutputStream import java.io.InputStream import java.io.OutputStream +import com.facebook.react.util.RNLog; //@ReactModule(name = OPSQLiteModule.NAME) internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextBaseJavaModule(context) { @@ -48,10 +50,11 @@ internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextB } } - @ReactMethod(isBlockingSynchronousMethod = true) - fun moveAssetsDatabase(args: ReadableMap): Boolean { - val filename = args.getString("filename") + @ReactMethod + fun moveAssetsDatabase(args: ReadableMap, promise: Promise) { + val filename = args.getString("filename")!! val path = args.getString("path") ?: "custom" + val overwrite = if(args.hasKey("overwrite")) { args.getBoolean("overwrite") } else false val context = reactApplicationContext val assetsManager = context.assets @@ -68,7 +71,12 @@ internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextB val outputFile = File(databasesFolder, filename) if (outputFile.exists()) { - return true + if(overwrite) { + outputFile.delete() + } else { + promise.resolve(true) + return + } } // Open the output stream for the output file @@ -85,9 +93,10 @@ internal class OPSQLiteModule(context: ReactApplicationContext?) : ReactContextB inputStream.close() outputStream.close() - return true + promise.resolve(true) } catch (exception: Exception) { - return false + RNLog.e(this.reactApplicationContext, "Exception: $exception") + promise.resolve(false) } } diff --git a/example/src/tests/dbsetup.spec.ts b/example/src/tests/dbsetup.spec.ts index f7583974..caf91232 100644 --- a/example/src/tests/dbsetup.spec.ts +++ b/example/src/tests/dbsetup.spec.ts @@ -92,14 +92,27 @@ export function dbSetupTests() { db.delete(); }); - it('Moves assets database', async () => { - const copied1 = moveAssetsDatabase({filename: 'sample.sqlite'}); - const copied2 = moveAssetsDatabase({ + it('Moves assets database simple', async () => { + const copied = await moveAssetsDatabase({filename: 'sample.sqlite'}); + + expect(copied).to.equal(true); + }); + it('Moves assets database with path', async () => { + const copied = await moveAssetsDatabase({ + filename: 'sample2.sqlite', + path: 'sqlite', + }); + + expect(copied).to.equal(true); + }); + it('Moves assets database with path and overwrite', async () => { + const copied = await moveAssetsDatabase({ filename: 'sample2.sqlite', path: 'sqlite', + overwrite: true, }); - expect(copied1).to.equal(true); - expect(copied2).to.equal(true); + + expect(copied).to.equal(true); }); // it('Should fail creating in-memory with non-bool arg', async () => { diff --git a/ios/OPSQLite.mm b/ios/OPSQLite.mm index 1d3be907..dd0d0c6c 100644 --- a/ios/OPSQLite.mm +++ b/ios/OPSQLite.mm @@ -87,30 +87,46 @@ - (NSDictionary *)getConstants { return @true; } -RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(moveAssetsDatabase - : (NSDictionary *)args) { +RCT_EXPORT_METHOD(moveAssetsDatabase + : (NSDictionary *)args resolve + : (RCTPromiseResolveBlock)resolve reject + : (RCTPromiseRejectBlock)reject) { NSString *documentPath = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory, NSUserDomainMask, true) objectAtIndex:0]; NSString *filename = args[@"filename"]; + BOOL overwrite = args[@"overwrite"]; NSString *sourcePath = [[NSBundle mainBundle] pathForResource:filename ofType:nil]; - NSString *destinationPath + NSString *destinationPath = [documentPath stringByAppendingPathComponent:filename]; + NSError *error; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:destinationPath]) { - return @true; + if (overwrite) { + [fileManager removeItemAtPath:destinationPath error:&error]; + if (error) { + NSLog(@"Error: %@", error); + resolve(@false); + return; + } + } else { + resolve(@true); + return; + } } - NSError *error; [fileManager copyItemAtPath:sourcePath toPath:destinationPath error:&error]; if (error) { - return @false; + NSLog(@"Error: %@", error); + resolve(@false); + return; } - return @true; + resolve(@true); + return; } // #if RCT_NEW_ARCH_ENABLED diff --git a/src/index.ts b/src/index.ts index 0ad3ea7c..055bdc1b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -492,6 +492,7 @@ export const open = (options: { export const moveAssetsDatabase = (args: { filename: string; path?: string; + overwrite?: boolean; }): boolean => { return NativeModules.OPSQLite.moveAssetsDatabase(args); }; From 3e132ecfba4fa9b3a91a66ee7e91800bf6bf04b9 Mon Sep 17 00:00:00 2001 From: ospfranco Date: Sun, 12 May 2024 09:00:53 +0200 Subject: [PATCH 3/4] Fix app.tsx --- example/src/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index 2abe1d20..682aac4c 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -80,7 +80,7 @@ export default function App() { }; const openAssetsDb = async () => { - const moved = moveAssetsDatabase('sample', 'sqlite'); + const moved = await moveAssetsDatabase({filename: 'sample.sqlite'}); console.log('moved', moved); const db = open({name: 'sample.sqlite'}); const users = db.execute('SELECT * FROM User'); From e74e303300d5cca0dda4ded4e4cc601a91858cf1 Mon Sep 17 00:00:00 2001 From: ospfranco Date: Sun, 12 May 2024 09:04:21 +0200 Subject: [PATCH 4/4] Change macos runner --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aefd9aff..c24b2482 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,7 @@ jobs: yarn turbo run build:android --cache-dir="${{ env.TURBO_CACHE_DIR }}" build-ios: - runs-on: self-hosted + runs-on: macos-latest env: TURBO_CACHE_DIR: .turbo/ios steps: @@ -126,7 +126,7 @@ jobs: yarn turbo run build:ios --cache-dir="${{ env.TURBO_CACHE_DIR }}" build-ios-sqlcipher: - runs-on: self-hosted + runs-on: macos-latest env: TURBO_CACHE_DIR: .turbo/ios steps: