Skip to content

Instantly share code, notes, and snippets.

@sidferreira
Last active September 13, 2024 04:41
Show Gist options
  • Save sidferreira/2b6b640e25544d601f311e35e430bce0 to your computer and use it in GitHub Desktop.
Save sidferreira/2b6b640e25544d601f311e35e430bce0 to your computer and use it in GitHub Desktop.
WatermelonDB preloaded db

This is the basic structure I'm using in an app.

getDatabasePath will handle any detail on unzip, copy, etc,

index will do all the usual dirty work, including withDatabase that won't explode if the database is missing

WatermelonProvider to cover original one til the DB is ready

import RNFS from "react-native-fs";
// Currently android will add `.db` to file name...
async function getDatabasePath(dbName) {
let dbPath = `${RNFS.DocumentDirectoryPath}/${dbName}`;
const exists = await RNFS.exists(dbPath.concat(".db"));
if (!exists) {
try {
await RNFS.copyFileAssets(dbName.concat(".db"), dbPath.concat(".db"));
} catch (e) {
console.log(">>> getDatabasePath error", e);
}
}
return dbPath;
}
export default getDatabasePath;
import RNFS from 'react-native-fs';
import * as RNZIP from 'react-native-zip-archive
async function getDatabasePath(dbName) {
let sanitizedDbName = dbName;
if (!sanitizedDbName.endsWith(".db")) {
sanitizedDbName = sanitizedDbName.concat(".db");
}
let dbPath = `${RNFS.DocumentDirectoryPath}/${sanitizedDbName}`;
const exists = await RNFS.exists(dbPath);
if (!exists) {
const assetPath = `${RNFS.MainBundlePath}/${sanitizedDbName.replace(
".db",
".zip"
)}`;
const existsZip = await RNFS.exists(assetPath);
if (existsZip) {
const tmpPath = `${RNFS.DocumentDirectoryPath}/tmp`;
await RNZIP.unzip(assetPath, tmpPath);
await RNFS.moveFile(`${tmpPath}/${sanitizedDbName}`, dbPath);
await RNFS.unlink(tmpPath);
}
}
return dbPath;
}
export default getDatabasePath;
async function getDatabasePath(dbName) {
let fullDbName = dbName;
if (!fullDbName.endsWith('.db') && !fullDbName.includes('?')) {
fullDbName = fullDbName.concat('.db');
}
let dbPath = dbName.includes(process.cwd())
? fullDbName
: `${process.cwd()}/${fullDbName}`;
return dbPath;
}
export default getDatabasePath;
import getDatabasePath from './getDatabasePath';
const DEFAULT_DATABASE_NAME = 'watermelon';
const promises: { [key: string]: Promise<Database> } = {};
const instances: { [key: string]: Database } = {};
async function init(dbName: string = DEFAULT_DATABASE_NAME) {
const dbPath = await getDatabasePath(dbName);
const adapter = new SQLiteAdapter({
schema,
migrations,
dbName: dbPath,
});
const instance = new Database({
adapter,
modelClasses,
actionsEnabled: true,
});
instances[dbName] = instance;
// sync();
return db;
}
export const getDatabase = async (
dbName: string = DEFAULT_DATABASE_NAME,
) => {
if (!promises[dbName]) {
promises[dbName] = init(dbName);
}
const instance = await promises[dbName];
return instance;
};
// For _very_ specific uses
export const getDatabaseSync = (altDbName: string = DEFAULT_DATABASE_NAME) => {
return instances[altDbName];
};
// custom withDatabase to handle the possibility of not having the database just yet...
export type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export const withDatabase = <T extends DatabaseProp>(
Wrapped: React.ComponentType<T>,
) => {
const WrappedComponent: React.ComponentType<Omit<T, DatabaseProp>> = (
props,
) => {
const database = useDatabase();
if (!database) {
return <View />;
}
return <Wrapped {...(props as T)} database={database} />;
};
return WrappedComponent;
};
import React, { ReactChild } from 'react';
import { Database } from '@nozbe/watermelondb';
import { getWatermelon } from 'app/utils/DBWatermelonOld/DBWatermelonOld';
import DatabaseProvider from '@nozbe/watermelondb/DatabaseProvider';
const WatermelonProvider = (props) => {
const watermelonRef = React.useRef();
const [database, setDatabase] = React.useState();
if (!watermelonRef.current) {
const promise = getWatermelon();
if (promise) {
watermelonRef.current = promise;
watermelonRef.current.then(setDatabase);
}
}
return database ? <DatabaseProvider database={database} {...props} /> : null;
};
export default WatermelonProvider;
@fullstackNRJ
Copy link

fullstackNRJ commented Feb 18, 2022

@Stophface I'm doing pretty much same what you just described, relying on react-native-sqlite-storage just to have access to my products catalog.

  • Rest of the data is in watermelondb and it works great. But, I want the product catalog data also in watermelondb's table, same as your requirement.
  • I've reached to the same conclusion that it is overwriting it somehow instead of using that .db file as the source for creating/populating table.

@sidferreira Thanks for more information. I think I'm definitely doing something wrong and since I'm running out of time, skipping this method for now.

Guys, let's stay connected on twitter @devnrj07 ! @Stophface we'll sort it out soon.

@sidferreira
Copy link
Author

@devnrj07 @Stophface to me it was really straightforward. If you want, we can meet online to find out what's going on...

@fullstackNRJ
Copy link

@sidferreira that would be really great!

@Stophface
Copy link

@sidferreira @devnrj07 Awesome, that is really very nice. Which timezone are you living in? I am UTC+1.

@fullstackNRJ
Copy link

@Stophface I am UTC + 5:30. Let us see what is @sidferreira 's availability, possible today or tomorrow

@sidferreira
Copy link
Author

@Stophface @devnrj07 reach me on Twitter https://twitter.com/sidferreiraz

@gabriel-almeida250
Copy link

gabriel-almeida250 commented Jun 7, 2023

Hello, @sidferreira @Stophface

Is this solution still functional? I am currently trying to implement this method but I am having some difficulties.

@Stophface
Copy link

@gabriel-almeida250 you probably need this in addition Nozbe/WatermelonDB#774 (comment)

@sidferreira
Copy link
Author

@gabriel-almeida250 Fala Gabriel! So, I moved to another company and I'm not using it anymore, but should be...

@gabriel-almeida250
Copy link

gabriel-almeida250 commented Jun 9, 2023

Thanks for your attention, guys @sidferreira @Stophface! I'm going to try to implement it now.

Fala, @sidferreira! Beleza, agradeço pelo rápido retorno!

@KosolapovR
Copy link

@gabriel-almeida250
Please let us know if you would be able to implement it, I'm also trying to prepopulate data using this method.

@KosolapovR
Copy link

KosolapovR commented Jun 14, 2023

I can say that this solution still work.
My personal struggle was that I misunderstood how I should create watermelon.db file, some sql statement packed into text file with .db extension not worked for some reason and I was able to solve it only by creating db file via "DB browser for sqlite".
I'm not sure if it will be difficult to prepopuate db later after multiple consecutive migrations.

@gabriel-almeida250
Copy link

Ok, @KosolapovR. I haven't had time to implement the solution yet, I had to prioritize other activities, but thanks for the feedback.

@GitMurf
Copy link

GitMurf commented Sep 13, 2024

Thanks all! This is wonderful! I have a similar but a little different use case. Bottom line, I don’t want to use watermelondb for anything other than their Sync module. So I want to bring my SQLite database with my own schema etc created outside of watermelon and simply want to call the Sync module functions. Is this something I can do by following these instructions to add the extra columns to my tables so that watermelon then can handle the push / pull sync methods? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment