5 from sqlobject.sqlbuilder import CONCAT
7 from m_lib.defenc import default_encoding
8 from m_librarian.db import Author, Book, Extension, Genre, Language, open_db
9 from m_librarian.search import mk_search_conditions, \
10 search_authors, search_books, \
11 search_extensions, search_genres, search_languages
13 from m_librarian.translations import translations
14 _ = translations.ugettext
17 def _get_values(args, *columns):
19 for column in columns:
20 value = getattr(args, column)
22 values[column] = unicode(value, default_encoding)
26 def _guess_case_sensitivity(values):
27 for value in values.values():
28 if not value.islower():
33 def _search_authors(case_sensitive, search_type, args):
34 if (args.surname or args.name or args.misc_name) and args.fullname:
36 "Cannot search by names and full name at the same time\n")
37 main_parser.print_help()
40 values = _get_values(args, 'surname', 'name', 'misc_name')
45 CONCAT(Author.q.surname, ' ', Author.q.name, ' ',
47 unicode(value, default_encoding)
49 if case_sensitive is None:
50 case_sensitive = _guess_case_sensitivity(values)
51 authors = search_authors(search_type, case_sensitive, values, expressions,
52 orderBy=('surname', 'name', 'misc_name'))
56 for author in authors:
57 names = filter(None, (author.surname, author.name, author.misc_name))
58 fullname = u' '.join(names)
59 print fullname.encode(default_encoding), \
60 (u"(%s: %d)" % (_('books'), author.count))\
61 .encode(default_encoding),
63 print "(id=%d)" % author.id,
67 def _search_books(case_sensitive, search_type, args):
69 values = _get_values(args, 'title', 'series', 'archive', 'file')
70 if case_sensitive is None:
71 test_values = values.copy()
72 test_values.update(_get_values(args, 'surname', 'name', 'misc_name',
73 'fullname', 'ext', 'gname', 'gtitle',
75 case_sensitive = _guess_case_sensitivity(test_values)
76 avalues = _get_values(args, 'surname', 'name', 'misc_name', 'fullname')
78 if (args.surname or args.name or args.misc_name) and args.fullname:
80 "Cannot search by names and full name at the same time\n")
81 main_parser.print_help()
84 join_expressions.append(Book.j.authors)
88 CONCAT(Author.q.surname, ' ', Author.q.name, ' ',
90 unicode(value, default_encoding)
92 conditions = mk_search_conditions(
93 Author, search_type, case_sensitive, avalues, expressions)
94 join_expressions.extend(conditions)
96 join_expressions.append(Book.j.extension)
97 conditions = mk_search_conditions(
98 Extension, search_type, case_sensitive,
100 join_expressions.extend(conditions)
102 for column in 'name', 'title':
103 value = getattr(args, 'g' + column)
105 gvalues[column] = unicode(value, default_encoding)
107 join_expressions.append(Book.j.genres)
108 conditions = mk_search_conditions(
109 Genre, search_type, case_sensitive, gvalues)
110 join_expressions.extend(conditions)
112 join_expressions.append(Book.j.language)
113 conditions = mk_search_conditions(
114 Language, search_type, case_sensitive,
116 join_expressions.extend(conditions)
117 books = search_books(search_type, case_sensitive, values, join_expressions,
118 orderBy=('series', 'ser_no', 'title'))
123 print book.title.encode(default_encoding),
124 if args.details >= 1:
125 print "(id=%d)" % book.id,
127 if args.details >= 1:
128 print " ", _("Author(s)").encode(default_encoding), ":",
129 for author in book.authors:
131 (author.surname, author.name, author.misc_name))
132 fullname = u' '.join(names)
133 print fullname.encode(default_encoding),
135 print " ", _("Genre(s)").encode(default_encoding), ":",
136 for genre in book.genres:
137 print (genre.title or genre.name).encode(default_encoding),
140 print " ", _("Series").encode(default_encoding), ":",
141 print book.series.encode(default_encoding), \
144 if args.details >= 2:
145 print " ", _("Date").encode(default_encoding), ":", book.date
146 print " ", _("Language").encode(default_encoding), ":", \
147 book.language.name.encode(default_encoding)
149 if args.details >= 3:
150 print " ", _("Archive").encode(default_encoding), ":", book.archive
151 print " ", _("File").encode(default_encoding), ":", book.file
152 print " ", _("Extension").encode(default_encoding), ":", \
153 book.extension.name.encode(default_encoding)
154 print " ", _("Size").encode(default_encoding), ":", \
155 book.size, _("bytes").encode(default_encoding)
156 print " ", _("Deleted").encode(default_encoding), ":", \
157 _(str(book.deleted)).encode(default_encoding)
160 def _search_extensions(case_sensitive, search_type, args):
162 values = {'name': args.name}
163 if case_sensitive is None:
164 case_sensitive = _guess_case_sensitivity(values)
167 extensions = search_extensions(search_type, case_sensitive, values,
170 print extensions.count()
172 for ext in extensions:
173 print ext.name.encode(default_encoding), \
174 (u"(%s: %d)" % (_('books'), ext.count)).encode(default_encoding),
175 if args.details >= 1:
176 print "(id=%d)" % ext.id,
180 def _search_genres(case_sensitive, search_type, args):
181 values = _get_values(args, 'name', 'title')
182 if case_sensitive is None:
183 case_sensitive = _guess_case_sensitivity(values)
184 genres = search_genres(search_type, case_sensitive, values, orderBy='name')
189 names = filter(None, (genre.name, genre.title))
190 fullname = u' '.join(names)
191 print fullname.encode(default_encoding), \
192 (u"(%s: %d)" % (_('books'), genre.count)).encode(default_encoding),
193 if args.details >= 1:
194 print "(id=%d)" % genre.id,
198 def _search_languages(case_sensitive, search_type, args):
200 values = {'name': args.name}
201 if case_sensitive is None:
202 case_sensitive = _guess_case_sensitivity(values)
205 for lang in search_languages(search_type, case_sensitive, values,
207 print lang.name.encode(default_encoding), \
208 (u"(%s: %d)" % (_('books'), lang.count)).encode(default_encoding),
209 if args.details >= 1:
210 print "(id=%d)" % lang.id,
214 if __name__ == '__main__':
215 main_parser = argparse.ArgumentParser(description='Search')
216 main_parser.add_argument('-i', '--ignore-case', action='store_true',
218 '(default is to guess)')
219 main_parser.add_argument('-I', '--case-sensitive', action='store_true',
220 help='don\'t ignore case')
221 main_parser.add_argument('-t', '--start', action='store_true',
222 help='search substring at the start '
223 '(this is the default)')
224 main_parser.add_argument('-s', '--substring', action='store_true',
225 help='search substring anywhere')
226 main_parser.add_argument('-f', '--full', action='store_true',
227 help='match the entire string')
228 main_parser.add_argument('-d', '--details', action='count',
229 help='output more details about books; '
230 'repeat for even more details')
231 main_parser.add_argument('-c', '--count', action='store_true',
232 help='count instead of output')
233 subparsers = main_parser.add_subparsers(help='Commands')
235 parser = subparsers.add_parser('authors', help='Search authors')
236 parser.add_argument('-s', '--surname', help='search by surname')
237 parser.add_argument('-n', '--name', help='search by name')
238 parser.add_argument('-m', '--misc-name', help='search by misc. name')
239 parser.add_argument('fullname', nargs='?', help='search by full name')
240 parser.set_defaults(func=_search_authors)
242 parser = subparsers.add_parser('books', help='Search books')
243 parser.add_argument('-t', '--title', help='search by title')
244 parser.add_argument('-s', '--series', help='search by series')
245 parser.add_argument('-a', '--archive', help='search by archive (zip file)')
246 parser.add_argument('-f', '--file', help='search by file name')
247 parser.add_argument('--surname', help='search by author\'s surname')
248 parser.add_argument('--name', help='search by author\'s name')
249 parser.add_argument('--misc-name', help='search by author\'s misc. name')
250 parser.add_argument('--fullname', help='search by author\'s full name')
251 parser.add_argument('-e', '--ext', help='search by file extension')
252 parser.add_argument('--gname', help='search by genre\'s name')
253 parser.add_argument('--gtitle', help='search by genre\'s title')
254 parser.add_argument('-l', '--lang', help='search by language')
255 parser.set_defaults(func=_search_books)
257 parser = subparsers.add_parser('ext', help='Search extensions')
258 parser.add_argument('name', nargs='?', help='search by name')
259 parser.set_defaults(func=_search_extensions)
261 parser = subparsers.add_parser('genres', help='Search genres')
262 parser.add_argument('-n', '--name', help='search by name')
263 parser.add_argument('-t', '--title', help='search by title')
264 parser.set_defaults(func=_search_genres)
266 parser = subparsers.add_parser('lang', help='Search languages')
267 parser.add_argument('name', nargs='?', help='search by name')
268 parser.set_defaults(func=_search_languages)
270 args = main_parser.parse_args()
272 if args.case_sensitive:
275 "Cannot search case sensitive and case insensitive "
276 "at the same time\n")
277 main_parser.print_help()
280 case_sensitive = True
281 elif args.ignore_case:
282 case_sensitive = False
284 case_sensitive = None # guess case sensitivity
286 if int(args.start) + int(args.substring) + int(args.full) > 1:
288 "Cannot search case sensitive and case insensitive "
289 "at the same time\n")
290 main_parser.print_help()
293 search_type = 'start'
295 search_type = 'substring'
299 search_type = 'start'
302 args.func(case_sensitive, search_type, args)