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', 'id')
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', 'id')
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 avalues['id'] = args.aid
80 if (args.surname or args.name or args.misc_name) and args.fullname:
82 "Cannot search by names and full name at the same time\n")
83 main_parser.print_help()
86 join_expressions.append(Book.j.authors)
90 CONCAT(Author.q.surname, ' ', Author.q.name, ' ',
92 unicode(value, default_encoding)
94 conditions = mk_search_conditions(
95 Author, search_type, case_sensitive, avalues, expressions)
96 join_expressions.extend(conditions)
99 evalues['name'] = args.ext
101 evalues['id'] = args.eid
103 join_expressions.append(Book.j.extension)
104 conditions = mk_search_conditions(
105 Extension, search_type, case_sensitive, evalues)
106 join_expressions.extend(conditions)
108 for column in 'name', 'title':
109 value = getattr(args, 'g' + column)
111 gvalues[column] = unicode(value, default_encoding)
113 gvalues['id'] = args.gid
115 join_expressions.append(Book.j.genres)
116 conditions = mk_search_conditions(
117 Genre, search_type, case_sensitive, gvalues)
118 join_expressions.extend(conditions)
121 lvalues['name'] = args.lang
123 lvalues['id'] = args.lid
125 join_expressions.append(Book.j.language)
126 conditions = mk_search_conditions(
127 Language, search_type, case_sensitive, lvalues)
128 join_expressions.extend(conditions)
129 books = search_books(search_type, case_sensitive, values, join_expressions,
130 orderBy=('series', 'ser_no', 'title'))
135 print book.title.encode(default_encoding),
136 if args.details >= 1:
137 print "(id=%d)" % book.id,
139 if args.details >= 1:
140 print " ", _("Author(s)").encode(default_encoding), ":",
141 for author in book.authors:
143 (author.surname, author.name, author.misc_name))
144 fullname = u' '.join(names)
145 print fullname.encode(default_encoding),
147 print " ", _("Genre(s)").encode(default_encoding), ":",
148 for genre in book.genres:
149 print (genre.title or genre.name).encode(default_encoding),
152 print " ", _("Series").encode(default_encoding), ":",
153 print book.series.encode(default_encoding), \
156 if args.details >= 2:
157 print " ", _("Date").encode(default_encoding), ":", book.date
158 print " ", _("Language").encode(default_encoding), ":", \
159 book.language.name.encode(default_encoding)
161 if args.details >= 3:
162 print " ", _("Archive").encode(default_encoding), ":", book.archive
163 print " ", _("File").encode(default_encoding), ":", book.file
164 print " ", _("Extension").encode(default_encoding), ":", \
165 book.extension.name.encode(default_encoding)
166 print " ", _("Size").encode(default_encoding), ":", \
167 book.size, _("bytes").encode(default_encoding)
168 print " ", _("Deleted").encode(default_encoding), ":", \
169 _(str(book.deleted)).encode(default_encoding)
172 def _search_extensions(case_sensitive, search_type, args):
173 values = _get_values(args, 'name', 'id')
174 if case_sensitive is None:
175 case_sensitive = _guess_case_sensitivity(values)
178 extensions = search_extensions(search_type, case_sensitive, values,
181 print extensions.count()
183 for ext in extensions:
184 print ext.name.encode(default_encoding), \
185 (u"(%s: %d)" % (_('books'), ext.count)).encode(default_encoding),
186 if args.details >= 1:
187 print "(id=%d)" % ext.id,
191 def _search_genres(case_sensitive, search_type, args):
192 values = _get_values(args, 'name', 'title', 'id')
193 if case_sensitive is None:
194 case_sensitive = _guess_case_sensitivity(values)
195 genres = search_genres(search_type, case_sensitive, values, orderBy='name')
200 names = filter(None, (genre.name, genre.title))
201 fullname = u' '.join(names)
202 print fullname.encode(default_encoding), \
203 (u"(%s: %d)" % (_('books'), genre.count)).encode(default_encoding),
204 if args.details >= 1:
205 print "(id=%d)" % genre.id,
209 def _search_languages(case_sensitive, search_type, args):
210 values = _get_values(args, 'name', 'id')
211 if case_sensitive is None:
212 case_sensitive = _guess_case_sensitivity(values)
215 for lang in search_languages(search_type, case_sensitive, values,
217 print lang.name.encode(default_encoding), \
218 (u"(%s: %d)" % (_('books'), lang.count)).encode(default_encoding),
219 if args.details >= 1:
220 print "(id=%d)" % lang.id,
224 if __name__ == '__main__':
225 main_parser = argparse.ArgumentParser(description='Search')
226 main_parser.add_argument('-i', '--ignore-case', action='store_true',
228 '(default is to guess)')
229 main_parser.add_argument('-I', '--case-sensitive', action='store_true',
230 help='don\'t ignore case')
231 main_parser.add_argument('-t', '--start', action='store_true',
232 help='search substring at the start '
233 '(this is the default)')
234 main_parser.add_argument('-s', '--substring', action='store_true',
235 help='search substring anywhere')
236 main_parser.add_argument('-f', '--full', action='store_true',
237 help='match the entire string')
238 main_parser.add_argument('-d', '--details', action='count',
239 help='output more details about books; '
240 'repeat for even more details')
241 main_parser.add_argument('-c', '--count', action='store_true',
242 help='count instead of output')
243 subparsers = main_parser.add_subparsers(help='Commands')
245 parser = subparsers.add_parser('authors', help='Search authors')
246 parser.add_argument('-s', '--surname', help='search by surname')
247 parser.add_argument('-n', '--name', help='search by name')
248 parser.add_argument('-m', '--misc-name', help='search by misc. name')
249 parser.add_argument('--id', help='search by database id')
250 parser.add_argument('fullname', nargs='?', help='search by full name')
251 parser.set_defaults(func=_search_authors)
253 parser = subparsers.add_parser('books', help='Search books')
254 parser.add_argument('-t', '--title', help='search by title')
255 parser.add_argument('-s', '--series', help='search by series')
256 parser.add_argument('-a', '--archive', help='search by archive (zip file)')
257 parser.add_argument('-f', '--file', help='search by file name')
258 parser.add_argument('--id', help='search by database id')
259 parser.add_argument('--surname', help='search by author\'s surname')
260 parser.add_argument('--name', help='search by author\'s name')
261 parser.add_argument('--misc-name', help='search by author\'s misc. name')
262 parser.add_argument('--fullname', help='search by author\'s full name')
263 parser.add_argument('--aid', help='search by author\'s id')
264 parser.add_argument('-e', '--ext', help='search by file extension')
265 parser.add_argument('--eid', help='search by extension\'s id')
266 parser.add_argument('--gname', help='search by genre\'s name')
267 parser.add_argument('--gtitle', help='search by genre\'s title')
268 parser.add_argument('--gid', help='search by genre\'s id')
269 parser.add_argument('-l', '--lang', help='search by language')
270 parser.add_argument('--lid', help='search by language\'s id')
271 parser.set_defaults(func=_search_books)
273 parser = subparsers.add_parser('ext', help='Search extensions')
274 parser.add_argument('name', nargs='?', help='search by name')
275 parser.add_argument('--id', help='search by database id')
276 parser.set_defaults(func=_search_extensions)
278 parser = subparsers.add_parser('genres', help='Search genres')
279 parser.add_argument('-n', '--name', help='search by name')
280 parser.add_argument('-t', '--title', help='search by title')
281 parser.add_argument('--id', help='search by database id')
282 parser.set_defaults(func=_search_genres)
284 parser = subparsers.add_parser('lang', help='Search languages')
285 parser.add_argument('name', nargs='?', help='search by name')
286 parser.add_argument('--id', help='search by database id')
287 parser.set_defaults(func=_search_languages)
289 args = main_parser.parse_args()
291 if args.case_sensitive:
294 "Cannot search case sensitive and case insensitive "
295 "at the same time\n")
296 main_parser.print_help()
299 case_sensitive = True
300 elif args.ignore_case:
301 case_sensitive = False
303 case_sensitive = None # guess case sensitivity
305 if int(args.start) + int(args.substring) + int(args.full) > 1:
307 "Cannot search case sensitive and case insensitive "
308 "at the same time\n")
309 main_parser.print_help()
312 search_type = 'start'
314 search_type = 'substring'
318 search_type = 'start'
321 args.func(case_sensitive, search_type, args)