Subscribe is not listening to remote changes even when policy is set to OfflineFirstGetPolicy.awaitRemote
rutaba1 opened this issue · comments
Hi, I have a configured graphql repository for and working fine for all the operations except subscribe. I had set the policy to OfflineFirstGetPolicy.awaitRemote and when I change anything from the backend the listener is not getting triggered. It triggers only If I do any CRUD operation from the frontend.
Here is the code for my Repository set up
class Repository extends OfflineFirstWithGraphqlRepository {
Repository._(String endpoint)
: super(
migrations: migrations,
graphqlProvider: GraphqlProvider(
link: HttpLink(endpoint),
modelDictionary: graphqlModelDictionary,
),
sqliteProvider: SqliteProvider(
"BrickGraphql.sqlite",
databaseFactory: databaseFactory,
modelDictionary: sqliteModelDictionary,
),
offlineRequestManager: GraphqlRequestSqliteCacheManager(
'brick_graphql_offline_queue.sqlite',
databaseFactory: databaseFactory,
),
autoHydrate: true,
);
factory Repository() => _singleton!;
static Repository? _singleton;
static void configure(String endpoint) {
_singleton = Repository._(endpoint);
}
}
And here is the UI where I'm trying to listen to the stream
StreamBuilder<List<Todo>>(
stream: repository?.subscribe<Todo>(
policy: OfflineFirstGetPolicy.awaitRemote),
builder: (context, ss) {
return ss.data?.isNotEmpty == true
? Center(
child: ListView.builder(
itemCount: ss.data!.length,
itemBuilder: (ctx, i) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
leading: Text(ss.data![i].id),
title: Text(ss.data![i].title),
tileColor: Colors.pink.shade50,
),
);
},
),
)
: const Center(
child: Text("No data available"),
);
},
)
I have also noticed that in initState function I have to call get function to hydrate the local database the stream subscription is not doing it on it's own.
Hey @rutaba1 is your backend GraphQL operation a subscribe
operation or a get
operation?
If you're calling a get
operation, then subscribe
will only add a new event to the stream when local data satisfying the subscribe
query is changed in the SQLite db.
@tshedor It is a subscribe operation and I'm even overriding the subscribe
function in my GraphqlQueryOperationTransformer but still no luck.
@override
GraphqlOperation? get subscribe => const GraphqlOperation(
document: r'''
subscription Subscription{
todo_mutated {
key
event
data {
title
id
}
}
}''',
);
I'm getting an error in console now with no realtime behaviour
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'String' in type cast
E/flutter (19394): #0 _$TodoFromGraphql (package:brick_graphql_test/brick/adapters/todo_adapter.g.dart:8:30)
E/flutter (19394): #1 TodoAdapter.fromGraphql (package:brick_graphql_test/brick/adapters/todo_adapter.g.dart:95:13)
E/flutter (19394): #2 GraphqlProvider.subscribe (package:brick_graphql/src/graphql_provider.dart:131:27)
I'm printing the values from $TodoFromGraphql function in generated adapter and I'm getting this:
MAP______{id: 86, title: Test}
MAP_______{id: 87, title: Fielder}
MAP_______{todo_mutated: null}
Here 1st and 2nd are valid but 3rd is not
@rutaba1 can you please provide your Todo
model? When you say "printing the values" does that mean you're doing print(data)
?
@tshedor Yeah,here is my model
@ConnectOfflineFirstWithGraphql(
graphqlConfig: GraphqlSerializable(
queryOperationTransformer: TodoQueryOperationTransformer.new,
))
class Todo extends OfflineFirstWithGraphqlModel {
@Sqlite(unique: true)
final String id;
final String title;
Todo({
required this.id,
required this.title,
});
}
and in todo_adapter.g.dart
I am printing the value here.
Future<Todo> _$TodoFromGraphql(Map<String, dynamic> data,
{required GraphqlProvider provider,
OfflineFirstWithGraphqlRepository? repository}) async {
print('MAP_______${data}');
return Todo(id: data['id'] as String, title: data['title'] as String);
}
@rutaba1 ah, I see. Brick expects the fields you list within the operation to map as top-level properties for the Dart instance fields. For example, the expected Dart model would be
@ConnectOfflineFirstWithGraphql(
graphqlConfig: GraphqlSerializable(
queryOperationTransformer: TodoQueryOperationTransformer.new,
))
class Todo extends OfflineFirstWithGraphqlModel {
final String key;
final String event;
final Map<String, dynamic> data;
Todo({
required this.key,
required this.event,
required this.data,
});
}
If you want to use the nested properties of data
as instance fields in Dart, you'll need to do some custom remapping:
@ConnectOfflineFirstWithGraphql(
graphqlConfig: GraphqlSerializable(
queryOperationTransformer: TodoQueryOperationTransformer.new,
))
class Todo extends OfflineFirstWithGraphqlModel {
@Sqlite(unique: true)
@Graphql(fromGenerator: "(data['data'] as Map)['id'] as String")
final String id;
@Graphql(fromGenerator: "(data['data'] as Map)['title'] as String")
final String title;
Todo({
required this.id,
required this.title,
});
}
@rutaba1 going to close this due to inactivity