mirror of
https://github.com/veekun/pokedex.git
synced 2024-08-20 18:16:34 +00:00
Stub out a CLI search interface, which can also work with JSON and strings
This commit is contained in:
parent
2dcc3c1aab
commit
59d8a790d1
4 changed files with 91 additions and 0 deletions
0
pokedex/cli/__init__.py
Normal file
0
pokedex/cli/__init__.py
Normal file
22
pokedex/cli/search.py
Normal file
22
pokedex/cli/search.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
from pokedex.search import search
|
||||||
|
|
||||||
|
|
||||||
|
def configure_parser(parser):
|
||||||
|
parser.set_defaults(func=command_search)
|
||||||
|
|
||||||
|
parser.add_argument('--name', default=None)
|
||||||
|
|
||||||
|
parser.add_argument('--attack', '--atk', dest='attack', default=None)
|
||||||
|
parser.add_argument('--defense', '--def', dest='defense', default=None)
|
||||||
|
parser.add_argument('--special-attack', '--spatk', dest='special-attack', default=None)
|
||||||
|
parser.add_argument('--special-defense', '--spdef', dest='special-defense', default=None)
|
||||||
|
parser.add_argument('--speed', dest='speed', default=None)
|
||||||
|
parser.add_argument('--hp', dest='hp', default=None)
|
||||||
|
|
||||||
|
|
||||||
|
def command_search(parser, args):
|
||||||
|
from pokedex.main import get_session
|
||||||
|
session = get_session(args)
|
||||||
|
results = search(session, **vars(args))
|
||||||
|
for result in results:
|
||||||
|
print(result.name)
|
|
@ -5,6 +5,7 @@ import argparse
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import pokedex.cli.search
|
||||||
import pokedex.db
|
import pokedex.db
|
||||||
import pokedex.db.load
|
import pokedex.db.load
|
||||||
import pokedex.db.tables
|
import pokedex.db.tables
|
||||||
|
@ -63,6 +64,9 @@ def create_parser():
|
||||||
cmd_lookup.set_defaults(func=command_lookup)
|
cmd_lookup.set_defaults(func=command_lookup)
|
||||||
cmd_lookup.add_argument('criteria', nargs='+')
|
cmd_lookup.add_argument('criteria', nargs='+')
|
||||||
|
|
||||||
|
cmd_search = cmds.add_parser('search', help=u'Find things by various criteria')
|
||||||
|
pokedex.cli.search.configure_parser(cmd_search)
|
||||||
|
|
||||||
cmd_load = cmds.add_parser('load', help=u'Load Pokédex data into a database from CSV files')
|
cmd_load = cmds.add_parser('load', help=u'Load Pokédex data into a database from CSV files')
|
||||||
cmd_load.set_defaults(func=command_load, verbose=True)
|
cmd_load.set_defaults(func=command_load, verbose=True)
|
||||||
# TODO get the actual default here
|
# TODO get the actual default here
|
||||||
|
|
65
pokedex/search.py
Normal file
65
pokedex/search.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from sqlalchemy import func
|
||||||
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
|
import pokedex.db.tables as t
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_range(value):
|
||||||
|
v = int(value)
|
||||||
|
return lambda x: x == v
|
||||||
|
|
||||||
|
|
||||||
|
CRITERION_RX = re.compile(r"""
|
||||||
|
\s*
|
||||||
|
(?: (?P<field>[-_a-zA-Z0-9]+): )?
|
||||||
|
(?P<pattern>
|
||||||
|
(?:
|
||||||
|
[^\s"]+?
|
||||||
|
)+
|
||||||
|
)
|
||||||
|
""", re.VERBOSE)
|
||||||
|
def parse_search_string(string):
|
||||||
|
"""Parses a search string!"""
|
||||||
|
criteria = {}
|
||||||
|
for match in CRITERION_RX.finditer(string):
|
||||||
|
# TODO what if there are several of the same match!
|
||||||
|
# TODO the cli needs to do append too
|
||||||
|
field = match.group('field') or '*'
|
||||||
|
criteria[field] = match.group('pattern')
|
||||||
|
return criteria
|
||||||
|
|
||||||
|
|
||||||
|
def search(session, **criteria):
|
||||||
|
query = (
|
||||||
|
session.query(t.Pokemon)
|
||||||
|
.options(
|
||||||
|
joinedload(t.Pokemon.species)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
stat_query = (
|
||||||
|
session.query(t.PokemonStat.pokemon_id)
|
||||||
|
.join(t.PokemonStat.stat)
|
||||||
|
)
|
||||||
|
do_stat = False
|
||||||
|
|
||||||
|
if criteria.get('name') is not None:
|
||||||
|
query = query.filter(t.Pokemon.species.has(func.lower(t.PokemonSpecies.name) == criteria['name'].lower()))
|
||||||
|
|
||||||
|
for stat_ident in (u'attack', u'defense', u'special-attack', u'special-defense', u'speed', u'hp'):
|
||||||
|
criterion = criteria.get(stat_ident)
|
||||||
|
if criterion is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
do_stat = True
|
||||||
|
stat_query = stat_query.filter(
|
||||||
|
(t.Stat.identifier == stat_ident)
|
||||||
|
& _parse_range(criterion)(t.PokemonStat.base_stat)
|
||||||
|
)
|
||||||
|
|
||||||
|
if do_stat:
|
||||||
|
query = query.filter(t.Pokemon.id.in_(stat_query.subquery()))
|
||||||
|
|
||||||
|
return query.all()
|
Loading…
Reference in a new issue