2 This file is part of notmuch.
4 Notmuch is free software: you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation, either version 3 of the License, or (at your
7 option) any later version.
9 Notmuch is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License
15 along with notmuch. If not, see <https://www.gnu.org/licenses/>.
17 Copyright 2010 Sebastian Spaeth <Sebastian@SSpaeth.de>
20 from ctypes import c_char_p, c_uint, POINTER, byref
21 from .globals import (
35 from .threads import Threads
36 from .messages import Messages
40 """Represents a search query on an opened :class:`Database`.
42 A query selects and filters a subset of messages from the notmuch
43 database we derive from.
45 :class:`Query` provides an instance attribute :attr:`sort`, which
46 contains the sort order (if specified via :meth:`set_sort`) or
49 Any function in this class may throw an :exc:`NotInitializedError`
50 in case the underlying query object was not set up correctly.
52 .. note:: Do remember that as soon as we tear down this object,
53 all underlying derived objects such as threads,
54 messages, tags etc will be freed by the underlying library
55 as well. Accessing these objects will lead to segfaults and
56 other unexpected behavior. See above for more details.
59 SORT = Enum(['OLDEST_FIRST', 'NEWEST_FIRST', 'MESSAGE_ID', 'UNSORTED'])
60 """Constants: Sort order in which to return results"""
62 def __init__(self, db, querystr):
64 :param db: An open database which we derive the Query from.
65 :type db: :class:`Database`
66 :param querystr: The query string for the message.
67 :type querystr: utf-8 encoded str or unicode
72 self.create(db, querystr)
74 def _assert_query_is_initialized(self):
75 """Raises :exc:`NotInitializedError` if self._query is `None`"""
77 raise NotInitializedError()
79 """notmuch_query_create"""
80 _create = nmlib.notmuch_query_create
81 _create.argtypes = [NotmuchDatabaseP, c_char_p]
82 _create.restype = NotmuchQueryP
84 def create(self, db, querystr):
85 """Creates a new query derived from a Database
87 This function is utilized by __init__() and usually does not need to
90 :param db: Database to create the query from.
91 :type db: :class:`Database`
92 :param querystr: The query string
93 :type querystr: utf-8 encoded str or unicode
95 :exc:`NullPointerError` if the query creation failed
96 (e.g. too little memory).
97 :exc:`NotInitializedError` if the underlying db was not
100 db._assert_db_is_initialized()
101 # create reference to parent db to keep it alive
103 # create query, return None if too little mem available
104 query_p = Query._create(db._db, _str(querystr))
106 raise NullPointerError
107 self._query = query_p
109 _set_sort = nmlib.notmuch_query_set_sort
110 _set_sort.argtypes = [NotmuchQueryP, c_uint]
111 _set_sort.argtypes = None
113 def set_sort(self, sort):
114 """Set the sort order future results will be delivered in
116 :param sort: Sort order (see :attr:`Query.SORT`)
118 self._assert_query_is_initialized()
120 self._set_sort(self._query, sort)
122 _exclude_tag = nmlib.notmuch_query_add_tag_exclude
123 _exclude_tag.argtypes = [NotmuchQueryP, c_char_p]
124 _exclude_tag.resttype = None
126 def exclude_tag(self, tagname):
127 """Add a tag that will be excluded from the query results by default.
129 This exclusion will be overridden if this tag appears explicitly in the
132 :param tagname: Name of the tag to be excluded
134 self._assert_query_is_initialized()
135 self._exclude_tag(self._query, _str(tagname))
137 """notmuch_query_search_threads"""
138 _search_threads = nmlib.notmuch_query_search_threads
139 _search_threads.argtypes = [NotmuchQueryP, POINTER(NotmuchThreadsP)]
140 _search_threads.restype = c_uint
142 def search_threads(self):
143 """Execute a query for threads
145 Execute a query for threads, returning a :class:`Threads` iterator.
146 The returned threads are owned by the query and as such, will only be
147 valid until the Query is deleted.
149 The method sets :attr:`Message.FLAG`\.MATCH for those messages that
150 match the query. The method :meth:`Message.get_flag` allows us
151 to get the value of this flag.
153 :returns: :class:`Threads`
154 :raises: :exc:`NullPointerError` if search_threads failed
156 self._assert_query_is_initialized()
157 threads_p = NotmuchThreadsP() # == NULL
158 status = Query._search_threads(self._query, byref(threads_p))
160 raise NotmuchError(status)
163 raise NullPointerError
164 return Threads(threads_p, self)
166 """notmuch_query_search_messages_st"""
167 _search_messages = nmlib.notmuch_query_search_messages
168 _search_messages.argtypes = [NotmuchQueryP, POINTER(NotmuchMessagesP)]
169 _search_messages.restype = c_uint
171 def search_messages(self):
172 """Filter messages according to the query and return
173 :class:`Messages` in the defined sort order
175 :returns: :class:`Messages`
176 :raises: :exc:`NullPointerError` if search_messages failed
178 self._assert_query_is_initialized()
179 msgs_p = NotmuchMessagesP() # == NULL
180 status = Query._search_messages(self._query, byref(msgs_p))
182 raise NotmuchError(status)
185 raise NullPointerError
186 return Messages(msgs_p, self)
188 _count_messages = nmlib.notmuch_query_count_messages
189 _count_messages.argtypes = [NotmuchQueryP, POINTER(c_uint)]
190 _count_messages.restype = c_uint
192 def count_messages(self):
194 This function performs a search and returns Xapian's best
195 guess as to the number of matching messages.
197 :returns: the estimated number of messages matching this query
200 self._assert_query_is_initialized()
202 status = Query._count_messages(self._query, byref(count))
204 raise NotmuchError(status)
207 _count_threads = nmlib.notmuch_query_count_threads
208 _count_threads.argtypes = [NotmuchQueryP, POINTER(c_uint)]
209 _count_threads.restype = c_uint
211 def count_threads(self):
213 This function performs a search and returns the number of
214 unique thread IDs in the matching messages. This is the same
215 as number of threads matching a search.
217 Note that this is a significantly heavier operation than
218 meth:`Query.count_messages`.
220 :returns: the number of threads returned by this query
223 self._assert_query_is_initialized()
225 status = Query._count_threads(self._query, byref(count))
227 raise NotmuchError(status)
230 _destroy = nmlib.notmuch_query_destroy
231 _destroy.argtypes = [NotmuchQueryP]
232 _destroy.restype = None
235 """Close and free the Query"""
237 self._destroy(self._query)