Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Event Metadata #161

Open
bounoable opened this issue Sep 28, 2023 · 4 comments
Open

Event Metadata #161

bounoable opened this issue Sep 28, 2023 · 4 comments
Labels
draft enhancement New feature or request

Comments

@bounoable
Copy link
Contributor

Objective

To extend the event store's capabilities by allowing the storage of additional metadata for events and provide the necessary querying mechanisms to filter based on various metadata types.

Requirements

  1. Metadata Storage: Ability to associate and store metadata with events in the event store.
  2. Advanced Querying: Support filtering based on various metadata types, including:
    • Strings
    • Integers
    • Booleans
    • Arrays

Example Usage

1. Creating an Event with Metadata:

func createEventWithMetadata() {
  evt := event.New("<eventName>", "<eventData>",  event.Metadata(map[string]any{
    "field-a": "value-a",
    "field-b": []string{"value-b", "value-c"},
  }))

  evt.Metadata()["field-a"] == "value-a"
  evt.Metadata()["field-b"] == []string{"value-b", "value-c"}
}

2. Querying Events Based on Metadata:

func queryEventsByMetadata(store event.Store) {
  // Query by exact metadata value.
  events, errs, err := store.Query(context.TODO(), query.New(
    query.Metadata("field-a", "value-a"),
  ))

  // Query by exact metadata array values (element order matters).
  events, errs, err := store.Query(context.TODO(), query.New(
    query.Metadata("field-b", []string{"value-b", "value-c"}),
  ))

  // Query based on the presence of specific values within an array.
  // Either "value-a" OR "value-c" must be present.
  events, errs, err := store.Query(context.TODO(), query.New(
    query.Metadata("field-b", metadata.Contains("value-a", "value-c")),
  ))

  // Query based on the presence of specific values within an array.
  // Both "value-a" AND "value-c" must be present.
  events, errs, err := store.Query(context.TODO(), query.New(
    query.Metadata("field-b", metadata.ContainsAll("value-a", "value-c")),
  ))
}
@bounoable bounoable added enhancement New feature or request draft labels Sep 28, 2023
@bounoable
Copy link
Contributor Author

bounoable commented Oct 20, 2023

Maybe just add additional filters for querying event data.

Query by field

This can only work if the event data can be accessed by field (e.g. JSON). Event stores may or may not support this.

func queryEventsByData(store event.Store) {
  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("age", 28, 32), // either 28 or 32 years old
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("age", field.Gt(30), field.Lt(40)), // greater than 30, less than 40 years
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("name", "Bob", "Linda"),
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("name", field.Contains("ob")), // will find "Bob"
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("skills", []string{"programming", "walking"}),
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("skills", field.Contains("programming", "walking")),
  ))

  store.Query(context.TODO(), query.New(
    query.AggregateName("user"),
    query.Field("skills", field.ContainsAll("programming", "walking")),
  ))
}

@plunkettscott
Copy link

Also interested in this and would like to help if you've got any ideas on how this may fit into things. I think the metadata approach, while less generic, will likely be easier to support across all event stores in some way or another. My use case is being able to simply query by tenant in a multi-tenant application, which is easily solved with metadata.

@bounoable
Copy link
Contributor Author

Hi @plunkettscott, thank you for your interest in contributing to the project!

I agree with you that the metadata approach seems to be more portable implementation-wise, as each event store can decide for itself on how to store the metadata, and does not rely on the user-defined structure of the event data. My thought was that event metadata queries would likely not be much more complex to implement than queries for the entire event data, but after thinking a bit more about this, separating metadata from the main event data will probably be less confusing to users because they don't have to check for "supported features" when choosing an event store backend.

Regarding multi-tenant support, it's interesting that you brought this up as multiple people have been reaching out with similar inquiries. As you said, supporting this should be pretty easy using the metadata approach. Unfortunately, I hadn't had the time to work on this feature yet and will likely not be able to invest much time into this project until at least January.

That being said, I think the implementation of this feature should be pretty straight-forward, so if you're interested in implementing this, I would be happy to merge. Otherwise I will take a deeper look into this in the upcoming weeks.

@plunkettscott
Copy link

Yeah, I’ll take a look at this closer and see if I have some time to help out.

Another nice feature for multi-tenancy would be multi-tenancy support in the authentication package, but I’ll create a separate issue for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
draft enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants