WebSQL threw an error [Error: Error code 1: no such table: document-store] - react-native

We are using react-naive-sqlite-2 in our application with RxDB and started getting this error somewhat sporadically. It seems to happen after we remove the database. I was surprised to see this was a WebSQL error since we are using react-native and WebSQL is deprecated. I don't have great ways to debug this but my hunch is that we have some code that still tries to access the now dead database.
This is the code we use to set up our database:
import SQLiteAdapterFactory from 'pouchdb-adapter-react-native-sqlite'
import SQLite from 'react-native-sqlite-2'
import { addRxPlugin, createRxDatabase } from 'rxdb'
import { RxDBReplicationGraphQLPlugin } from 'rxdb/plugins/replication-graphql'
import type { DatabaseType } from '../generated'
/**
* SQLITE SETUP
*/
const SQLiteAdapter = SQLiteAdapterFactory(SQLite)
addRxPlugin(SQLiteAdapter)
addRxPlugin(require('pouchdb-adapter-http'))
/**
* Other plugins
*/
addRxPlugin(RxDBReplicationGraphQLPlugin)
export const getRxDB = async () => {
return await createRxDatabase<DatabaseType>({
name: 'gatherdatabase',
adapter: 'react-native-sqlite', // the name of your adapter
multiInstance: false,
})
The issue happens after we logout and attempt to log back in. When we logout, we call removeRxDatabase. Has anyone ran into this kind of issue before or know of ways to debug?

For posterity, the issue was that we had a reference to the database in our state management library (Zustand) that was being held onto past logout. When we tried to login again, our getOrCreateDatabase function didn't make a new one but it wasn't valid since we had run database.remove() in rxdb. We ended up just clearing the Zustand db and calling database.remove() at one place.
export const useRxDB = create<UseRxDBType>((set, get) => ({
database: undefined,
/**
* we set the database to ready in the LocalDocument store once local docs are loaded into the store
*/
databaseIsReady: false,
getOrCreateDatabase: async () => {
let database = get().database
if (!database) {
database = await createRxDatabase()
if (!Rx.isRxDatabase(database)) throw new Error(`database isnt a valid RxDB database.`)
set({ database })
}
return database
},
resetDatabase: async () => {
const database = get().database
if (database) {
await database.remove()
set({ database: undefined })
}
},
}))

Related

Mongoose connection closing too soon before tests have run

I am a beginner using jest to test a node/express app with mongo database.
I am getting an issue where different tests are failing each time I run the tests and sometimes they all pass/all fail. I think it is because of a time-out or things not happening in the right order because I'm getting this error:
MongoPoolClosedError: Attempted to check out a connection from closed connection pool
a) can you let me know if you think I'm on the right track?
b) if so, is the solution to make this into an async function and how can I do that? (I have tried making it into async await, using .then and also putting the code that clears the database collections into the test files instead of the helper and have had no success so far.
beforeAll( (done) => {
mongoose.connect("mongodb://127.0.0.1/jobBuddy_test", {
useNewUrlParser: true,
useUnifiedTopology: true,
})
var db = mongoose.connection;
const users = db.collection('users')
users.deleteMany({})
const applications = db.collection('applications')
applications.deleteMany({})
db.on("error", console.error.bind(console, "MongoDB connection error:"));
db.on("open", function () {
done();
});
});
afterAll(function (done) {
mongoose.connection.close(true, function () {
done();
});
});

Access existing SQLite database using expo-sqlite

When moving from objective-c to react-native I am trying to access the SQLite database.
What the app is currently doing. It saves some of the user's login information to an SQLite3 database. I want to access that information so that when the user moves from 1.1.0 to 1.2.0 they don't need to log in again.
Locate SQLite database
I am using expo-sqlite like so:
const dbName = 'test.sqlite';
const openDatabase = async () => {
if ((await FileSystem.getInfoAsync(FileSystem.documentDirectory + dbName)).exists) {
await FileSystem.downloadAsync(
Asset.fromModule(require('../../assets/test.sqlite')).uri,
FileSystem.documentDirectory + dbName
);
const db = await SQLite.openDatabase(dbName);
return db;
}
return alert('SQLite database not found');
}
Accessing the database:
useEffect(() => {
openDatabase().then((db) => {
db.transaction((tx) => {
tx.executeSql("SELECT name FROM sqlite_master WHERE type = 'table'", [], (tx,
results) => {
alert(`get result ${JSON.stringify(results)}`);
});
});
});
}, []);
What is happening is when I move from 1.1.0 and then install 1.2.0 on top of that application it says that the database exists but that it is empty. If I just delete the app off the phone and then download 1.2.0 it says that no database exists.
As far as I can tell this means that it is getting the database from 1.1.0 but for some reason, it says that there are no rows.
returned value when installing 1.2.0 on top of 1.1.0
{
"rowAffected": 0,
"rows": {
"_array": [],
"length": 0
}
}
Also, I have used SQLite browser to download the test.sqlite database from finder (building the 1.1.0 app locally) and execute the same query. When I do that I get a list of all available tables (rows: 82). So I know that the query is correct.
Any idea on why when I use the code above it returns nothing?

"The original argument must be of type function" ERROR for promisifying client.zrem?

I am making a cron job instance that is running using Node to run a job that removes posts from my Redis cache.
I want to promisify client.zrem for removing many posts from the cache to insure they are all removed but when running my code I get the error below on line: "client.zrem = util.promisify(client.zrem)"
"TypeError [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type function. Received undefined"
I have another Node instance that runs this SAME CODE with no errors, and I have updated my NPM version to the latest version, according to a similar question for this SO article but I am still getting the error.
TypeError [ERR_INVALID_ARG_TYPE]: The "original" argument must be of type Function. Received type undefined
Any idea how I can fix this?
const Redis = require("redis")
const util = require(`util`)
const client = Redis.createClient({
url: process.env.REDIS,
})
client.zrem = util.promisify(client.zrem) // ERROR THROWN HERE
// DELETE ONE POST
const deletePost = async (deletedPost) => {
await client.zrem("posts", JSON.stringify(deletedPost))
}
// DELETES MANY POSTS
const deleteManyPosts = (postsToDelete) => {
postsToDelete.map(async (post) => {
await client.zrem("posts", JSON.stringify(post))
})
}
module.exports = { deletePost, deleteManyPosts }
Node Redis 4.x introduced several breaking changes. Adding support for Promises was one of those. Renaming the methods to be camel cased was another. Details can be found at in the README in the GitHub repo for Node Redis.
You need to simply delete the offending line and rename the calls to .zrem to .zRem.
I've also noticed that you aren't explicitly connecting to Redis after creating the client. You'll want to do that.
Try this:
const Redis = require("redis")
const client = Redis.createClient({
url: process.env.REDIS,
})
// CONNECT TO REDIS
// NOTE: this code assumes that the Node.js version supports top-level await
client.on('error', (err) => console.log('Redis Client Error', err));
await client.connect(); //
// DELETE ONE POST
const deletePost = async (deletedPost) => {
await client.zRem("posts", JSON.stringify(deletedPost))
}
// DELETES MANY POSTS
const deleteManyPosts = (postsToDelete) => {
postsToDelete.map(async (post) => {
await client.zRem("posts", JSON.stringify(post))
})
}
module.exports = { deletePost, deleteManyPosts }

using redis in getServerSideProps results in error net.isIP is not a function

Correct me if I am wrong but getServerSideProps is used to pre-render data on each render? If I use the standard redis npm module in getServerSideProps I get the error net.isIP is not a function. From what I have researched this is due to the client trying to use the redis functions.
I am trying to create an application to where session data is saved in a redis key based on a cookie token. Based on the user Id a database is called and renders data to the component. I can get the cookie token in getServerSideProps but I I run client.get(token) I get the error net.isIP is not a function at runtime.
Am I not using getServerSideProps correctly or should I be using a different method / function? I am new to the whole Next.js world. I appreciate the help.
If I use the same functionality in an /api route everything works correctly.
import util from 'util';
import client from '../libs/redis' // using 'redis' module
// ... my component here
export async function getServerSideProps(context) {
const get = util.promisify(client.get).bind(client);
const name = await get('mytoken') // error `net.isIP is not a function`
return {
props: {
name
},
}
}
// redis.js
const redis = require("redis");
const client = redis.createClient();
client.on("error", function(error) {
console.error(error);
});
module.exports = client
I upgraded to next version 10.0.6 from 9.3 and I do not receive the error anymore.

Multiple realms in React Native don't query realm object server correctly on first launch of app after install

I am having an issue dealing with multiple realms in React Native. I'm working on an app that allows users to use the app without having a subscription (using a local realm) and then at any point in their app journey they have the option of upgrading to a subscription with syncing (which uses sync to a realm object server).
When I start the app I check to see if they are using sync and if so I initialize a synced realm with their user and everything works great. I get all the data I expect.
However, when the app starts on first launch after install (that part about first launch after install is crucial) and I see that they don't use sync I initialize a local realm which I save data to until they decide to log in to their sync account (if they have one). At this point I attempt to pull information from the synced realm but it does not have the information that I saw when I only initialized the synced realm (in the case that on app startup I detect they use sync).
I am able to log in as the sync user but the data isn't there if I've previously initialized a local realm AND this logic gets run on the first launch of the app after install. The data only shows up from the realm object server when I initialize a local and synced realm on a secondary launch of the app (no reinstall before launching).
Here's a simple test script with dummy data in it with which I've been able to replicate the observed behavior:
const username = 'testuser2';
const password = 'supersecret';
const tld = 'REALM_OBJECT_SERVER_TLD';
class Test extends Realm.Object {}
Test.schema = {
name: 'Test',
properties: {
id: {
type: 'string',
},
}
};
function initLocalRealm() {
return new Realm({
path: 'local.realm',
schema: [Test],
});
}
function initSyncedRealmWithUser(user) {
return new Realm({
path: 'synced.realm',
sync: {
user,
url: `realm://${tld}:9080/~/data`,
},
schema: [Test],
});
}
function writeTestObjectWithId(realm, id) {
realm.write(() => {
realm.create('Test', {
id,
});
alert(`Test object with id: ${id}`);
});
}
initLocalRealm();
// setup
// uncomment this and comment out the login section to setup user on first run
// Realm.Sync.User.register(`http://${tld}:9080`, username, password, (error, user) => {
// if (error) {
// return;
// }
// const syncedRealm = initSyncedRealmWithUser(user);
// writeTestObjectWithId(syncedRealm, '1');
// });
// login
Realm.Sync.User.login(`http://${tld}:9080`, username, password, (error, user) => {
if (error) {
return;
}
const syncedRealm = initSyncedRealmWithUser(user);
alert(`Synced realm test objects: ${syncedRealm.objects('Test').length}`);
});
If you create a react native app and then add this code to the main components componentDidMount function you should see that on the first run of the app (after you've uncommented the register code once) you will see the Test collection length at 0, but then when you refresh you will see the Test collection length at 1.
Any help on this would be awesome.
Thanks!
running your code snippet, I get a length of 1 immediately as soon as I uncomment the login section. Could you try observing your synchronized realm with the Realm Browser and see if it seems to have the data you are expecting after registering the user?