We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Database.query buggy with Time
Database.query works different using the Time attribute than VSO does.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `sunpy/database/attrs.py`
Content:
```
1 # Author: Simon Liedtke <liedtke.simon@googlemail.com>
2 #
3 # This module was developed with funding provided by
4 # the Google Summer of Code (2013).
5 
6 from __future__ import absolute_import
7 
8 from sqlalchemy import or_, and_, not_
9 from astropy.units import Unit, nm, equivalencies
10 
11 from sunpy.time import parse_time
12 from sunpy.net.vso import attrs as vso_attrs
13 from sunpy.net.attr import AttrWalker, Attr, ValueAttr, AttrAnd, AttrOr
14 from sunpy.database.tables import DatabaseEntry, Tag as TableTag,\
15     FitsHeaderEntry as TableFitsHeaderEntry
16 
17 __all__ = [
18     'Starred', 'Tag', 'Path', 'DownloadTime', 'FitsHeaderEntry', 'walker']
19 
20 
21 class _BooleanAttr(object):
22     def __init__(self, value, make):
23         self.value = bool(value)
24         self.make = make
25 
26     def __and__(self, other):
27         if not isinstance(other, self.make):
28             return AttrAnd([self, other])
29         attr = self.make()
30         attr.value = self.value and other.value
31         return attr
32 
33     def __or__(self, other):
34         if not isinstance(other, self.make):
35             return AttrOr([self, other])
36         attr = self.make()
37         attr.value = self.value or other.value
38         return attr
39 
40     def __nonzero__(self):
41         return self.value
42 
43     def __invert__(self):
44         attr = self.make()
45         attr.value = not self.value
46         return attr
47 
48     def __eq__(self, other):
49         return isinstance(other, self.make) and self.value == other.value
50 
51     def collides(self, other):  # pragma: no cover
52         return False
53 
54     def __repr__(self):
55         return '<{0}{1}()>'.format(
56             '~' if not self.value else '', self.__class__.__name__)
57 
58 
59 class Starred(_BooleanAttr, Attr):
60     def __init__(self):
61         _BooleanAttr.__init__(self, True, self.__class__)
62 
63 
64 class Tag(Attr):
65     def __init__(self, tagname):
66         self.tagname = tagname
67         self.inverted = False
68 
69     def __invert__(self):
70         tag = self.__class__(self.tagname)
71         tag.inverted = True
72         return tag
73 
74     def collides(self, other):  # pragma: no cover
75         return False
76 
77     def __repr__(self):
78         return '<{0}Tag({1!r})>'.format(
79             '~' if self.inverted else '', self.tagname)
80 
81 
82 class Path(Attr):
83     def __init__(self, value):
84         self.value = value
85         self.inverted = False
86 
87     def __invert__(self):
88         path = self.__class__(self.value)
89         path.inverted = True
90         return path
91 
92     def collides(self, other):  # pragma: no cover
93         return isinstance(other, self.__class__)
94 
95     def __repr__(self):
96         return '<{0}Path({1!r})>'.format(
97             '~' if self.inverted else '', self.value)
98 
99 
100 # TODO: support excluding ranges as soon as
101 # vso_attrs._Range.__xor__ is fixed / renamed
102 class DownloadTime(Attr, vso_attrs._Range):
103     def __init__(self, start, end):
104         self.start = parse_time(start)
105         self.end = parse_time(end)
106         self.inverted = False
107         vso_attrs._Range.__init__(self, start, end, self.__class__)
108 
109     def __invert__(self):
110         download_time = self.__class__(self.start, self.end)
111         download_time.inverted = True
112         return download_time
113 
114     def collides(self, other):  # pragma: no cover
115         return isinstance(other, self.__class__)
116 
117     def __repr__(self):
118         return '<{0}DownloadTime({1!r}, {2!r})>'.format(
119             '~' if self.inverted else '', self.start, self.end)
120 
121 
122 class FitsHeaderEntry(Attr):
123     def __init__(self, key, value):
124         self.key = key
125         self.value = value
126         self.inverted = False
127 
128     def __invert__(self):
129         entry = self.__class__(self.key, self.value)
130         entry.inverted = True
131         return entry
132 
133     def collides(self, other):  # pragma: no cover
134         return False
135 
136     def __repr__(self):
137         return '<{0}FitsHeaderEntry({1!r}, {2!r})>'.format(
138             '~' if self.inverted else '', self.key, self.value)
139 
140 
141 walker = AttrWalker()
142 
143 
144 @walker.add_creator(AttrOr)
145 def _create(wlk, root, session):
146     entries = set()
147     for attr in root.attrs:
148         # make sure to add only new entries to the set to avoid duplicates
149         entries.update(set(wlk.create(attr, session)) - entries)
150     return list(entries)
151 
152 
153 @walker.add_creator(AttrAnd)
154 def _create(wlk, root, session):
155     entries = [set(wlk.create(attr, session)) for attr in root.attrs]
156     return list(set.intersection(*entries))
157 
158 
159 @walker.add_creator(ValueAttr)
160 def _create(wlk, root, session):
161     query = session.query(DatabaseEntry)
162     for key, value in root.attrs.iteritems():
163         typ = key[0]
164         if typ == 'tag':
165             criterion = TableTag.name.in_([value])
166             # `key[1]` is here the `inverted` attribute of the tag. That means
167             # that if it is True, the given tag must not be included in the
168             # resulting entries.
169             if key[1]:
170                 query = query.filter(~DatabaseEntry.tags.any(criterion))
171             else:
172                 query = query.filter(DatabaseEntry.tags.any(criterion))
173         elif typ == 'fitsheaderentry':
174             key, val, inverted = value
175             key_criterion = TableFitsHeaderEntry.key == key
176             value_criterion = TableFitsHeaderEntry.value == val
177             if inverted:
178                 query = query.filter(not_(and_(
179                     DatabaseEntry.fits_header_entries.any(key_criterion),
180                     DatabaseEntry.fits_header_entries.any(value_criterion))))
181             else:
182                 query = query.filter(and_(
183                     DatabaseEntry.fits_header_entries.any(key_criterion),
184                     DatabaseEntry.fits_header_entries.any(value_criterion)))
185         elif typ == 'download time':
186             start, end, inverted = value
187             if inverted:
188                 query = query.filter(
189                     ~DatabaseEntry.download_time.between(start, end))
190             else:
191                 query = query.filter(
192                     DatabaseEntry.download_time.between(start, end))
193         elif typ == 'path':
194             path, inverted = value
195             if inverted:
196                 query = query.filter(or_(
197                     DatabaseEntry.path != path, DatabaseEntry.path == None))
198             else:
199                 query = query.filter(DatabaseEntry.path == path)
200         elif typ == 'wave':
201             min_, max_, unit = value
202             waveunit = Unit(unit)
203             # convert min_ and max_ to nm from the unit `waveunit`
204             wavemin = waveunit.to(nm, min_, equivalencies.spectral())
205             wavemax = waveunit.to(nm, max_, equivalencies.spectral())
206             query = query.filter(and_(
207                 DatabaseEntry.wavemin >= wavemin,
208                 DatabaseEntry.wavemax <= wavemax))
209         elif typ == 'time':
210             start, end, near = value
211             query = query.filter(and_(
212                 DatabaseEntry.observation_time_start >= start,
213                 DatabaseEntry.observation_time_end <= end))
214         else:
215             query = query.filter_by(**{typ: value})
216     return query.all()
217 
218 
219 @walker.add_converter(Tag)
220 def _convert(attr):
221     return ValueAttr({('tag', attr.inverted): attr.tagname})
222 
223 
224 @walker.add_converter(Starred)
225 def _convert(attr):
226     return ValueAttr({('starred', ): attr.value})
227 
228 
229 @walker.add_converter(Path)
230 def _convert(attr):
231     return ValueAttr({('path', ): (attr.value, attr.inverted)})
232 
233 
234 @walker.add_converter(DownloadTime)
235 def _convert(attr):
236     return ValueAttr({
237         ('download time', ): (attr.start, attr.end, attr.inverted)})
238 
239 
240 @walker.add_converter(FitsHeaderEntry)
241 def _convert(attr):
242     return ValueAttr(
243         {('fitsheaderentry', ): (attr.key, attr.value, attr.inverted)})
244 
245 
246 @walker.add_converter(vso_attrs._VSOSimpleAttr)
247 def _convert(attr):
248     return ValueAttr({(attr.__class__.__name__.lower(), ): attr.value})
249 
250 
251 @walker.add_converter(vso_attrs.Wave)
252 def _convert(attr):
253     return ValueAttr({('wave', ): (attr.min, attr.max, attr.unit)})
254 
255 
256 @walker.add_converter(vso_attrs.Time)
257 def _convert(attr):
258     return ValueAttr({('time', ): (attr.start, attr.end, attr.near)})
259
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/sunpy/database/attrs.py b/sunpy/database/attrs.py
--- a/sunpy/database/attrs.py
+++ b/sunpy/database/attrs.py
@@ -209,8 +209,8 @@
         elif typ == 'time':
             start, end, near = value
             query = query.filter(and_(
-                DatabaseEntry.observation_time_start >= start,
-                DatabaseEntry.observation_time_end <= end))
+                DatabaseEntry.observation_time_start < end,
+                DatabaseEntry.observation_time_end > start))
         else:
             query = query.filter_by(**{typ: value})
     return query.all()

{"golden_diff": "diff --git a/sunpy/database/attrs.py b/sunpy/database/attrs.py\n--- a/sunpy/database/attrs.py\n+++ b/sunpy/database/attrs.py\n@@ -209,8 +209,8 @@\n         elif typ == 'time':\n             start, end, near = value\n             query = query.filter(and_(\n-                DatabaseEntry.observation_time_start >= start,\n-                DatabaseEntry.observation_time_end <= end))\n+                DatabaseEntry.observation_time_start < end,\n+                DatabaseEntry.observation_time_end > start))\n         else:\n             query = query.filter_by(**{typ: value})\n     return query.all()\n", "issue": "Database.query buggy with Time\nDatabase.query works different using the Time attribute than VSO does.\n\n", "before_files": [{"content": "# Author: Simon Liedtke <liedtke.simon@googlemail.com>\n#\n# This module was developed with funding provided by\n# the Google Summer of Code (2013).\n\nfrom __future__ import absolute_import\n\nfrom sqlalchemy import or_, and_, not_\nfrom astropy.units import Unit, nm, equivalencies\n\nfrom sunpy.time import parse_time\nfrom sunpy.net.vso import attrs as vso_attrs\nfrom sunpy.net.attr import AttrWalker, Attr, ValueAttr, AttrAnd, AttrOr\nfrom sunpy.database.tables import DatabaseEntry, Tag as TableTag,\\\n    FitsHeaderEntry as TableFitsHeaderEntry\n\n__all__ = [\n    'Starred', 'Tag', 'Path', 'DownloadTime', 'FitsHeaderEntry', 'walker']\n\n\nclass _BooleanAttr(object):\n    def __init__(self, value, make):\n        self.value = bool(value)\n        self.make = make\n\n    def __and__(self, other):\n        if not isinstance(other, self.make):\n            return AttrAnd([self, other])\n        attr = self.make()\n        attr.value = self.value and other.value\n        return attr\n\n    def __or__(self, other):\n        if not isinstance(other, self.make):\n            return AttrOr([self, other])\n        attr = self.make()\n        attr.value = self.value or other.value\n        return attr\n\n    def __nonzero__(self):\n        return self.value\n\n    def __invert__(self):\n        attr = self.make()\n        attr.value = not self.value\n        return attr\n\n    def __eq__(self, other):\n        return isinstance(other, self.make) and self.value == other.value\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}{1}()>'.format(\n            '~' if not self.value else '', self.__class__.__name__)\n\n\nclass Starred(_BooleanAttr, Attr):\n    def __init__(self):\n        _BooleanAttr.__init__(self, True, self.__class__)\n\n\nclass Tag(Attr):\n    def __init__(self, tagname):\n        self.tagname = tagname\n        self.inverted = False\n\n    def __invert__(self):\n        tag = self.__class__(self.tagname)\n        tag.inverted = True\n        return tag\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}Tag({1!r})>'.format(\n            '~' if self.inverted else '', self.tagname)\n\n\nclass Path(Attr):\n    def __init__(self, value):\n        self.value = value\n        self.inverted = False\n\n    def __invert__(self):\n        path = self.__class__(self.value)\n        path.inverted = True\n        return path\n\n    def collides(self, other):  # pragma: no cover\n        return isinstance(other, self.__class__)\n\n    def __repr__(self):\n        return '<{0}Path({1!r})>'.format(\n            '~' if self.inverted else '', self.value)\n\n\n# TODO: support excluding ranges as soon as\n# vso_attrs._Range.__xor__ is fixed / renamed\nclass DownloadTime(Attr, vso_attrs._Range):\n    def __init__(self, start, end):\n        self.start = parse_time(start)\n        self.end = parse_time(end)\n        self.inverted = False\n        vso_attrs._Range.__init__(self, start, end, self.__class__)\n\n    def __invert__(self):\n        download_time = self.__class__(self.start, self.end)\n        download_time.inverted = True\n        return download_time\n\n    def collides(self, other):  # pragma: no cover\n        return isinstance(other, self.__class__)\n\n    def __repr__(self):\n        return '<{0}DownloadTime({1!r}, {2!r})>'.format(\n            '~' if self.inverted else '', self.start, self.end)\n\n\nclass FitsHeaderEntry(Attr):\n    def __init__(self, key, value):\n        self.key = key\n        self.value = value\n        self.inverted = False\n\n    def __invert__(self):\n        entry = self.__class__(self.key, self.value)\n        entry.inverted = True\n        return entry\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}FitsHeaderEntry({1!r}, {2!r})>'.format(\n            '~' if self.inverted else '', self.key, self.value)\n\n\nwalker = AttrWalker()\n\n\n@walker.add_creator(AttrOr)\ndef _create(wlk, root, session):\n    entries = set()\n    for attr in root.attrs:\n        # make sure to add only new entries to the set to avoid duplicates\n        entries.update(set(wlk.create(attr, session)) - entries)\n    return list(entries)\n\n\n@walker.add_creator(AttrAnd)\ndef _create(wlk, root, session):\n    entries = [set(wlk.create(attr, session)) for attr in root.attrs]\n    return list(set.intersection(*entries))\n\n\n@walker.add_creator(ValueAttr)\ndef _create(wlk, root, session):\n    query = session.query(DatabaseEntry)\n    for key, value in root.attrs.iteritems():\n        typ = key[0]\n        if typ == 'tag':\n            criterion = TableTag.name.in_([value])\n            # `key[1]` is here the `inverted` attribute of the tag. That means\n            # that if it is True, the given tag must not be included in the\n            # resulting entries.\n            if key[1]:\n                query = query.filter(~DatabaseEntry.tags.any(criterion))\n            else:\n                query = query.filter(DatabaseEntry.tags.any(criterion))\n        elif typ == 'fitsheaderentry':\n            key, val, inverted = value\n            key_criterion = TableFitsHeaderEntry.key == key\n            value_criterion = TableFitsHeaderEntry.value == val\n            if inverted:\n                query = query.filter(not_(and_(\n                    DatabaseEntry.fits_header_entries.any(key_criterion),\n                    DatabaseEntry.fits_header_entries.any(value_criterion))))\n            else:\n                query = query.filter(and_(\n                    DatabaseEntry.fits_header_entries.any(key_criterion),\n                    DatabaseEntry.fits_header_entries.any(value_criterion)))\n        elif typ == 'download time':\n            start, end, inverted = value\n            if inverted:\n                query = query.filter(\n                    ~DatabaseEntry.download_time.between(start, end))\n            else:\n                query = query.filter(\n                    DatabaseEntry.download_time.between(start, end))\n        elif typ == 'path':\n            path, inverted = value\n            if inverted:\n                query = query.filter(or_(\n                    DatabaseEntry.path != path, DatabaseEntry.path == None))\n            else:\n                query = query.filter(DatabaseEntry.path == path)\n        elif typ == 'wave':\n            min_, max_, unit = value\n            waveunit = Unit(unit)\n            # convert min_ and max_ to nm from the unit `waveunit`\n            wavemin = waveunit.to(nm, min_, equivalencies.spectral())\n            wavemax = waveunit.to(nm, max_, equivalencies.spectral())\n            query = query.filter(and_(\n                DatabaseEntry.wavemin >= wavemin,\n                DatabaseEntry.wavemax <= wavemax))\n        elif typ == 'time':\n            start, end, near = value\n            query = query.filter(and_(\n                DatabaseEntry.observation_time_start >= start,\n                DatabaseEntry.observation_time_end <= end))\n        else:\n            query = query.filter_by(**{typ: value})\n    return query.all()\n\n\n@walker.add_converter(Tag)\ndef _convert(attr):\n    return ValueAttr({('tag', attr.inverted): attr.tagname})\n\n\n@walker.add_converter(Starred)\ndef _convert(attr):\n    return ValueAttr({('starred', ): attr.value})\n\n\n@walker.add_converter(Path)\ndef _convert(attr):\n    return ValueAttr({('path', ): (attr.value, attr.inverted)})\n\n\n@walker.add_converter(DownloadTime)\ndef _convert(attr):\n    return ValueAttr({\n        ('download time', ): (attr.start, attr.end, attr.inverted)})\n\n\n@walker.add_converter(FitsHeaderEntry)\ndef _convert(attr):\n    return ValueAttr(\n        {('fitsheaderentry', ): (attr.key, attr.value, attr.inverted)})\n\n\n@walker.add_converter(vso_attrs._VSOSimpleAttr)\ndef _convert(attr):\n    return ValueAttr({(attr.__class__.__name__.lower(), ): attr.value})\n\n\n@walker.add_converter(vso_attrs.Wave)\ndef _convert(attr):\n    return ValueAttr({('wave', ): (attr.min, attr.max, attr.unit)})\n\n\n@walker.add_converter(vso_attrs.Time)\ndef _convert(attr):\n    return ValueAttr({('time', ): (attr.start, attr.end, attr.near)})\n", "path": "sunpy/database/attrs.py"}], "after_files": [{"content": "# Author: Simon Liedtke <liedtke.simon@googlemail.com>\n#\n# This module was developed with funding provided by\n# the Google Summer of Code (2013).\n\nfrom __future__ import absolute_import\n\nfrom sqlalchemy import or_, and_, not_\nfrom astropy.units import Unit, nm, equivalencies\n\nfrom sunpy.time import parse_time\nfrom sunpy.net.vso import attrs as vso_attrs\nfrom sunpy.net.attr import AttrWalker, Attr, ValueAttr, AttrAnd, AttrOr\nfrom sunpy.database.tables import DatabaseEntry, Tag as TableTag,\\\n    FitsHeaderEntry as TableFitsHeaderEntry\n\n__all__ = [\n    'Starred', 'Tag', 'Path', 'DownloadTime', 'FitsHeaderEntry', 'walker']\n\n\nclass _BooleanAttr(object):\n    def __init__(self, value, make):\n        self.value = bool(value)\n        self.make = make\n\n    def __and__(self, other):\n        if not isinstance(other, self.make):\n            return AttrAnd([self, other])\n        attr = self.make()\n        attr.value = self.value and other.value\n        return attr\n\n    def __or__(self, other):\n        if not isinstance(other, self.make):\n            return AttrOr([self, other])\n        attr = self.make()\n        attr.value = self.value or other.value\n        return attr\n\n    def __nonzero__(self):\n        return self.value\n\n    def __invert__(self):\n        attr = self.make()\n        attr.value = not self.value\n        return attr\n\n    def __eq__(self, other):\n        return isinstance(other, self.make) and self.value == other.value\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}{1}()>'.format(\n            '~' if not self.value else '', self.__class__.__name__)\n\n\nclass Starred(_BooleanAttr, Attr):\n    def __init__(self):\n        _BooleanAttr.__init__(self, True, self.__class__)\n\n\nclass Tag(Attr):\n    def __init__(self, tagname):\n        self.tagname = tagname\n        self.inverted = False\n\n    def __invert__(self):\n        tag = self.__class__(self.tagname)\n        tag.inverted = True\n        return tag\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}Tag({1!r})>'.format(\n            '~' if self.inverted else '', self.tagname)\n\n\nclass Path(Attr):\n    def __init__(self, value):\n        self.value = value\n        self.inverted = False\n\n    def __invert__(self):\n        path = self.__class__(self.value)\n        path.inverted = True\n        return path\n\n    def collides(self, other):  # pragma: no cover\n        return isinstance(other, self.__class__)\n\n    def __repr__(self):\n        return '<{0}Path({1!r})>'.format(\n            '~' if self.inverted else '', self.value)\n\n\n# TODO: support excluding ranges as soon as\n# vso_attrs._Range.__xor__ is fixed / renamed\nclass DownloadTime(Attr, vso_attrs._Range):\n    def __init__(self, start, end):\n        self.start = parse_time(start)\n        self.end = parse_time(end)\n        self.inverted = False\n        vso_attrs._Range.__init__(self, start, end, self.__class__)\n\n    def __invert__(self):\n        download_time = self.__class__(self.start, self.end)\n        download_time.inverted = True\n        return download_time\n\n    def collides(self, other):  # pragma: no cover\n        return isinstance(other, self.__class__)\n\n    def __repr__(self):\n        return '<{0}DownloadTime({1!r}, {2!r})>'.format(\n            '~' if self.inverted else '', self.start, self.end)\n\n\nclass FitsHeaderEntry(Attr):\n    def __init__(self, key, value):\n        self.key = key\n        self.value = value\n        self.inverted = False\n\n    def __invert__(self):\n        entry = self.__class__(self.key, self.value)\n        entry.inverted = True\n        return entry\n\n    def collides(self, other):  # pragma: no cover\n        return False\n\n    def __repr__(self):\n        return '<{0}FitsHeaderEntry({1!r}, {2!r})>'.format(\n            '~' if self.inverted else '', self.key, self.value)\n\n\nwalker = AttrWalker()\n\n\n@walker.add_creator(AttrOr)\ndef _create(wlk, root, session):\n    entries = set()\n    for attr in root.attrs:\n        # make sure to add only new entries to the set to avoid duplicates\n        entries.update(set(wlk.create(attr, session)) - entries)\n    return list(entries)\n\n\n@walker.add_creator(AttrAnd)\ndef _create(wlk, root, session):\n    entries = [set(wlk.create(attr, session)) for attr in root.attrs]\n    return list(set.intersection(*entries))\n\n\n@walker.add_creator(ValueAttr)\ndef _create(wlk, root, session):\n    query = session.query(DatabaseEntry)\n    for key, value in root.attrs.iteritems():\n        typ = key[0]\n        if typ == 'tag':\n            criterion = TableTag.name.in_([value])\n            # `key[1]` is here the `inverted` attribute of the tag. That means\n            # that if it is True, the given tag must not be included in the\n            # resulting entries.\n            if key[1]:\n                query = query.filter(~DatabaseEntry.tags.any(criterion))\n            else:\n                query = query.filter(DatabaseEntry.tags.any(criterion))\n        elif typ == 'fitsheaderentry':\n            key, val, inverted = value\n            key_criterion = TableFitsHeaderEntry.key == key\n            value_criterion = TableFitsHeaderEntry.value == val\n            if inverted:\n                query = query.filter(not_(and_(\n                    DatabaseEntry.fits_header_entries.any(key_criterion),\n                    DatabaseEntry.fits_header_entries.any(value_criterion))))\n            else:\n                query = query.filter(and_(\n                    DatabaseEntry.fits_header_entries.any(key_criterion),\n                    DatabaseEntry.fits_header_entries.any(value_criterion)))\n        elif typ == 'download time':\n            start, end, inverted = value\n            if inverted:\n                query = query.filter(\n                    ~DatabaseEntry.download_time.between(start, end))\n            else:\n                query = query.filter(\n                    DatabaseEntry.download_time.between(start, end))\n        elif typ == 'path':\n            path, inverted = value\n            if inverted:\n                query = query.filter(or_(\n                    DatabaseEntry.path != path, DatabaseEntry.path == None))\n            else:\n                query = query.filter(DatabaseEntry.path == path)\n        elif typ == 'wave':\n            min_, max_, unit = value\n            waveunit = Unit(unit)\n            # convert min_ and max_ to nm from the unit `waveunit`\n            wavemin = waveunit.to(nm, min_, equivalencies.spectral())\n            wavemax = waveunit.to(nm, max_, equivalencies.spectral())\n            query = query.filter(and_(\n                DatabaseEntry.wavemin >= wavemin,\n                DatabaseEntry.wavemax <= wavemax))\n        elif typ == 'time':\n            start, end, near = value\n            query = query.filter(and_(\n                DatabaseEntry.observation_time_start < end,\n                DatabaseEntry.observation_time_end > start))\n        else:\n            query = query.filter_by(**{typ: value})\n    return query.all()\n\n\n@walker.add_converter(Tag)\ndef _convert(attr):\n    return ValueAttr({('tag', attr.inverted): attr.tagname})\n\n\n@walker.add_converter(Starred)\ndef _convert(attr):\n    return ValueAttr({('starred', ): attr.value})\n\n\n@walker.add_converter(Path)\ndef _convert(attr):\n    return ValueAttr({('path', ): (attr.value, attr.inverted)})\n\n\n@walker.add_converter(DownloadTime)\ndef _convert(attr):\n    return ValueAttr({\n        ('download time', ): (attr.start, attr.end, attr.inverted)})\n\n\n@walker.add_converter(FitsHeaderEntry)\ndef _convert(attr):\n    return ValueAttr(\n        {('fitsheaderentry', ): (attr.key, attr.value, attr.inverted)})\n\n\n@walker.add_converter(vso_attrs._VSOSimpleAttr)\ndef _convert(attr):\n    return ValueAttr({(attr.__class__.__name__.lower(), ): attr.value})\n\n\n@walker.add_converter(vso_attrs.Wave)\ndef _convert(attr):\n    return ValueAttr({('wave', ): (attr.min, attr.max, attr.unit)})\n\n\n@walker.add_converter(vso_attrs.Time)\ndef _convert(attr):\n    return ValueAttr({('time', ): (attr.start, attr.end, attr.near)})\n", "path": "sunpy/database/attrs.py"}]}