How to combine two streams where the second depends on the first?
Have you considered using @Entity directly on the DocumentFamily
and DocumentTemplate
classes? See this example that shows it with package freezed
.
In any case you'd probably need to represent the link between the entities as an ObjectBox relation instead of just a plain ID field.
Then box.query().link() to create a query across entities. And if you watch()
that one, it's triggered on changes in the base entity as well as all the linked ones.
Teio07
Updated on November 25, 2022Comments
-
Teio07 over 1 year
I'm building an app where a
Document
has aDocumentTemplate
which belongs to aDocumentFamily
.I'm working on the basic CRUD operations for the app and I need a
watchDocumentTemplateById
method where I get a stream of aDocumentTemplate
but I also need to watch itsDocumentFamily
.The problem is that I have no idea how to nest the two streams so that when a
DocumentFamily
gets updated, theDocumentTemplate
will have the updatedDocumentFamily
.I would really appreciate if someone could show me the right way to do it. I'm using Flutter with ObjectBox as my local database.
Here is the method
watchDocumentTemplateById
I started implementing (unfinished) :@override Stream<Either<DocumentTemplateFailure, DocumentTemplate>> watchDocumentTemplateById(UniqueId templateId) { return _box .query(DocumentTemplateEntity_.id.equals(templateId.getOrCrash())) .watch(triggerImmediately: true) .map((query) { final templateEntity = query.findFirst(); if (null != templateEntity) { final familyOrFailureStream = _documentFamilyRepository.watchDocumentFamilyById( UniqueId.fromUniqueString(templateEntity.familyId)); familyOrFailureStream.listen((familyOrFailure) { return familyOrFailure.fold( (failure) => DocumentTemplateFailure.familyFailure(familyFailure: failure), (family) => templateEntity.toDomain(family: family), ); }); } return left(const DocumentTemplateFailure.notFound()); }); }
And the classes mentioned above (DocumentTemplate, DocumentTemplateEntity, DocumentFamily and DocumentFamilyEntity) :
DocumentTemplate :
@freezed class DocumentTemplate with _$DocumentTemplate { factory DocumentTemplate({ required UniqueId id, required DocumentTemplateTitle title, required double leftMargin, required double topMargin, required double rightMargin, required double bottomMargin, required DocumentFamily family, }) = _DocumentTemplate; }
DocumentTemplateEntity :
@Entity() class DocumentTemplateEntity { @Id() int obid = 0; @Unique() String id; String title; double leftMargin; double topMargin; double rightMargin; double bottomMargin; String familyId; DocumentTemplateEntity({ required this.id, required this.title, required this.leftMargin, required this.topMargin, required this.rightMargin, required this.bottomMargin, required this.familyId, }); DocumentTemplate toDomain({ required DocumentFamily family, }) => DocumentTemplate( id: UniqueId.fromUniqueString(id), title: DocumentTemplateTitle(title), leftMargin: leftMargin, topMargin: topMargin, rightMargin: rightMargin, bottomMargin: bottomMargin, family: family, ); factory DocumentTemplateEntity.fromDomain(DocumentTemplate template) => DocumentTemplateEntity( id: template.id.getOrCrash(), title: template.title.getOrCrash(), leftMargin: template.leftMargin, topMargin: template.topMargin, rightMargin: template.rightMargin, bottomMargin: template.bottomMargin, familyId: template.family.id.getOrCrash(), ); }
DocumentFamily :
@freezed class DocumentFamily with _$DocumentFamily { factory DocumentFamily({ required UniqueId id, required int position, required String name, }) = _DocumentFamily; }
DocumentFamilyEntity :
@Entity() class DocumentFamilyEntity { @Id() int obid = 0; @Unique() String id; String name; int position; DocumentFamilyEntity({ required this.id, required this.name, required this.position, }); DocumentFamily toDomain() => DocumentFamily( id: UniqueId.fromUniqueString(id), name: name, position: position, ); factory DocumentFamilyEntity.fromDomain(DocumentFamily family) => DocumentFamilyEntity( id: family.id.getOrCrash(), name: family.name, position: family.position, ); }
Thanks in advance !
EDIT :
I tried to solve it by myself and found the
switchMap
method, which seems to combine two streams into one but I'm not entirely sure if it will work here's the updatedwatchDocumentTemplateById
method :ref.: How do I nest Streams in Dart (map Streams to Stream events)?
@override Stream<Either<DocumentTemplateFailure, DocumentTemplate>> watchDocumentTemplateById(UniqueId templateId) { return _box .query(DocumentTemplateEntity_.id.equals(templateId.getOrCrash())) .watch(triggerImmediately: true) .switchMap((query) { final templateEntity = query.findFirst(); // if(null == templateEntity) return ??? DocumentTemplateFailure.notFound(); final familyId = UniqueId.fromUniqueString(templateEntity!.familyId); return _documentFamilyRepository.watchDocumentFamilyById(familyId).map( (failureOrFamily) => failureOrFamily.fold( (failure) => left( DocumentTemplateFailure.familyFailure(familyFailure: failure), ), (family) => right( templateEntity.toDomain(family: family), ), ), ); }); }
-
Teio07 almost 3 yearsThat's what I ended up doing. I don't know why I wanted to do it by nesting streams.
-
Teio07 almost 3 yearsI'm building an offline-first app where everything is stored locally using ObjectBox but I'm also using Supabase to share some of the user's data across devices and the DTOs I've created for Supabase just have the id of another table as a foreign key to link them together (my DTOs are a one to one mapping with the database) that's probably why I didn't want to "mess" with ObjectBox's specificities (like relations) but that's actually a lot easier to do with the ToMany and ToOne annotations.
-
minato almost 2 years@vaind can u help me with this issue ? stackoverflow.com/questions/72501459