From 42c20a0442a4348b9059018f8939dd4e351db8e6 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Mon, 28 Mar 2016 00:14:05 +0300 Subject: [PATCH] Search authors by name/surname/misc name Add generic search (case sensitive and insensitive; exact search, substring search and substring anchored to the start) and apply it to authors. --- m_librarian/search.py | 70 +++++++++++++++++++++++++++++++++++++++++++ requirements.txt | 1 + scripts/ml-search.py | 45 ++++++++++++++++++++++++++++ setup.py | 2 +- 4 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 m_librarian/search.py create mode 100755 scripts/ml-search.py diff --git a/m_librarian/search.py b/m_librarian/search.py new file mode 100644 index 0000000..10cfc28 --- /dev/null +++ b/m_librarian/search.py @@ -0,0 +1,70 @@ + +__all__ = [ + 'search_authors', 'search_books', 'search_extensions', + 'search_genres', 'search_languages', +] + +from sqlobject.sqlbuilder import AND, func +from .db import Author, Book, Extension, Genre, Language + + +def _search_exact(table, case_sensitive, values): + expressions = [] + if case_sensitive: + for column, value in values.items(): + expressions.append(getattr(table.q, column) == value) + else: + for column, value in values.items(): + expressions.append( + func.lower(getattr(table.q, column)) == value.lower()) + return AND(*expressions) + + +def _search_start(table, case_sensitive, values): + expressions = [] + if case_sensitive: + for column, value in values.items(): + expressions.append(getattr(table.q, column).startswith(value)) + else: + for column, value in values.items(): + expressions.append( + func.lower(getattr(table.q, column)).startswith(value.lower())) + return AND(*expressions) + + +def _search_substring(table, case_sensitive, values): + expressions = [] + if case_sensitive: + for column, value in values.items(): + expressions.append(getattr(table.q, column).contains(value)) + else: + for column, value in values.items(): + expressions.append( + func.lower(getattr(table.q, column)).contains(value.lower())) + return AND(*expressions) + + +def _search(table, search_type, case_sensitive, values): + _search_f = globals()['_search_%s' % search_type] + conditions = _search_f(table, case_sensitive, values) + return table.select(conditions) + + +def search_authors(search_type, case_sensitive, values): + return _search(Author, search_type, case_sensitive, values) + + +def search_books(search_type, case_sensitive, values): + return _search(Book, search_type, case_sensitive, values) + + +def search_extensions(search_type, case_sensitive, values): + return _search(Extension, search_type, case_sensitive, values) + + +def search_genres(search_type, case_sensitive, values): + return _search(Genre, search_type, case_sensitive, values) + + +def search_languages(search_type, case_sensitive, values): + return _search(Language, search_type, case_sensitive, values) diff --git a/requirements.txt b/requirements.txt index 4147751..88acdf5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ SQLObject +m_lib diff --git a/scripts/ml-search.py b/scripts/ml-search.py new file mode 100755 index 0000000..403780a --- /dev/null +++ b/scripts/ml-search.py @@ -0,0 +1,45 @@ +#! /usr/bin/env python +# coding: utf-8 + +import argparse +from m_lib.defenc import default_encoding +from m_librarian.search import search_authors, search_books, \ + search_extensions, search_genres, search_languages + + +def _search_authors(args): + values = {} + for column in 'surname', 'name', 'misc': + value = getattr(args, column) + if value: + values[column] = unicode(value, default_encoding) + for author in search_authors(args.search_type, args.case_sensitive, + values): + full_name = filter(None, + (author.surname, author.name, author.misc_name)) + full_name = u' '.join(full_name) + print full_name.encode(default_encoding), \ + u"(книг: %d)".encode(default_encoding) % author.count + + +if __name__ == '__main__': + main_parser = argparse.ArgumentParser(description='Search') + main_parser.add_argument('-I', '--case-sensitive', + action='store_true', + help='don\'t ignore case ' + '(default is case-insensitive search)') + main_parser.add_argument('-t', '--search-type', + choices=['exact', 'start', 'substring'], + help='search type: ' + 'exact match, substring at the start ' + '(this is the default), substring anywhere') + subparsers = main_parser.add_subparsers(help='Commands') + + parser = subparsers.add_parser('authors', help='Search authors') + parser.add_argument('-s', '--surname', help='search by surname') + parser.add_argument('-n', '--name', help='search by name') + parser.add_argument('-m', '--misc', help='search by misc. name') + parser.set_defaults(func=_search_authors) + + args = main_parser.parse_args() + args.func(args) diff --git a/setup.py b/setup.py index d616820..f649f3e 100755 --- a/setup.py +++ b/setup.py @@ -44,5 +44,5 @@ setup(name='m_librarian', packages=['m_librarian'], package_data={'m_librarian': ['glst/*.txt', 'glst/genres_*.glst']}, scripts=['scripts/ml-import.py', 'scripts/ml-initdb.py'], - requires=['SQLObject'], + requires=['SQLObject', 'm_lib'], ) -- 2.39.5