toggl-cli icon indicating copy to clipboard operation
toggl-cli copied to clipboard

Connect Tag model to TimeEntry model

Open sjvrijn opened this issue 5 years ago • 2 comments

If a TimeEntry currently has tags associated to it, they are stored as a generic SetField. To link the proper Tag model to the time entries the tags field of TimeEntry should probably change to a MappingField, but cardinality 'many' has not yet been implemented for those.

I'd like to look into it, but I'm stuck with what has to be done to implement that. Any pointers would be very helpful.

sjvrijn avatar Jan 27 '19 17:01 sjvrijn

Ufff yeah, this will be quiet a lot of work 😄 That is mainly the reason why I left out the implementation of many cardinality for now. But it would be very appreciated contribution!

Originally, I had in my mind read-only approach as the main use case for the many cardinality. To enable easy access to filtered out entries. For example, have something like:

project = api.Project.get(id=123)
project.time_entries # return all linked Time Entries to the Project

But with the use-case of Tags, there will be the need also for being able to add/remove tags. Tags will be an especially special case because they are serialized as normal array/list for the time entries.

As I am thinking about how to approach this, I believe that the main work will go into implementing a special container that will encapsulate the mapped entries. There should be a general implementation that could be used for the read-only/filter out use-case and then for specific use-cases there would be extended containers that would allow mutability.

You could then specify for the mapping field with many cardinality, what Container should be used for the field. Something like:


class FilterContainer(AbstractContainer)
	...

class Project(api.TogglEntity):
	time_entries = field.MappingField(TimeEntry, cardinality=field.MappingField.MANY, container=FilterContainer) 

Mapped Container

It is a question on its own, what capabilities of this container should be. I think that it could be quiet similar (at least from an interface point of view) to the SetContainer. I would start with implementing a general immutable container, for the read-only use-case and then extend on that for the Tag's case.

Few things about the container:

  • It should receive the mapped_cls and the Entity's instance.
  • The mapped_field could be used as "reverse field"
  • When the entity is serialized to be saved the serialization should be delegated to the Container from the MappingField, but it should be also allowed to skip the serialization as some of these fields can be "virtual" and should not be sent to Toggl.

The general filter should then have all the information to retrieve the filtered information, it could look something like:

class FilterContainer:
	def __init__(self, mapped_cls, reverse_field, instance):
		self.entities = mapped_cls.objects.filter(**{reverse_field: instance.id})

MappingField

Mapping field then should mainly do work around constructing the Container, returning it to the user, handling serialization, parsing etc.

Sorry for such a long reply, but hopefully this give you some direction on how to approach this. Let me know if you have any questions, suggestions anything 😄

AuHau avatar Jan 27 '19 19:01 AuHau

Thanks for the reply! Initially I thought I was really going to need this many-many relationship for doing what I want with tags. But realizing how Tags are dealt with by Toggl itself, and that they are literally no more than an ID-Name pair means that that part can be pretty low on the list of priorities.

At least getting the read-only version working for e.g. the Project-TimeEntries relationship would still be very nice though. Is probably a better starting point for me to start looking into anyway 😄

sjvrijn avatar Jan 28 '19 21:01 sjvrijn