Skip to content

Using SQL clause "NOT IN" for syncing DBs (pulling remote data that is not present locally) #598

@stefanorumi7

Description

@stefanorumi7

First of all, let me say "thanks" for developing and maintaining this project. It is amazing!

Now lets get into my scenario:

  • I would like to pull all the records of EntityA from the remote DB into my local DB to allow future offline workflow.
  • It is a large number of them, and they have a lot of asociations, so I have to batch the request, or some associations will be missing.
  • Before reaching this step, I created an instance locally of EntityA, so my local DB is not empty, but missing lot of records.
  • The idea is to do this load optimistically, but not depend on it.

So my solution is:

In an unawaited async method request all the data of EntityA from the remote DB using OfflineFirstGetPolicy.awaitRemote`. It looks something like this:

  Future<void> pullRemoteData(String userId) async {
      int processedCount = 0;
      const pageSize = 5;
      bool hasMoreRecords = true;

      while (hasMoreRecords) {
        final query = Query(
          where: [Where('userId', value: userId)],
          limit: pageSize,
          offset: processedCount,
        );

        final remoteEntities = await BrickRepository().get<EntityA>(
          query: query,
          policy: OfflineFirstGetPolicy.awaitRemote,
        );

        if (remoteEntities.isEmpty) {
          hasMoreRecords = false;
          break;
        }

        processedCount += remoteEntities.length;

        if (remoteEntities.length < pageSize) {
          hasMoreRecords = false;
        }
      }
  }

Limitation i am facing:

  • If I would like to periodically trigger this sync to ensure the localDB is up to date, this querying of the whole table would get to expensive.
  • I would like to use a NOT IN SQL clause to query from the remote DB only records that I don't have locally.
  • I cannot find a way to do this using Brick.

What I tried but didn't work

  Future<void> pullRemoteData(String userId) async {
      final localQuery = Query(where: [Where('userId', value: userId)]);
      final localEntities = await BrickRepository()
          .get<EntityA>(
            query: localQuery,
            policy: OfflineFirstGetPolicy.localOnly,
          );

      final localIds =
          localEntities.map((e) => e.id).toSet();

      int processedCount = 0;
      const pageSize = 5;
      bool hasMoreRecords = true;

      while (hasMoreRecords) {
        final query = Query(
          where:
              localIds.isNotEmpty
                  ? [
                    Where(
                      'id',
                      compare: Compare.doesNotContain,
                      value: localIds.toList(),
                    ),
                  ]
                  : [],
          limit: pageSize,
          offset: processedCount,
        );

        final remoteEntities = await BrickRepository().get<EntityA>(
          query: query,
          policy: OfflineFirstGetPolicy.awaitRemote,
        );

        if (remoteEntities.isEmpty) {
          hasMoreRecords = false;
          break;
        }

        processedCount += remoteEntities.length;

        if (remoteEntities.length < pageSize) {
          hasMoreRecords = false;
        }
      }
  }

Is there a way of doing the NOT IN clause? Or maybe an alternative flow to achieve the same result?

Note that it is not critical to the flow in my app, but I believe it is something more people could face.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions