Git Product home page Git Product logo

saltechsystems / couchbase_lite Goto Github PK

View Code? Open in Web Editor NEW
61.0 10.0 29.0 9.5 MB

Flutter plugin for the Community edition of Couchbase Lite. Couchbase Lite is an embedded lightweight, document-oriented (NoSQL), syncable database engine.

License: MIT License

Java 25.74% Ruby 0.62% Swift 22.35% Objective-C 0.10% Dart 51.19%
flutter flutter-plugin dart plugin android ios nosql flutter-package couchbase package

couchbase_lite's Introduction

couchbase_lite plugin

Build Status Coverage Status pub package

A Flutter plugin for Couchbase Lite Community Edition. An embedded lightweight, noSQL database with live synchronization and offline support on Android and iOS.

The goal of this project is to align this library with the Swift SDK API for Couchbase Lite.

Note: This plugin is still under development, and some APIs might not be available yet. Feedback and Pull Requests are most welcome!

This project forked from Fluttercouch

Getting Started

In your flutter project add the dependency:

dependencies:
  couchbase_lite: ^2.7.1
  
  flutter:
      sdk: flutter

For help getting started with Flutter, view the online documentation

Supported Versions

iOS

Platform Minimum OS version
iOS 10.0 (9.0 - DEPRECATED)

Android

Platform Runtime architectures Minimum API Level
Android armeabi-v7a 22 (19 - DEPRECATED)
Android arm64-v8a 22 (21 - DEPRECATED)
Android x86 22 (19 - DEPRECATED)
Android x86_64 22

API References

Swift SDK API References

Java SDK API References

Note: Syntax follows the Swift SDK but these are the SDKs used for the platform code.

Local Server Setup

Download and setup Couchbase Server / Sync Gateway Community Editions on your local machine the following link

Setup beer-sample database Local Couchbase Server:

  • Add the beer-sample bucket: Settings > Sample Buckets
  • Create a sync_gateway user in the Couchbase Server under Security
  • Give sync_gateway access to the beer-sample

Start Sync Gateway:

~/Downloads/couchbase-sync-gateway/bin/sync_gateway ~/path/to/sync-gateway-config.json

Note: Included in this example is sync-gateway-config.json (Login => u: foo, p: bar)

Usage example

Below is an example for the database using the BLoC pattern ( View <-> BLoC <-> Repository <-> Database )

// Initialize the database
try {
  database = await Database.initWithName("gettingStarted");
} on PlatformException {
  return "Error initializing database";
}

// Create a new document (i.e. a record) in the database.
var mutableDoc = MutableDocument()
    .setDouble("version", 2.0)
    .setString("type", "SDK");

// Save it to the database.
try{
  await database.saveDocument(mutableDoc);
} on PlatformException {
  return "Error saving document";
}

// Update a document.
mutableDoc = (await database.document(mutableDoc.id))?.toMutable()?.setString("language", "Dart");

if (mutableDoc != null) {
  // Save it to the database.
  try {
    await database.saveDocument(mutableDoc);

    var document = await database.document(mutableDoc.id);

    // Log the document ID (generated by the database)
    // and properties
    print("Document ID :: ${document.id}");
    print("Learning ${document.getString("language")}");
  } on PlatformException {
    return "Error saving document";
  }
}

// Create a query to fetch documents of type SDK.
var query = QueryBuilder
    .select([SelectResult.all().from("mydocs")])
    .from("gettingStarted", as: "mydocs")
    .where(Expression.property("type").from("mydocs").equalTo(Expression.string("SDK")));

// Run the query.
try {
  var result = await query.execute();
  print("Number of rows :: ${result.allResults().length}");
} on PlatformException {
  return "Error running the query";
}

// Note wss://10.0.2.2:4984/my-database is for the android simulator on your local machine's couchbase database
// Create replicators to push and pull changes to and from the cloud.
ReplicatorConfiguration config =
ReplicatorConfiguration(database, "ws://10.0.2.2:4984/beer-sample");
config.replicatorType = ReplicatorType.pushAndPull;
config.continuous = true;

// Add authentication.
config.authenticator = BasicAuthenticator("foo", "bar");

// Create replicator (make sure to add an instance or static variable named replicator)
var replicator = Replicator(config);

// Listen to replicator change events.
_listenerToken = replicator.addChangeListener((ReplicatorChange event) {
  if (event.status.error != null) {
    print("Error: " + event.status.error);
  }

  print(event.status.activity.toString());
});

// Start replication.
await replicator.start();

For this getting started guide, you will need to allow using ws protocol.

As of Android Pie, version 9, API 28, cleartext support is disabled, by default. Although wss: protocol URLs are not affected, in order to use the ws: protocol, applications must target API 27 or lower, or must configure application network security as described here.

<application android:usesCleartextTraffic="true">
</application>

App Transport Security is enabled by default since iOS 9 and enforces applications to use HTTPS exclusively. For this getting started guide, you will disable it but we recommend to enable it in production (and enable HTTPS on Sync Gateway). In the Xcode navigator, right-click on Info.plist and open it as a source file.

Append the following inside of the XML tags to disable ATS.

<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>

couchbase_lite's People

Contributors

allanwolski avatar bangfalse avatar bawelter avatar e-adrien avatar ethras avatar matsunanaro avatar rudiksz avatar saltechdevelopers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

couchbase_lite's Issues

Module compiled with Swift 5.3.2 cannot be imported by the Swift 5.5.1 compiler

I have Xcode 13.1 installed running app from flutter on iOS simulator gives issue such module compiled by Swift 5.3.2 cannot be imported by Swift 5.5.1. Even though changing from swift version from Build Setting could not solve problem.

<unknown>:0: error: unable to load standard library for target 'arm64-apple-ios9.0' /Users/thereameekey/flutter/.pub-cache/hosted/pub.dartlang.org/couchbase_lite-3.0.0-nullsafety.2/ios/Classes/CBManager.swift:10:8: error: module compiled with Swift 5.3.2 cannot be imported by the Swift 5.5.1 compiler: /Users/thereameekey/tass/tassovec/ios/Pods/CouchbaseLite-Swift/iOS/CouchbaseLiteSwift.framework/Modules/CouchbaseLiteSwift.swiftmodule/arm64.swiftmodule import CouchbaseLiteSwift

Hi

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Go to '...'
  2. Click on '....'
  3. Scroll down to '....'
  4. See error

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS]
  • Browser [e.g. chrome, safari]
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6]
  • OS: [e.g. iOS8.1]
  • Browser [e.g. stock browser, safari]
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Network unreachable

I am trying to connect the replicator and I am getting the network unreachable

Fatal Error: couchbase_lite/couchbase_lite-Swift.h file not found

I am trying to run a flutter app on the ios simulator and it's failing with the following error:

ios/Classes/CouchbaseLitePlugin.m:2:9: fatal error: 'couchbase_lite/couchbase_lite-Swift.h'
file not found
#import <couchbase_lite/couchbase_lite-Swift.h>

which ultimately results in:

Could not build the application for the simulator.
Error launching application on iPhone 11 Pro Max.

I couldn't find the file either but I'm quite unfamiliar with ios builds. Is couchbase_lite-Swift.h a generated file or something? Or do I need to install or copy couchbase lite swift files somewhere?

The application was started about 10 months ago and has been built in VScode on a windows machine. It runs without a problem on Android and I'm now trying to get it onto an iPhone simulator.

I'm pointing at a beta branch commit from my pubspec.yaml:

  couchbase_lite:
    git:
      url: git://github.com/SaltechSystems/couchbase_lite.git
      ref: 2b53288

Steps to reproduce the behavior:

  1. Navigate to my project folder
  2. type:

Flutter Run

  1. See error
  • Device: iPhone 11 simulator

SessionAuthenticator not working when cookieName is not specified

If a ReplicatorConfiguration class is set up with a SessionAuthenticator whose cookieName is not specified, the associated Replicator will fail with an error code "Unauthorized".

I believe the culprit is in the "guard" statement in the file ios/Classes/CBManager.swift:285

The guard statement will return nil because the json parameter can not be casted as a Dictionary<String, String> as it contains a NSNull object. For instance, when a SessionAuthenticator is initialized without a cookieName.

func inflateAuthenticator(json: Any?) throws -> Authenticator? {
        guard let map = json as? Dictionary<String,String> else {
            return nil
        }
        
        switch map["method"] {
        case "basic":
            guard let username = map["username"], let password = map["password"] else {
                throw CBManagerError.MissingArgument
            }
            
            return BasicAuthenticator(username: username, password: password)
        case "session":
            guard let sessionId = map["sessionId"] else {
                throw CBManagerError.MissingArgument
            }
            
            return SessionAuthenticator(sessionID: sessionId, cookieName: map["cookieName"])
        default:
            throw CBManagerError.IllegalArgument
        }
    }

Replicator looses connection after 2 1/2 Minutes with error 'Error: Websocket connection closed by peer'

Describe the bug
Replicator looses connection after 2 1/2 Minutes with error 'Error: Websocket connection closed by peer'

Replicator status goes to ReplicatorActivityLevel.stopped and stays there.

This problem only exists with version 2.8.1
With previous versions the Replicator reconnected without problems.

Only tested on Android so far

*Edit

Here are some code snippets

This is how I start the replication

_database = await Database.initWithName(databaseName);
final couchbaseUrl = 'wss://$host/fieldforce_$client';
final config = ReplicatorConfiguration(_database, couchbaseUrl);
config.replicatorType = ReplicatorType.pushAndPull;
config.continuous = true;
config.authenticator =
          SessionAuthenticator(store.state.appSettingsState.syncToken);
_replicator = Replicator(config);
await _replicator.start();

This is the error in the client when I lose the connection after 150 seconds
The 1001 is described in the documentation as 1001: DNS resolution error. But unsure why it looses the connection after a certain time.
It works fine with version 2.7.1

E/CouchbaseLite/REPLICATOR( 9062): {Repl#1} Got LiteCore error: WebSocket error 1001 "WebSocket connection closed by peer" 
I/flutter ( 9062): 2021-05-21T11:10:53.448496 ⛔ CouchbaseClient - Error: WebSocket connection closed by peer
I/flutter ( 9062): (CouchbaseLite Android v2.8.1-1 (CE/release, Commit/a9c0287d1e@c65a5127e818 Core/2.8.1 (1) at 2020-10-31T20:38:30.143Z) on Java; Android 10; SM-A515F)

These are the SyncGateway log from starting the session and when the disconnect happens. Seems normal

2021-05-21T09:21:11.742966501Z 2021-05-21T09:21:11.741Z [INF] WS: c:#8840 Start BLIP/Websocket handler
2021-05-21T09:21:11.743003839Z 2021-05-21T09:21:11.741Z [DBG] WSFrame+: c:#8840 Sender starting
2021-05-21T09:21:11.771464594Z 2021-05-21T09:21:11.769Z [DBG] WSFrame+: c:#8840 Received frame: MSG#1 (flags=       0, length=62)
2021-05-21T09:21:11.771497207Z 2021-05-21T09:21:11.769Z [DBG] WS+: c:#8840 Incoming BLIP Request: MSG#1
2021-05-21T09:23:41.813368847Z 2021-05-21T09:23:41.811Z [DBG] WSFrame+: c:#8840 receiveLoop stopped
2021-05-21T09:23:41.813450268Z 2021-05-21T09:23:41.811Z [DBG] WSFrame+: c:#8840 parseLoop stopped
2021-05-21T09:23:41.813461064Z 2021-05-21T09:23:41.811Z [DBG] WSFrame+: c:#8840 Sender stopped
2021-05-21T09:23:41.863769406Z 2021-05-21T09:23:41.862Z [INF] HTTP: c:[e898402] #8840: --> BLIP+WebSocket connection closed
2021-05-21T09:23:41.863819544Z 2021-05-21T09:23:41.862Z [DBG] Changes+: Notifying to check for _changes feed termination
2021-05-21T09:23:41.863826558Z 2021-05-21T09:23:41.862Z [DBG] Changes+: No new changes to send to change listener. Waiting for "Fieldforce_01"'s count to pass 60
2021-05-21T09:23:41.863830944Z 2021-05-21T09:23:41.862Z [INF] Changes: c:[e898402] MultiChangesFeed done (to joe.wilhelm2)
2021-05-21T09:23:41.863834890Z 2021-05-21T09:23:41.862Z [DBG] SyncMsg+: c:[e898402] #2: Type:subChanges --> Time:2m30.067421298s

flutter doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 1.22.4, on macOS 11.2.3 20D91 darwin-x64, locale
    en-GB)
 
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 12.4)
[✓] Android Studio (version 4.0)
[✓] VS Code (version 1.56.2)
[✓] Connected device (2 available)
    ! Error: iPhone is not paired with your computer. To use iPhone with Xcode,
      unlock it and choose to trust this computer when prompted. (code -9)

• No issues found!

Desktop support

Hi, what is the block of supporting mac and windows? Is there a package which doesn't support that?

Pinned Certificate Required for Replicator

Describe the bug
Pinned certificate is required to connect a replicator.

To Reproduce
Steps to reproduce the behavior:

  1. Create a replicator without a pinned certificate.
  2. Start the replicator and get an error.

Expected behavior
No error is expected when a pinned certificate is provided.

Out of date dependencies

Describe the bug
Unmached peer dependencies with other installed libraries

To Reproduce
Steps to reproduce the behavior:

  1. Install couchbase_lit
  2. Install another library like flutter_flavorizr v2 flutter_cache_manager v3
  3. Dependency conflict

Expected behavior
Install as expected

Screenshots
None

Additional context
Can you update dependencies of this library specifically encrypt crypto uuid pedantic so that we can install latest versions of other libraries too?

null-safety migrated app crash on document change (listener)

Describe the bug
We've migrated our app to null-safety using the latest tag v3.0.0-nullsafety.1
However, the app crashes whenever there is a document change (in the hosted couchbase bucket).

To Reproduce
Steps to reproduce the behavior:

  1. Migrated the couchbase_lite_example app to null-safety
  2. Log in using foo/bar
  3. In the couchbase server, manually change a document in the 'sample-beer' bucket
  4. The migrated app will crash with the following exception:

I/flutter ( 3367): ReplicatorActivityLevel.busy E/flutter ( 3367): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: type 'List<Object?>' is not a subtype of type 'List<Object>' in type cast E/flutter ( 3367): #0 Database.addDocumentChangeListener.<anonymous closure> package:couchbase_lite/src/database.dart:223 E

Additional context
The crash was due to a downcast in 'couchbase_lite/src/database.dart:223'.
I believe the downcast should be List<dynamic> instead.

`ListenerToken addDocumentChangeListener(String withId,
Function(DocumentChange) callback) {
var token = ListenerToken();

tokens[token] = _stream
    .where((data) =>
(data['database'] == name && data['type'] == 'DatabaseChange') &&
    (data['documentIDs'] as List<Object>).contains(withId))
                                          ^^^^^^^^^^^^^
  ///  Failed to cast as List<Object>. Should it be cast as List<dynamic> instead?
    .listen((data) {
  callback(DocumentChange(this, withId));
});

// Caveat:  Do not call addChangeListener more than once.
if (tokens.length == 1) {
  _methodChannel.invokeMethod(
      'addChangeListener', <String, dynamic>{'database': name});
}

`

Failed to build the example app on v3.0.0-nullsafety.1

Describe the bug
Failed to build the example app using v3.0.0-nullsafety.1.
The example app appears not to be migrated to null safety yet; while its parent package has!

To Reproduce
Steps to reproduce the behavior:

  1. Launch IDE e.g. Visual Studio

  2. Click on the main.dart file under the example subfolder

  3. Build

  4. The following errors will appear:
    BuiltValueNullFieldError.checkNotNull(
    ^^^^^^^^^^^^
    ../lib/src/replicated_document.g.dart:85:30: Error: Method not found: 'BuiltValueNullFieldError.checkNotNull'.
    BuiltValueNullFieldError.checkNotNull(id, 'ReplicatedDocument', 'id');

                          ^^^^^^^^^^^^
    

../lib/src/replicated_document.g.dart:86:30: Error: Method not found: 'BuiltValueNullFieldError.checkNotNull'.
BuiltValueNullFieldError.checkNotNull(flags, 'ReplicatedDocument', 'flags');
^^^^^^^^^^^^
Additional context
If you open the file "example/pubspec.yaml", the environment is still set to:

environment:
sdk: ">=2.6.0 <3.0.0"

It clearly indicates that the example app needs to be migrated to null safety. Or it won't build successfully

Cannot close the database

Describe the bug
Getting the error when closing the database: Cannot close the database. Please remove all of the query listeners before closing the database.

To Reproduce
Steps to reproduce the behavior:

  1. Add a query change listener
  2. Remove query change listener
  3. Close the database
  4. See error

And Query is not working returning empty result.

Describe the bug
When I do Query like select * from document where sth =sth and sth = sth it does not work

To Reproduce

Future<List<Map<String, dynamic>>> filter(
QueryBuilder.select([SelectResult.all()])
        .from(CoreDB.instance.dbName)
        .where(
          Expression.property(property)
              .equalTo(
                Expression.string(equator),
              )
              .and(
                Expression.property(andProperty).equalTo(
                  Expression.string(andEquator),
                ),
              )
}

Expected behavior
I expect that if I have a document that has for example table='users' name='richard murag' id=WDF to be returned by that
Query This is How I would call it final ```
List<Map<String, dynamic>> product = await _databaseService.filter(
equator: 'richard murag',
property: 'name',
and: true,
andProperty: 'table',
andEquator: 'users,
);


 - OS: [android 29 sdk]

 - Version [couchbase_lite: ^2.7.1+6]

I need your help on this.

Get the document It within the response

When Creating a document the system creates a document ID this ID can be used to update a document, later on, the problem is that there is no way we can get this ID when querying the document. What do you think if the document is returned with the ID?

Channels not working when I connect to CB the first time

Describe the bug

When I fetch data for the first time after app install I can't get data if I use the new 'channel' config. You can see my config code here. The line that is commented out is the problem. If I kill the app and restart, everything works fine. I test this on multiple Android phones

'final config =
ReplicatorConfiguration(database, 'wss://$host/fieldforce$client');
config.replicatorType = ReplicatorType.pushAndPull;
config.continuous = true;
// config.channels = [store.state.appSettingsState.username];
config.authenticator = SessionAuthenticator(token);
_replicator = Replicator(config);'

This is one of my queries

var query = QueryBuilder.select([ SelectResult.all(), ]).from(DATABASE_NAME).where( Expression.property('type').equalTo(Expression.string('job')), );

nil certificate key

First of all, thanks for this great piece of code.

Now, any idea why I'm always getting a "nil" lookupkey when trying to access the cert asset??

Again awesome work from you guys.

Non-Static EventChannel BroadcastStream

Describe the bug
The replicator EventChannel BroadcastStream is being created with a non-static variable which will cause _replicationEventChannel.receiveBroadcastStream() to be called multiple times with active streams being listened to. This will cause previous replicator change listeners to not get an alert when more than one replicator is used.

Reproduce
Create two replicators with change listeners.
The first replicator will not get change events.

Unable to install

Describe the bug
Unable to install couchbase_lite

To Reproduce
Steps to reproduce the behavior:

  1. Create a new Flutter App
  2. Add couchbase_lite by adding couchbase_lite: ^2.7.1 to the pubspec.yaml, get pub
  3. Debug

Expected behavior
It builds and deploys

Screenshots
C:\dev\FlutterCouch101\fluttercouch101\android\app\src\debug\AndroidManifest.xml:4:9-40 Error:
Attribute application@label value=(fluttercouch101) from AndroidManifest.xml:4:9-40
is also present at [com.couchbase.lite:couchbase-lite-android:2.8.1] AndroidManifest.xml:33:18-50 value=(@string/app_name).
Suggestion: add 'tools:replace="android:label"' to element at AndroidManifest.xml:3:4-40:19 to override.

FAILURE: Build failed with an exception.

  • What went wrong:
    Execution failed for task ':app:processDebugMainManifest'.

Manifest merger failed : Attribute application@label value=(fluttercouch101) from AndroidManifest.xml:4:9-40
is also present at [com.couchbase.lite:couchbase-lite-android:2.8.1] AndroidManifest.xml:33:18-50 value=(@string/app_name).
Suggestion: add 'tools:replace="android:label"' to element at AndroidManifest.xml:3:4-40:19 to override.

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

  • Get more help at https://help.gradle.org

BUILD FAILED in 10s
Exception: Gradle task assembleDebug failed with exit code 1
Exited (sigterm)

Desktop (please complete the following information):

  • OS: Windows 10 pro
  • Browser chrome
  • Version 90.0.4430.93 (Official Build) (64-bit)

Smartphone (please complete the following information):

  • Device: flutter emulator Android 11
  • OS: Android
  • Browser
  • Version

Support batch database operations

It would be great to allow for batch operations for efficiency (like avoiding unnecessary change events after saving docs etc..)

The solution would just expose the couchbase lite functionality for batch operations

Querying boolean property returns as int

Describe the bug
getting property inserted as boolean in int format

To Reproduce
db.saveDocument(MutableDocument()
.setString('type', TYPE)
.setString('title', title)
.setBoolean('done', done));

await QueryBuilder.select([
SelectResult.expression(Meta.id.from(ALIAS)).as('id'),
SelectResult.expression(Expression.property('title').from(ALIAS))
.as('title'),
SelectResult.expression(Expression.property('done')
.from(ALIAS))
.as('done')
])
.from(Constants.DB_NAME, as: ALIAS)
.where(Expression.property('type')
.from(ALIAS)
.equalTo(Expression.string(TYPE)))
.execute()

Expected behavior
Each Result in ResultSet should have a done property with boolean value on it but returned result is an int

Database encryption

Are you guys planning on adding the ability to encrypt the local file of the database? I just read the docs for Couchbase Lite Android and Swift, they both support it.

Here are the links:
https://docs.couchbase.com/couchbase-lite/current/android/learn/java-android-database.html#database-encryption
https://docs.couchbase.com/couchbase-lite/current/swift/learn/swift-database.html#database-encryption

In both cases the encryption is set in the DatabaseConfiguration when creating the database. So perhaps you can add a way for us to set this configuration through Flutter?

Im also open to making a PR for this...

Thank you,
Oliver

How to enable verbose log

Is there a way to enable verbose logging? I saw that the option exists for Android & iOS sdk but I can't find it in the Flutter package.

Thanks

Database.addDocumentChangeListener seems to be missing

In Couchbase Lite SDK for iOS and Android, there is a method, Database.addDocumentChangeListener(withID:listener:), that can be used to listen to change of a specific document. But this method seems to be missing in this SDK.

PlatformException(error, java.lang.Long cannot be cast to java.lang.Integer, null)

when the data map contains a large integer (which is java's long), execute query on this field like


final Query query = QueryBuilder.select([SelectResult.all().from(_alias)])
        .from(_couchDb.dbName, as: _alias)
        .where(Expression.property("expireIn")
            .from(_alias)
            .lessThan(Expression.intValue(currentTime)));
    var retSet = await query.execute();

error occurs

Unhandled Exception: PlatformException(error, java.lang.Long cannot be cast to java.lang.Integer, null)
E/flutter (26935): #0      JSONMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:149:7)
E/flutter (26935): #1      MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:321:33)
E/flutter (26935): <asynchronous suspension>
E/flutter (26935): #2      Query.execute (package:couchbase_lite/src/query/query.dart:31:26)

Crash on query with predicate using long attributes.

Describe the bug
Crash on query with predicate using long attributes.

Our app was making a query for a time period represented by two int64/long attributes in Unix Epoch Time, i.e milliseconds since 1970 Jan 1. However, it crashed with the following stack:

I/flutter (11304): onChange -- cubit: GlucoseQueryBloc, change: Change { currentState: GlucoseQueryLoading(), nextState: GlucoseQueryFailure: Failed to query database: Error querying Couchbase repository: CouchBaseRepositoryException: Error querying Couchbase repository: PlatformException(error, java.lang.Long cannot be cast to java.lang.Integer, null, java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.Integer
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.QueryJson.inflateExpressionFromArray(QueryJson.java:361)
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.QueryJson.inflateExpressionFromArray(QueryJson.java:528)
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.QueryJson.inflateExpressionFromArray(QueryJson.java:519)
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.QueryJson.inflateWhere(QueryJson.java:321)
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.QueryJson.toCouchbaseQuery(QueryJson.java:114)
I/flutter (11304): 	at com.saltechsystems.couchbase_lite.CouchbaseLitePlugin$JSONCallHandler.onMethodCall(CouchbaseLitePlugin.java:708)
I/flutter (11304): 	at io.flutter.plugin.common.MethodCha

To Reproduce
Simply make a query with a long attribute in its predicate

Expected behavior
It seems that the code couldn't handle long on Android. However, it was working fine with iOS implementation.

Smartphone

  • Device: Pixel 2 API 29 android-x86 simulator
  • OS: Android 10

Additional context
According to the official document from Flutter here, a Long object is used in Java when its representation in Dart is an integer with > 32 bits.

App from PlayStore crashes

Problem: USB debug works. After downloading from PlayStore, the app will not work. This is caused by R8 minimization

Reproduce errors locally:
android/app/build.gradle, area buildTypes

buildTypes {
    debug {
        debuggable true
        minifyEnabled true
        signingConfig signingConfigs.release
    }
    release {
        signingConfig signingConfigs.release
    }
}

with "minifyEnabled true" you get errors in Logcat:

07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.NoSuchMethodError: no static method "Lcom/couchbase/lite/internal/core/C4DatabaseObserver;.callback(J)V"
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader, java.lang.String) (Runtime.java:-2)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.String java.lang.Runtime.doLoad(java.lang.String, java.lang.ClassLoader) (Runtime.java:435)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void java.lang.Runtime.loadLibrary(java.lang.String, java.lang.ClassLoader) (Runtime.java:370)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void java.lang.System.loadLibrary(java.lang.String) (System.java:1076)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void b.a.a.g0.a(android.content.Context) (:63)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void b.b.a.c.<init>(c.a.b.a.l$c) (:97)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void b.b.a.c.a(c.a.b.a.l$c) (:70)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void io.flutter.plugins.GeneratedPluginRegistrant.registerWith(io.flutter.embedding.engine.a) (:18)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void io.flutter.embedding.android.d.c(io.flutter.embedding.engine.a) (:972)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void io.flutter.embedding.android.d.a(io.flutter.embedding.engine.a) (:873)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void io.flutter.embedding.android.e.a(android.content.Context) (:178)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void io.flutter.embedding.android.d.onCreate(android.os.Bundle) (:409)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.Activity.performCreate(android.os.Bundle) (Activity.java:6877)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.Instrumentation.callActivityOnCreate(android.app.Activity, android.os.Bundle) (Instrumentation.java:1136)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:3209)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:3352)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.ActivityThread.access$1100(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:223)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1797)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:102)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.os.Looper.loop() (Looper.java:158)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:7231)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:1230)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:1120)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410] 
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]     in call to NewGlobalRef
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]     from java.lang.String java.lang.Runtime.nativeLoad(java.lang.String, java.lang.ClassLoader, java.lang.String)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410] "main" prio=5 tid=1 Runnable
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   | group="main" sCount=0 dsCount=0 obj=0x760a8598 self=0xb48f6500
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   | sysTid=10249 nice=-11 cgrp=default sched=0/0 handle=0xb6fc0b4c
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   | state=R schedstat=( 163903902 109134544 175 ) utm=9 stm=7 core=0 HZ=100
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   | stack=0xbe057000-0xbe059000 stackSize=8MB
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   | held mutexes= "mutator lock"(shared held)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #00 pc 0035d135  /system/lib/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiPKcPNS_9ArtMethodEPv+116)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #01 pc 0033dc13  /system/lib/libart.so (_ZNK3art6Thread4DumpERNSt3__113basic_ostreamIcNS1_11char_traitsIcEEEE+138)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #02 pc 0024fe89  /system/lib/libart.so (_ZN3art9JavaVMExt8JniAbortEPKcS2_+760)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #03 pc 00250527  /system/lib/libart.so (_ZN3art9JavaVMExt9JniAbortVEPKcS2_St9__va_list+54)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #04 pc 000fbe0b  /system/lib/libart.so (_ZN3art11ScopedCheck6AbortFEPKcz+30)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #05 pc 00100ce7  /system/lib/libart.so (_ZN3art11ScopedCheck5CheckERNS_18ScopedObjectAccessEbPKcPNS_12JniValueTypeE.constprop.95+5054)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #06 pc 0011249d  /system/lib/libart.so (_ZN3art8CheckJNI12NewGlobalRefEP7_JNIEnvP8_jobject+376)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #07 pc 00336bb9  /system/lib/libart.so (_ZN3art6Thread22SetClassLoaderOverrideEP8_jobject+32)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #08 pc 00250a89  /system/lib/libart.so (_ZN3art9JavaVMExt17LoadNativeLibraryEP7_JNIEnvRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEP8_jobjectPS9_+1228)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #09 pc 002c29c7  /system/lib/libart.so (_ZN3artL18Runtime_nativeLoadEP7_JNIEnvP7_jclassP8_jstringP8_jobjectS5_+178)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   native: #10 pc 0020d04d  /system/framework/arm/boot.oat (Java_java_lang_Runtime_nativeLoad__Ljava_lang_String_2Ljava_lang_ClassLoader_2Ljava_lang_String_2+144)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.Runtime.nativeLoad(Native method)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.Runtime.doLoad(Runtime.java:435)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   - locked <0x03bf20e1> (a java.lang.Runtime)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.Runtime.loadLibrary(Runtime.java:370)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.System.loadLibrary(System.java:1076)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at b.a.a.g0.a(:63)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at b.b.a.c.<init>(:97)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at b.b.a.c.a(:70)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at io.flutter.plugins.GeneratedPluginRegistrant.registerWith(:18)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.reflect.Method.invoke!(Native method)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at io.flutter.embedding.android.d.c(:972)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at io.flutter.embedding.android.d.a(:873)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at io.flutter.embedding.android.e.a(:178)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at io.flutter.embedding.android.d.onCreate(:409)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.Activity.performCreate(Activity.java:6877)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1136)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3209)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3352)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.ActivityThread.access$1100(ActivityThread.java:223)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1797)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.os.Handler.dispatchMessage(Handler.java:102)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.os.Looper.loop(Looper.java:158)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at android.app.ActivityThread.main(ActivityThread.java:7231)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at java.lang.reflect.Method.invoke!(Native method)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410]   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/java_vm_ext.cc:410] 
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/runtime.cc:368] Runtime aborting...
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/art: art/runtime/runtime.cc:368] 
07-30 18:37:17.760 10249-10249/de.trames.umkreis A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 10249 (.trames.umkreis)

Currently release can only be created with "flutter build appbundle --no-shrink"

iN() not working properly. It is returning all records in that documentType.

Describe the bug
Issue with iN() query in flutter CouchBase. in() works fine in iOS as I am iOS developer I have used it before too. But in flutter it returns all the records under that documentType.

To Reproduce
Steps to reproduce the behavior:

  1. Use iN() and pass expressions list to it.
  2. I have only 3 documents in couchbase_db having ids as 1, 2, 3 in int format. I have just passed 1 in below expression it returns all 3 documents. I thought issue with my query but just replaced iN() with equalTo(expressions[0]) it works fine.

List<Expression> expressions = [idsArray.map((id)](url) => Expression.string(id)).toList();
Query query = QueryBuilder.select([SelectResult.all()]) .from("couch_db") .where(Expression.property("documentType") .equalTo(Expression.string("student")) .and(Expression.property("id").iN(expressions)));

Expected behavior
It should return only documents that are related to List<Expressions> passed in where query.

Screenshots
screen_shot

Desktop:

  • macOS for development and iOS device / Android device(In android emulator it shows only 2 documents 1, 3 tried by passing any id)

Supporting 32 and 64 bit

After a bit of trial and error I've found that, unfortunately, couchbase_lite doesn't yet support native 64 and 32 bit code which means it can't be in an app published via the Google Play Console.

From the playconsole:
image

Functions (Expression) not working

the use of any function of "Functions"-class results in error message:

Failed to handle method call E/MethodChannel#com.saltechsystems.couchbase_lite/json(11267): java.lang.IllegalArgumentException: expression cannot be null. E/MethodChannel#com.saltechsystems.couchbase_lite/json(11267): at com.couchbase.lite.From.where(From.java:71) E/MethodChannel#com.saltechsystems.couchbase_lite/json(11267): at com.saltechsystems.couchbase_lite.QueryJson.inflateWhere(QueryJson.java:270) E/MethodChannel#com.saltechsystems.couchbase_lite/json(11267): at com.saltechsystems.couchbase_lite.QueryJson.toCouchbaseQuery(QueryJson.java:64) E/MethodChannel#com.saltechsystems.couchbase_lite/json(11267): at com.saltechsystems.couchbase_lite.CouchbaseLitePlugin$JSONCallHandler.onMethodCall(CouchbaseLitePlugin.java:294)

it seems there are no implementations of these functions in QueryJson.java

Crash when initiating database, but only with published app

Describe the bug
Flutter application that has been published on Google Play crashes when initializing database

To Reproduce
Steps to reproduce the behavior:

  1. Release application to the play store with
    _database = await Database.initWithName(_dbName);
  2. Run the application with logcat open in Android Studio
  3. Watch the application crash and burn
  4. See error:

E/flutter: [ERROR:flutter/shell/platform/android/platform_view_android_jni.cc(39)] java.lang.NoSuchMethodError: no static method "Lcom/couchbase/litecore/C4Log;.logCallback(Ljava/lang/String;ILjava/lang/String;)V"
at com.couchbase.litecore.C4Log.setCallbackLevel(Native Method)
at com.couchbase.a.ar.(Unknown Source:23)
at com.couchbase.a.a.(Unknown Source:5)
at com.b.a.a.b(Unknown Source:8)
at com.b.a.c$a.onMethodCall(Unknown Source:1043)
at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(Unknown Source:17)
at io.flutter.embedding.engine.dart.DartMessenger.handleMessageFromDart(Unknown Source:59)
at io.flutter.embedding.engine.FlutterJNI.handlePlatformMessage(Unknown Source:6)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:325)
at android.os.Looper.loop(Looper.java:142)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

Smartphone (please complete the following information):

  • Device: Samsung Galaxy S7 Edge and Samsung Galaxy S7
  • OS: Android 8.0.0

Additional context
I'm using the current beta version of couchbase_lite

I believe the crash occurs while initiating the database as this starts, but never succeeds.

This was originally crashing while testing apks (not during debug) with an application that I created using an older version of flutter. I ported it over to the current version of flutter and the crashes went away during testing, but not in production.

I can't reproduce it in debug, but it reliably occurs in production every time.

Replication Callback not received when document updated/added from another phone

I am trying to implement just a basic demo. The following code runs. properly on an android device. But when the app ran on iPhone, the replication listener is not working. I am expecting a callback in DocumentReplicationListener. The callback never happens in the case of iPhone.
Following is the code. Only posting relevant code. Everything else is a copy of the example code of this repo.

Future<String> runExample() async {
    // Platform messages may fail, so we use a try/catch PlatformException.
    try {
      database = await Database.initWithName("myDb");
    } on PlatformException {
      return "Error initializing database";
    }

    // Create a query to fetch documents of type SDK.
    var query = QueryBuilder.select([SelectResult.all()])
        .from("getting-started-db");

    // Note wss://10.0.2.2:4984/my-database is for the android simulator on your local machine's couchbase database
    // Create replicators to push and pull changes to and from the cloud.
    ReplicatorConfiguration config =ReplicatorConfiguration(database, "ws://ipAddress/myDb");
    config.replicatorType = ReplicatorType.pushAndPull;
    config.continuous = true;
    // Add authentication.
    config.authenticator = BasicAuthenticator("myDb", "myPassword");

    // Create replicator (make sure to add an instance or static variable named replicator)
    var replicator = Replicator(config);

    replicator.addDocumentReplicationListener((callback){

      var docs = callback.documents.last;
      print("replication listener => ${ jsonDecode(docs.toJson())}");
    });

    // Listen to replicator change events.
    _listenerToken = replicator.addChangeListener((ReplicatorChange event) {
      if (event.status.error != null) {
        print("Error: " + event.status.error);
      }

      print("change == "+event.status.activity.toString());
      print("time == ${new DateTime.now().millisecondsSinceEpoch}");

    });

    // Start replication.
    await replicator.start();

    return "Database and Replicator Started";
  }

I want to contribute on writing wiki on this project.

With the right plugin with good features, we need good clear documentation for the community to benefit. I want to take on this but I need your guidance for me to succeed in doing it. please help me on how I can do it, as far as I know, GitHub does not have a way to send a pull request on wiki page.

Is Channel supported?

I like the idea of channel in couchbase is it implemented here or not? please let me know.

Please consider supporting nullsafety (at least in beta channel)

Describe the bug
Version 2.8.1 uses crypto ^2.1.3 which doesn't support nullsafety

To Reproduce

  1. Run flutter pub get
  2. See error
Because pdf >=3.0.0-nullsafety.0 depends on crypto ^3.0.0-nullsafety and couchbase_lite >=2.7.1+6 depends on crypto ^2.1.3, pdf >=3.0.0-nullsafety.0 is incompatible with couchbase_lite >=2.7.1+6.
So, because your app depends on both couchbase_lite ^2.8.1 and pdf ^3.0.0-nullsafety.0, version solving failed.
pub finished with exit code 1

Expected behavior
It should compile, which it does in stable channel.

Additional context
My flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel beta, 1.26.0-17.3.pre, on Linux, locale en_US.UTF-8)
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/linux#android-setup for more details.
[✓] Chrome - develop for the web
[!] Android Studio (not installed)
[✓] Connected device (2 available)

Some confusions

I'm so sorry for opening an issue here, I hope someone can enlighten me a bit.
Currently, I'm developing a mobile app I've decided to use CouchDB as my backend. but for the mobile side apparently another CouchDB implementation must be available, I mean a NoSQL database running in user's mobile(Right?) So Couchbase lite does exactly that(Are there any opensource alternatives?)
Also searching for flutter ports I found that there is fluutercouch can you explain in what way have you edited this library from that? any new features or refactors? (I saw that some API signatures are changed)
Can couchBase lite work with a CouchDB or should the backend be also Couchbase?
Also, I'm concerned about switching from CouchDB to couchBase, does the community edition has all features of CouchDB and does its source code get updates from CouchDB?

Adding documents and then syncing via channel filtering

Is there any to use the filter on a pull method.

pull.Filter=“sync_gateway/bychannel”; // Added for filtering
pull.Channels = channel; // Added for filtering

push.Continuous = true;
pull.Continuous = true;

push.Start();
pull.Start();

Long Problem in pullAttributeFilters

If you use

  config.pullAttributeFilters = {
      "sender": [1]
    };

in replication config you got a empty response, that is because the value of Dart send is of int but the response JSON in Java is of Lang.Long

i solved the problem with a simple if. but it's only a quick fix

Replicatorjson.java line 150

    if (value instanceof Long) {
        try {
            value = ((Long) value).intValue();
        }catch (Exception e) {
            System.out.println("Error"+e.toString());
        }
    }

flutter app does not start for iOS build due to: couchbase_lite does not specify a Swift version

I'm getting the following message upon project startup:

Installing CouchbaseLite (2.7.1)
> Copying CouchbaseLite from /Users/developer/Library/Caches/CocoaPods/Pods/Release/CouchbaseLite/2.7.1-cccdd to Pods/CouchbaseLite

Installing CouchbaseLite-Swift (2.7.1)
> Copying CouchbaseLite-Swift from /Users/developer/Library/Caches/CocoaPods/Pods/Release/CouchbaseLite-Swift/2.7.1-02012 to Pods/CouchbaseLite-Swift

Installing couchbase_lite (0.0.1) ????

couchbase_lite does not specify a Swift version and none of the targets (Runner) integrating it have the SWIFT_VERSION attribute set. Please contact the author or set the SWIFT_VERSION attribute in at least one of the targets that integrate this pod.

I configured the project according to Install help page.

dependencies:
  ...
  couchbase_lite: ^2.7.1

I did not even implement anything yet. Just added a dependency.

Android project starts up without issues.

Module compiled with Swift 5.0.1 cannot be imported by the Swift 5.1 compiler

I have Xcode 11 installed running app from flutter on iOS simulator gives issue such module compiled by Swift 5.0.1 cannot be imported by Swift 5.1. Even though changing from swift version from Build Setting could not solve problem.

/Users/swapnil_dhotre/SwapnilDhotre/Android/FlutterSDK/flutter/.pub-cache/hosted/pub.dartlang.org/couchbase_lite-2.5.1+8/ios/Classes/CBManager.swift:10:8: error: module compiled with Swift 5.0.1 cannot be imported by the Swift 4.2.1 compiler: /Users/swapnil_dhotre/SwapnilDhotre/Github/flutter-cmms/ios/Pods/CouchbaseLite-Swift/iOS/CouchbaseLiteSwift.framework/Modules/CouchbaseLiteSwift.swiftmodule/x86_64.swiftmodule import CouchbaseLiteSwift

Blobs content type is not being read

The content type of a Blob is not being parsed correctly.

in lib/src/Blob.dart

  Blob._fromMap(Map<String, dynamic> map) {
    print(map);
    this._contentType = map["contentType"];
    this._digest = map["digest"];
    this._length = map["length"];
  }

While the result map uses the key "content_type". This causes blobs to be deleted when saving the document again, because contentType is null. Probably because even though all other fields are correct, including the data, couchbase thinks there's no attachment and just deletes the entry altogether.

Replacing the line with the one below, fixes the problem of the blobs being deleted on subsequent saves.
this._contentType = map["content_type"];

There's another instance in Document.dart where the wrong index is used, but I haven't tested that.

Reading and saving documents and blobs (re. PR#66)

#66 (comment)

I'm pretty sure the map/dictionary is enough and probably prefereable. If a blob field has the same content_type and digest as the one already stored in database but no actual data, it's a no-op for the blob. The blob should be preserved. If you also send data then it's replaced.

Fixing this issue has implications in the way documents are read and saved to/from the database, and would significantly impact the platform code, hence this new discussion.

One of the issues I see currently is that the platform code is doing a lot of work parsing data both when reading and saving documents. Below is a working proof of concept that delegates most of the serialization/deserialization to the library itself, therefore greatly simplifying the plugin's code.

A short breakdown of the important bits:

  1. The code below is entirely self-contained and sufficient to read and save documents, and it produces the exact same output as the old implementations. The Dart code requires no changes (except if we want to also handle the revision property, which is strangely missing now).

  2. The SDK has methods which serialize/deserialize maps and they support all the types that the method channel's codec supports - except the Blobs. Therefore, except for transforming the Blob instances into dictionaries, there's no need to do any kind of custom parsing in the platform code.

  3. When reading a document. The SDK has a 'document.toMap()' method, which, if it weren't for the blobs could be just passed to the method channel without any changes. the "_documentToMapNew(Document doc)" method replaces all Blob instances with their dictionary counterpart. The Blob class even has a method for it in 'getProperties()'.

  4. When saving a document the situation is very similar. The map that the method channel passes to the Java code is the same that the MutableDocument's constructors expect - minus the blobs. Here the situation is a bit more complex but not by much.

If you set a @blob field with byte data in it, the MutableDocument needs a Blob instance instead of a simple dictionary.

Ex: this is a document that is being saved with a new blob
{age=10, languages=[en, es], active=true, id=person1, avatar={digest=null, @type=blob, length=null, data=[B@e3e7d9b, content_type=image/png}, settings={list=[1, 2, 3, 4, 5], a=b, x=y, map={1=one, 2=two, 3=three}}, doctype=person, name=Person1, height=5.6, birthday=2000-02-02T00:00:00.000}

If there are @blob fields in the dictionary, but their data field is empty, then the MutableDocument can deserialize it by himself and the blobs are preserved as expected. In other words, if there is no data sent, there is no need to convert the metadata into a Blob instance. With the new code that is accessing the blob files directly, this allows an important optimization on the dart side to only send data when the data is actually changed (like when uploading a new avatar). In every other case only the metada is ever sent. More importantly, the part that is relevant to the PR66 is that there is no need to ever keep track or cache the blobs in the platform side. It is the resposability of the dart code to ensure that the blobs in a document are preserved, updated or deleted according to the business logic.

Ex: this is a document that was read in dart using "database.document()' and saved again but without reading or writing the 'avatar' field.
{age=10, active=true, languages=[en, es], id=person1, avatar={digest=sha1-K5R8dtFHQYSI4daLqfJwXQgZb8k=, @type=blob, length=120, content_type=image/png}, settings={a=b, list=[1, 2, 3, 4, 5], x=y, map={1=one, 2=two, 3=three}}, doctype=person, height=5.6, name=Person1, birthday=2000-02-02T00:00:00.000}

Hint: The blob was preserved.

  1. Currently this code assumes that the blobs are only at the first level of the document, and doesn't handle blobs in nested values. I'm not aware of any way to set blobs deeper in the document, but I'll try to investigate this further to confirm it.
     Map<String, Object> getDocumentWithIdNew(Database database, String _id) {
        HashMap<String, Object> resultMap = new HashMap<>();

        Document document = database.getDocument(_id);

        if (document != null) {
            resultMap.put("doc", _documentToMapNew(document));
            resultMap.put("id", document.getId());
            resultMap.put("rev", document.getRevisionID());
            resultMap.put("sequence", document.getSequence());
        } else {
            resultMap.put("doc", null);
            resultMap.put("id", _id);
        }

        return resultMap;
    }

    Map<String, Object> saveDocumentNew(Database database, Object id, Map<String, Object> data, ConcurrencyControl concurrencyControl) throws CouchbaseLiteException {
        // Blobs need special attention
        // When sending data we replace the value in the dictionary with a Blob instance.
        // When there is no data sent, we leave the blob's metadata dictionary as is
        // and let Couchbase Core to deserialize it. This will ensure the blobs are preserved.
        for (String key : data.keySet()) {
            Object value = data.get(key);
            if (value instanceof Map<?, ?>) {
                Map<?,?> v = (Map<?,?>) value;
                if (Objects.equals(v.get("@type"),"blob")) {
                    if (v.get("data") != null) {
                        String contentType = (String) v.get("content_type");
                        byte[] blobData = (byte[]) v.get("data");
                        data.put(key, new Blob(contentType, blobData));
                    }
                }
            }
        }

        MutableDocument mutableDoc;
        if (id != null && data != null) {
            mutableDoc = new MutableDocument(id.toString(), data);
        }
        else if (id == null && data == null) {
            mutableDoc = new MutableDocument();
        }
        else if (data == null) {
            mutableDoc = new MutableDocument(id.toString());
        }
        else {
            mutableDoc = new MutableDocument(data);
        }

        boolean success = database.save(mutableDoc, concurrencyControl);
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("success", success);
        if (success) {
            resultMap.put("id", mutableDoc.getId());
            resultMap.put("sequence", mutableDoc.getSequence());
            resultMap.put("rev", mutableDoc.getRevisionID());
            resultMap.put("doc", _documentToMapNew(mutableDoc));
        }
        return resultMap;
    }


    private Map<String, Object> _documentToMapNew(Document doc) {
        Map<String, Object> map = doc.toMap();

        // Replace all Blob instances with their "json" metadata
        for (String key : map.keySet()) {
            if (map.get(key) instanceof Blob) {
                Map<String,Object> json =  ((Blob) map.get(key)).getProperties();
                json.put("@type", "blob");
                map.put(key,json);
            }
        }
        return map;
    }

I have an example app with test code, that I'm cleaning up and I'll try to share in the next few days. I just wanted to put this out there for feedback.


Similar concepts can be used in handling query results too, but that's for another day. Queries return every document in the result set twice, which is not only very inefficient, but also is diverges from the API.

Conflict Resolution

Add concurrencyControl option to the save function for documents which would allow users to properly handle conflicts instead of relying on last write wins strategy which is set by default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.