pubkey / rxdb

A fast, local first, reactive Database for JavaScript Applications https://rxdb.info/
https://rxdb.info/
Apache License 2.0
20.95k stars 1.02k forks source link

RxDB not replacing local state with real master state #6085

Open malhous opened 3 weeks ago

malhous commented 3 weeks ago

I am using RxDB along with a replication to Supabase. I have the following scenario:

  1. User logs in.
  2. User enters OTP (One Time Password).
  3. Sync "Settings" collection to local DB: a. If no "Settings" doc found, insert a new document to local which will then sync. b. Else insert remote "Settings" doc.

Here's the code, i'm using React + Typescript:

import {
  selectSession,
  setSession,
  setSettings,
} from "@my-app/store";
import { uuid } from "@supabase/supabase-js/dist/main/lib/helpers";
import { useEffect } from "react";

import { supabase } from "../api";
import { getDB } from "../rxdb";
import { useAppDispatch } from "./useAppDispatch";
import { useAppSelector } from "./useAppSelector";

export const useInitApp = () => {
  const dispatch = useAppDispatch();
  const session = useAppSelector(selectSession);

  useEffect(() => {
    if (!session) {
      return;
    }

    getDB()
      .then((db) => {
        // LOAD RXDB MODELS TO STORE

        db.settings
          .find({ sort: [{ created_at: "asc" }] })
          .$.subscribe((documents) => {
            console.log(documents); // returns [] on first Observable event, then [RemoteSettingsDoc] on second one
            if (!documents.length) {
              void db.settings.insert({
                user_id: session.user.id,
                created_at: new Date().toISOString(),
                modified_at: new Date().toISOString(),
                analytics_id: uuid(),
                replication_revision: "",
                _deleted: false,
              });
            } else {
              const mappedClean = documents.map((d) => d.toMutableJSON());
              void dispatch(setSettings(mappedClean[0]));
            }
          });
      })
      .catch((err) => {
        console.error("DB INIT FAILED");
        console.error(err);
      });
  }, [session]);

  useEffect(() => {
    supabase.auth.onAuthStateChange((_, latestSession) => {
      dispatch(setSession(latestSession));
    });
  }, []);

// ...
};

For some reason documents are returned as [] on the first observable emission, which is weird. But that's not my problem, what's then happening is that it's inserting the document into db, triggers conflictHandler, which uses the realMasterState but does not sync it with the local state.

image

I'm not sure what are the next steps or how to solve it, any help would be great!

I'm using Dexie Storage and i noticed this empty function in rxbd/src/plugins/storage-dexie/rx-storage-dexie-instance.ts, not sure if it's relevant.

image

pubkey commented 3 weeks ago

The conflict handler is not only used to handle conflicts but also to detect them. So it is called many times at various places. Next step would be that you create a PR with a test case to reproduce the problem. Maybe it is even reproducable without supabase which would make debugging easier.

stale[bot] commented 2 weeks ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed soon. Please update it or it may be closed to keep our repository organized. The best way is to add some more information or make a pull request with a test case. Also you might get help in fixing it at the RxDB Community Chat If you know you will continue working on this, just write any message to the issue (like "ping") to remove the stale tag.