nats-io / nats-architecture-and-design

Architecture and Design Docs
Apache License 2.0
187 stars 20 forks source link

[update] ADR-6 add bucket and key naming conventions #48

Closed scottf closed 2 years ago

aricart commented 2 years ago

I was just looking at this, as I was updating the JavaScript implementation. The realization that I have on this is that we can validate the key names (currently in go/javascript it allows -, /, =, alpha, digits, and . so long as they are not a start or end character). Buckets are the same but . is not allowed anywhere.

const validKeyRe = /^[-/=.\w]+$/;
const validBucketRe = /^[-\w]+$/;

However quickly this becomes an issue because the number of characters that probably should be allowed is much larger (as Scott is pointing out). - So the quick realization is that the key encoding function (and there must be one), is really the correct strategy or unexpected errors will creep up, as key values from unknown sources are now subject to a runtime error.

This means that all keys should, split on "." in case they gave some compound key, extract the wildcards as they are, and encode all else, rejoining with a ".":

  function encodeKey(key: string): string {
    const chunks: string[] = [];
    for (const t of key.split(".")) {
      switch (t) {
        case ">":
        case "*":
          chunks.push(t);
          break;
        default:
          chunks.push(this.codec.key.encode(t));
          break;
      }
    }
    return chunks.join(".");
  }
ripienaar commented 2 years ago

Your . in the key regex needs to be escaped.

I specifically restricted these to maximise the possibility of being able to integrate with other tools.

ripienaar commented 2 years ago

I have this for encoding keys

func (j *jetStreamStorage) encodeKey(key string) (string, error) {
    res := []string{}
    for _, t := range strings.Split(key, ".") {
        if t == ">" || t == "*" {
            res = append(res, t)
            continue
        }

        et, err := j.encode([]byte(t))
        if err != nil {
            return "", err
        }

        res = append(res, string(et))
    }

    return strings.Join(res, "."), nil
}