]> git.notmuchmail.org Git - notmuch/blob - devel/schemata
search: Add stable queries to thread search results
[notmuch] / devel / schemata
1 This file describes the schemata used for notmuch's structured output
2 format (currently JSON and S-Expressions).
3
4 []'s indicate lists.  List items can be marked with a '?', meaning
5 they are optional; or a '*', meaning there can be zero or more of that
6 item.  {}'s indicate an object that maps from field identifiers to
7 values.  An object field marked '?' is optional.  |'s indicate
8 alternates (e.g., int|string means something can be an int or a
9 string).
10
11 For S-Expression output, lists are printed delimited by () instead of
12 []. Objects are printed as p-lists, i.e. lists where the keys and values
13 are interleaved. Keys are printed as keywords (symbols preceded by a
14 colon), e.g. (:id "123" :time 54321 :from "foobar"). Null is printed as
15 nil, true as t and false as nil.
16
17 This is version 2 of the structured output format.
18
19 Version history
20 ---------------
21
22 v1
23 - First versioned schema release.
24 - Added part.content-length and part.content-transfer-encoding fields.
25
26 v2
27 - Added the thread_summary.query field.
28
29 Common non-terminals
30 --------------------
31
32 # Number of seconds since the Epoch
33 unix_time = int
34
35 # Thread ID, sans "thread:"
36 threadid = string
37
38 # Message ID, sans "id:"
39 messageid = string
40
41 notmuch show schema
42 -------------------
43
44 # A top-level set of threads (do_show)
45 # Returned by notmuch show without a --part argument
46 thread_set = [thread*]
47
48 # Top-level messages in a thread (show_messages)
49 thread = [thread_node*]
50
51 # A message and its replies (show_messages)
52 thread_node = [
53     message|null,             # null if not matched and not --entire-thread
54     [thread_node*]            # children of message
55 ]
56
57 # A message (format_part_sprinter)
58 message = {
59     # (format_message_sprinter)
60     id:             messageid,
61     match:          bool,
62     filename:       string,
63     timestamp:      unix_time, # date header as unix time
64     date_relative:  string,   # user-friendly timestamp
65     tags:           [string*],
66
67     headers:        headers,
68     body?:          [part]    # omitted if --body=false
69 }
70
71 # A MIME part (format_part_sprinter)
72 part = {
73     id:             int|string, # part id (currently DFS part number)
74
75     encstatus?:     encstatus,
76     sigstatus?:     sigstatus,
77
78     content-type:   string,
79     content-id?:    string,
80     # if content-type starts with "multipart/":
81     content:        [part*],
82     # if content-type is "message/rfc822":
83     content:        [{headers: headers, body: [part]}],
84     # otherwise (leaf parts):
85     filename?:      string,
86     content-charset?: string,
87     # A leaf part's body content is optional, but may be included if
88     # it can be correctly encoded as a string.  Consumers should use
89     # this in preference to fetching the part content separately.
90     content?:       string,
91     # If a leaf part's body content is not included, the length of
92     # the encoded content (in bytes) may be given instead.
93     content-length?: int,
94     # If a leaf part's body content is not included, its transfer encoding
95     # may be given.  Using this and the encoded content length, it is
96     # possible for the consumer to estimate the decoded content length.
97     content-transfer-encoding?: string
98 }
99
100 # The headers of a message or part (format_headers_sprinter with reply = FALSE)
101 headers = {
102     Subject:        string,
103     From:           string,
104     To?:            string,
105     Cc?:            string,
106     Bcc?:           string,
107     Reply-To?:      string,
108     Date:           string
109 }
110
111 # Encryption status (format_part_sprinter)
112 encstatus = [{status: "good"|"bad"}]
113
114 # Signature status (format_part_sigstatus_sprinter)
115 sigstatus = [signature*]
116
117 signature = {
118     # (signature_status_to_string)
119     status:         "none"|"good"|"bad"|"error"|"unknown",
120     # if status is "good":
121     fingerprint?:   string,
122     created?:       unix_time,
123     expires?:       unix_time,
124     userid?:        string
125     # if status is not "good":
126     keyid?:         string
127     # if the signature has errors:
128     errors?:        int
129 }
130
131 notmuch search schema
132 ---------------------
133
134 # --output=summary
135 search_summary = [thread_summary*]
136
137 # --output=threads
138 search_threads = [threadid*]
139
140 # --output=messages
141 search_messages = [messageid*]
142
143 # --output=files
144 search_files = [string*]
145
146 # --output=tags
147 search_tags = [string*]
148
149 thread_summary = {
150     thread:         threadid,
151     timestamp:      unix_time,
152     date_relative:  string,   # user-friendly timestamp
153     matched:        int,      # number of matched messages
154     total:          int,      # total messages in thread
155     authors:        string,   # comma-separated names with | between
156                               # matched and unmatched
157     subject:        string,
158     tags:           [string*],
159
160     # Two stable query strings identifying exactly the matched and
161     # unmatched messages currently in this thread.  The messages
162     # matched by these queries will not change even if more messages
163     # arrive in the thread.  If there are no matched or unmatched
164     # messages, the corresponding query will be null (there is no
165     # query that matches nothing).  (Added in schema version 2.)
166     query:          [string|null, string|null],
167 }
168
169 notmuch reply schema
170 --------------------
171
172 reply = {
173     # The headers of the constructed reply
174     reply-headers: reply_headers,
175
176     # As in the show format (format_part_sprinter)
177     original: message
178 }
179
180 # Reply headers (format_headers_sprinter with reply = TRUE)
181 reply_headers = {
182     Subject:        string,
183     From:           string,
184     To?:            string,
185     Cc?:            string,
186     Bcc?:           string,
187     In-reply-to:    string,
188     References:     string
189 }