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

Add Tags to RecordsWrite #642

Open
LiranCohen opened this issue Dec 5, 2023 · 5 comments
Open

Add Tags to RecordsWrite #642

LiranCohen opened this issue Dec 5, 2023 · 5 comments

Comments

@LiranCohen
Copy link
Member

Allowing a user to tag a record, and then query for records that match the tags.

export type Tags = {
  [tag: string]: Array<string | number | boolean>
};


export type RecordsWriteDescriptor = {
  interface: DwnInterfaceName.Records;
  method: DwnMethodName.Write;
  // ...
  tags: Tags;
};

Write:

{
  "schema": "https://schema",
  "protocol": "https://protocol",
  "protocolPath": "some/path",
  "tags": {
    "tag1": ["val1", "val2", "val3"],
    "tag2": [123, 456],
    "tag3": [true]
  }
}

Query:

{
  "filter": {
    "schema": "https://schema",
    "tags": {
       "tag1": "val2",
    }
  }
}
@csuwildcat
Copy link
Contributor

csuwildcat commented Dec 5, 2023

What about starting out with the Phase 1 structure/behavior below, then at some later date we can add top-level array passage of multiple objects to enable ORs later:

// Phase 1:

{
  tags: { // if tags is an object, its full set of keys and values are evaluated as exact match
    tag1 ["val1", "val2"], // Must have 'tag1' with both 'val1' and 'val2'
    tag2: [123] // Must also have 'tag2' and a value '123'
  }
}

// Phase 2:

{
  tags: [ // allow tags to be an array, and if it's an array, each member is an OR
    { // every object's full set of keys and values is evaluated as exact match
      tag1 ["val1", "val2"], // Must have 'tag1' with both 'val1' and 'val2'
      tag2: [123] // Must also have 'tag2' value '123'
    },
    { // if the first matching object misses, this second object would be tried
      tag3: [true] // Must have 'tag3' and be 'true'
    }
  ]
}

@csuwildcat
Copy link
Contributor

What I liked about the proposal above is that 1) the matcher objects retain the same behavior, 2) the only future change is to make tags polymorphic but bound to OR, and 3) at no point do we introduce any DSL strings, the whole thing remains an object literal syntax that seems rather intuitive if you know that a top-level array = OR and value arrays = AND.

@LiranCohen
Copy link
Member Author

@csuwildcat interesting with the array of tag objects like that for the queries to represent both AND and OR.

Our current typing/representation of filters (although not being used) would read the array as an OR, have to think about what that looks like in the implementation.

Worst case scenario to get this feature in sooner rather than later would you be opposed to your Phase 1 + 2 being the Phase 2 and Phase 1 being a single match?

@csuwildcat
Copy link
Contributor

Single match is fine, I suppose we can always make that polymorphic too, given the behavior is rather simple. That would be effectively 3 simple things to remember about the structure to account for the vast majority of queries (literally every one I could think of outside of inner-string comparisons, which is a whole different beast I don't want to touch).

@thehenrytsai
Copy link
Member

My Phase 1 is sooo puny compared to all yours:

"tags": {
    "tag1": ["val1", "val2", "val3"]; // one and only property, { } container is only there for extensibility purposes in phase 50
  }

LiranCohen added a commit that referenced this issue Apr 8, 2024
This is a first pass at adding the functionality for `tags` within
records as mentioned here
#642.

There will be subsequent PRs for any protocol specific enforcement.


```typescript
{
    published : true,
    schema    : 'post',
    tags      : {
        someString : 'some-value',
        someStringArray : ['some-value1', 'some-value2'],
        someNumber : 54566975,
        someNumberArray : [ 1, 2, 3, 4, 5 ],
        someBoolean: true,
        someOtherBoolean: false
    }
}
```

### Filtering
A filter for a tag is treated as an Equal filter. If any of the values
within the tag array match the filter, the record matches.
#### Exact Match

```typescript
{
  filter : {
    schema : 'post',
    tags   : {
      someString: 'some-value'
    }
  }
}
```

#### Range Filters
```typescript
{
  filter : {
    schema : 'post',
    tags   : {
      someString: { gte: 'b', lt: 'c' }, // returns anything that starts with `b`
      someNumber: { gt: 0, lt: 10 }, // (exclusive) returns anything greater than 0 but less than 10 
      someStringArray: { gte: 'b', lt: 'c' }, // returns anything that starts with `b` within the array
      someNumberArray: { gt: 0, lt: 10 } // (exclusive) returns anything greater than 0 but less than 10 within the array 
    }
  }
}
```
#### Prefix Filters
```typescript
{
  filter : {
    schema : 'post',
    tags   : {
      someString: { prefix: 'some' }, // returns anything that starts with the string prefix `some`
      someStringArray: { prefix: 'some' }, // returns anything that starts with the string prefix `some` within the array
    }
  }
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants