1package syntax
2
3import (
4 "errors"
5 "regexp"
6)
7
8var recordKeyRegex = regexp.MustCompile(`^[a-zA-Z0-9_~.:-]{1,512}$`)
9
10// String type which represents a syntaxtually valid RecordKey identifier, as could be included in an AT URI
11//
12// Always use [ParseRecordKey] instead of wrapping strings directly, especially when working with input.
13//
14// Syntax specification: https://atproto.com/specs/record-key
15type RecordKey string
16
17func ParseRecordKey(raw string) (RecordKey, error) {
18 if raw == "" {
19 return "", errors.New("expected record key, got empty string")
20 }
21 if len(raw) > 512 {
22 return "", errors.New("recordkey is too long (512 chars max)")
23 }
24 if raw == "" || raw == "." || raw == ".." {
25 return "", errors.New("recordkey can not be empty, '.', or '..'")
26 }
27 if !recordKeyRegex.MatchString(raw) {
28 return "", errors.New("recordkey syntax didn't validate via regex")
29 }
30 return RecordKey(raw), nil
31}
32
33func (r RecordKey) String() string {
34 return string(r)
35}
36
37func (r RecordKey) MarshalText() ([]byte, error) {
38 return []byte(r.String()), nil
39}
40
41func (r *RecordKey) UnmarshalText(text []byte) error {
42 rkey, err := ParseRecordKey(string(text))
43 if err != nil {
44 return err
45 }
46 *r = rkey
47 return nil
48}