diff --git a/lib/src/cli/deployapps/baas_client.dart b/lib/src/cli/deployapps/baas_client.dart index 16e62d3f7..98959b7b5 100644 --- a/lib/src/cli/deployapps/baas_client.dart +++ b/lib/src/cli/deployapps/baas_client.dart @@ -184,7 +184,7 @@ class BaasClient { "flexible_sync": { "state": "enabled", "database_name": "$_differentiator-$name", - "queryable_fields_names": ["differentiator"], + "queryable_fields_names": ["differentiator", "stringQueryField", "boolQueryField", "intQueryField"], "permissions": { "rules": {}, "defaultRoles": [ diff --git a/test/subscription_test.dart b/test/subscription_test.dart index 1f2354d35..18b1fe890 100644 --- a/test/subscription_test.dart +++ b/test/subscription_test.dart @@ -36,7 +36,12 @@ void testSubscriptions(String name, FutureOr Function(Realm) tester) async final app = App(appConfiguration); final credentials = Credentials.anonymous(); final user = await app.logIn(credentials); - final configuration = Configuration.flexibleSync(user, [Task.schema, Schedule.schema]); + final configuration = Configuration.flexibleSync(user, [ + Task.schema, + Schedule.schema, + Event.schema, + ]) + ..sessionStopPolicy = SessionStopPolicy.immediately; final realm = getRealm(configuration); await tester(realm); }); @@ -498,4 +503,75 @@ Future main([List? args]) async { final realm = getRealm(config); expect(() => realm.write(() => realm.add(Task(ObjectId()))), throws("no flexible sync subscription has been created")); }); + + testSubscriptions('Subscription on unqueryable field sould throw', (realm) async { + realm.subscriptions.update((mutableSubscriptions) { + mutableSubscriptions.add(realm.all()); + }); + + realm.write(() { + realm.addAll([ + Event(ObjectId(), name: "NPMG Event", isCompleted: true, durationInMinutes: 30, assignedTo: "@me"), + Event( + ObjectId(), + name: "NPMG Meeting", + isCompleted: false, + durationInMinutes: 10, + ), + Event(ObjectId(), name: "Some other eveent", isCompleted: true, durationInMinutes: 60), + ]); + }); + + await realm.syncSession.waitForUpload(); + + realm.subscriptions.update((mutableSubscriptions) { + mutableSubscriptions.removeByQuery(realm.all()); + mutableSubscriptions.add(realm.query(r'assignedTo BEGINSWITH $0 AND boolQueryField == $1 AND intQueryField > $2', ["@me", true, 20]), + name: "filter"); + }); + + String expectedErrorMessage = + "Client provided query with bad syntax: unsupported query for table \"${(Event).toString()}\": key \"assignedTo\" is not a queryable field"; + + try { + await realm.subscriptions.waitForSynchronization(); + fail("Expected exception not thrown"); + } catch (e) { + expect(e is RealmException, isTrue); + expect((e as RealmException).message, expectedErrorMessage); + expect(realm.subscriptions.state, SubscriptionSetState.error); + expect(realm.subscriptions.error, isNotNull); + expect(realm.subscriptions.error is RealmException, isTrue); + expect((realm.subscriptions.error as RealmException).message, expectedErrorMessage); + } + }); + + testSubscriptions('Filter realm data using query subscription', (realm) async { + realm.subscriptions.update((mutableSubscriptions) { + mutableSubscriptions.add(realm.all()); + }); + + realm.write(() { + realm.addAll([ + Event(ObjectId(), name: "NPMG Event", isCompleted: true, durationInMinutes: 30), + Event(ObjectId(), name: "NPMG Meeting", isCompleted: false, durationInMinutes: 10), + Event(ObjectId(), name: "Some other eveent", isCompleted: true, durationInMinutes: 60), + ]); + }); + + await realm.syncSession.waitForUpload(); + + realm.subscriptions.update((mutableSubscriptions) { + mutableSubscriptions.removeByQuery(realm.all()); + mutableSubscriptions.add(realm.query(r'stringQueryField BEGINSWITH $0 AND boolQueryField == $1 AND intQueryField > $2', ["NPMG", true, 20]), + name: "filter"); + }); + + await realm.subscriptions.waitForSynchronization(); + + var filtered = realm.query(realm.subscriptions.findByName("filter")!.queryString); + var all = realm.all(); + expect(filtered, isNotEmpty); + expect(filtered.length, all.length); + }); } diff --git a/test/test.dart b/test/test.dart index 6d6ce1775..0a8037c83 100644 --- a/test/test.dart +++ b/test/test.dart @@ -143,6 +143,20 @@ class _NullableTypes { late int? intProp; } +@RealmModel() +class _Event { + @PrimaryKey() + @MapTo('_id') + late ObjectId id; + @MapTo('stringQueryField') + late String? name; + @MapTo('boolQueryField') + late bool? isCompleted; + @MapTo('intQueryField') + late int? durationInMinutes; + late String? assignedTo; +} + String? testName; Map arguments = {}; final baasApps = {}; diff --git a/test/test.g.dart b/test/test.g.dart index 15f09b3d9..9d581f626 100644 --- a/test/test.g.dart +++ b/test/test.g.dart @@ -678,3 +678,73 @@ class NullableTypes extends _NullableTypes with RealmEntity, RealmObject { ]); } } + +class Event extends _Event with RealmEntity, RealmObject { + Event( + ObjectId id, { + String? name, + bool? isCompleted, + int? durationInMinutes, + String? assignedTo, + }) { + RealmObject.set(this, '_id', id); + RealmObject.set(this, 'stringQueryField', name); + RealmObject.set(this, 'boolQueryField', isCompleted); + RealmObject.set(this, 'intQueryField', durationInMinutes); + RealmObject.set(this, 'assignedTo', assignedTo); + } + + Event._(); + + @override + ObjectId get id => RealmObject.get(this, '_id') as ObjectId; + @override + set id(ObjectId value) => throw RealmUnsupportedSetError(); + + @override + String? get name => + RealmObject.get(this, 'stringQueryField') as String?; + @override + set name(String? value) => RealmObject.set(this, 'stringQueryField', value); + + @override + bool? get isCompleted => + RealmObject.get(this, 'boolQueryField') as bool?; + @override + set isCompleted(bool? value) => + RealmObject.set(this, 'boolQueryField', value); + + @override + int? get durationInMinutes => + RealmObject.get(this, 'intQueryField') as int?; + @override + set durationInMinutes(int? value) => + RealmObject.set(this, 'intQueryField', value); + + @override + String? get assignedTo => + RealmObject.get(this, 'assignedTo') as String?; + @override + set assignedTo(String? value) => RealmObject.set(this, 'assignedTo', value); + + @override + Stream> get changes => + RealmObject.getChanges(this); + + static SchemaObject get schema => _schema ??= _initSchema(); + static SchemaObject? _schema; + static SchemaObject _initSchema() { + RealmObject.registerFactory(Event._); + return const SchemaObject(Event, 'Event', [ + SchemaProperty('_id', RealmPropertyType.objectid, + mapTo: '_id', primaryKey: true), + SchemaProperty('stringQueryField', RealmPropertyType.string, + mapTo: 'stringQueryField', optional: true), + SchemaProperty('boolQueryField', RealmPropertyType.bool, + mapTo: 'boolQueryField', optional: true), + SchemaProperty('intQueryField', RealmPropertyType.int, + mapTo: 'intQueryField', optional: true), + SchemaProperty('assignedTo', RealmPropertyType.string, optional: true), + ]); + } +}