|
|
|
@ -2,19 +2,69 @@
|
|
|
|
Module for accessing the sqlite monster hunter db from
|
|
|
|
Module for accessing the sqlite monster hunter db from
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os.path
|
|
|
|
import sqlite3
|
|
|
|
import sqlite3
|
|
|
|
|
|
|
|
|
|
|
|
from mhapi import model
|
|
|
|
from mhapi import model
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def field_model(key):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
Model to replace each row with the value of single field in the row,
|
|
|
|
|
|
|
|
with the specified key.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def model_fn(row):
|
|
|
|
|
|
|
|
return row[key]
|
|
|
|
|
|
|
|
return model_fn
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _db_path():
|
|
|
|
|
|
|
|
module_path = os.path.dirname(__file__)
|
|
|
|
|
|
|
|
project_path = os.path.abspath(os.path.join(module_path, ".."))
|
|
|
|
|
|
|
|
return os.path.join(project_path, "db", "mh4u.db")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MHDB(object):
|
|
|
|
class MHDB(object):
|
|
|
|
def __init__(self, path, use_cache=True):
|
|
|
|
"""
|
|
|
|
|
|
|
|
Wrapper around the Android App sqlite3 db. The following conventions
|
|
|
|
|
|
|
|
are used:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- get_ENTITY_NAME will return a single entity by id
|
|
|
|
|
|
|
|
- get_ENTITY_NAME_by_name will return a single entity by name
|
|
|
|
|
|
|
|
- get_ENTITY_NAMEs will return a list of all entities in the db
|
|
|
|
|
|
|
|
- get_ENTITY_NAME_names will return a list of all names of the
|
|
|
|
|
|
|
|
entities in the db, possibly with a type param.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, path=None, use_cache=False):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
If use_cache=True, a lot of memory could be used. No attempt is
|
|
|
|
|
|
|
|
made to de-dupe data between keys, e.g. if you access an item
|
|
|
|
|
|
|
|
by id and by name, it will be fetched and stored in the cache
|
|
|
|
|
|
|
|
twice. Disk cache, sqlite caching, and the smallness of the
|
|
|
|
|
|
|
|
database should make in-memory caching unnecessary for most use
|
|
|
|
|
|
|
|
cases.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
if path is None:
|
|
|
|
|
|
|
|
path = _db_path()
|
|
|
|
self.conn = sqlite3.connect(path)
|
|
|
|
self.conn = sqlite3.connect(path)
|
|
|
|
self.conn.row_factory = sqlite3.Row
|
|
|
|
self.conn.row_factory = sqlite3.Row
|
|
|
|
self.use_cache = use_cache
|
|
|
|
self.use_cache = use_cache
|
|
|
|
self.cache = {}
|
|
|
|
self.cache = {}
|
|
|
|
|
|
|
|
|
|
|
|
def _get_memoized(self, key, query, *args):
|
|
|
|
def _query_one(self, key, query, args=(), model_cls=None,
|
|
|
|
if self.use_cache:
|
|
|
|
no_cache=False):
|
|
|
|
|
|
|
|
values = self._query_all(key, query, args, model_cls, no_cache)
|
|
|
|
|
|
|
|
if values:
|
|
|
|
|
|
|
|
return values[0]
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _query_all(self, key, query, args=(), model_cls=None,
|
|
|
|
|
|
|
|
no_cache=False, collection_cls=None):
|
|
|
|
|
|
|
|
assert isinstance(args, tuple)
|
|
|
|
|
|
|
|
assert model_cls is None or collection_cls is None
|
|
|
|
|
|
|
|
if self.use_cache and not no_cache:
|
|
|
|
if key in self.cache:
|
|
|
|
if key in self.cache:
|
|
|
|
v = self.cache[key].get(args)
|
|
|
|
v = self.cache[key].get(args)
|
|
|
|
if v is not None:
|
|
|
|
if v is not None:
|
|
|
|
@ -22,10 +72,14 @@ class MHDB(object):
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
self.cache[key] = {}
|
|
|
|
self.cache[key] = {}
|
|
|
|
cursor = self.conn.execute(query, args)
|
|
|
|
cursor = self.conn.execute(query, args)
|
|
|
|
v = cursor.fetchall()
|
|
|
|
rows = cursor.fetchall()
|
|
|
|
if self.use_cache:
|
|
|
|
if model_cls:
|
|
|
|
self.cache[key][args] = v
|
|
|
|
rows = [model_cls(row) for row in rows]
|
|
|
|
return v
|
|
|
|
if collection_cls:
|
|
|
|
|
|
|
|
rows = collection_cls(rows)
|
|
|
|
|
|
|
|
if self.use_cache and not no_cache:
|
|
|
|
|
|
|
|
self.cache[key][args] = rows
|
|
|
|
|
|
|
|
return rows
|
|
|
|
|
|
|
|
|
|
|
|
def cursor(self):
|
|
|
|
def cursor(self):
|
|
|
|
return self.conn.cursor()
|
|
|
|
return self.conn.cursor()
|
|
|
|
@ -36,41 +90,65 @@ class MHDB(object):
|
|
|
|
def close(self):
|
|
|
|
def close(self):
|
|
|
|
return self.conn.close()
|
|
|
|
return self.conn.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_types(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
List of strings.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._query_all("item_types", """
|
|
|
|
|
|
|
|
SELECT DISTINCT type FROM items
|
|
|
|
|
|
|
|
""", model_cls=field_model("type"))
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_names(self, item_types):
|
|
|
|
def get_item_names(self, item_types):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
List of unicode strings.
|
|
|
|
|
|
|
|
"""
|
|
|
|
item_types.sort()
|
|
|
|
item_types.sort()
|
|
|
|
placeholders = ", ".join(["?"] * len(item_types))
|
|
|
|
placeholders = ", ".join(["?"] * len(item_types))
|
|
|
|
v = self._get_memoized("item_names", """
|
|
|
|
return self._query_all("item_names", """
|
|
|
|
SELECT _id, name FROM items
|
|
|
|
SELECT _id, name FROM items
|
|
|
|
WHERE type IN (%s)
|
|
|
|
WHERE type IN (%s)
|
|
|
|
""" % placeholders, *item_types)
|
|
|
|
""" % placeholders, tuple(item_types), model_cls=field_model("name"))
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_names(self):
|
|
|
|
def get_items(self, item_types=None):
|
|
|
|
v = self._get_memoized("monster_names", """
|
|
|
|
"""
|
|
|
|
SELECT name FROM monsters
|
|
|
|
List of item objects.
|
|
|
|
""")
|
|
|
|
"""
|
|
|
|
return v
|
|
|
|
q = "SELECT * FROM items"
|
|
|
|
|
|
|
|
if item_types:
|
|
|
|
|
|
|
|
item_types.sort()
|
|
|
|
|
|
|
|
placeholders = ", ".join(["?"] * len(item_types))
|
|
|
|
|
|
|
|
q += "\nWHERE type IN (%s)" % placeholders
|
|
|
|
|
|
|
|
item_types = tuple(item_types)
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
|
|
|
item_types = ()
|
|
|
|
|
|
|
|
return self._query_all("items", q, item_types, model_cls=model.Item)
|
|
|
|
|
|
|
|
|
|
|
|
def get_item(self, item_id):
|
|
|
|
def get_item(self, item_id):
|
|
|
|
v = self._get_memoized("item", """
|
|
|
|
"""
|
|
|
|
|
|
|
|
Single item object or None.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._query_one("item", """
|
|
|
|
SELECT * FROM items
|
|
|
|
SELECT * FROM items
|
|
|
|
WHERE _id=?
|
|
|
|
WHERE _id=?
|
|
|
|
""", item_id)
|
|
|
|
""", (item_id,), model_cls=model.Item)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_by_name(self, name):
|
|
|
|
def get_item_by_name(self, name):
|
|
|
|
v = self._get_memoized("item", """
|
|
|
|
"""
|
|
|
|
|
|
|
|
Single item object or None.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._query_one("item", """
|
|
|
|
SELECT * FROM items
|
|
|
|
SELECT * FROM items
|
|
|
|
WHERE name=?
|
|
|
|
WHERE name=?
|
|
|
|
""", name)
|
|
|
|
""", (name,), model_cls=model.Item)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_wyporium_trade(self, item_id):
|
|
|
|
def get_wyporium_trade(self, item_id):
|
|
|
|
v = self._get_memoized("wyporium", """
|
|
|
|
"""
|
|
|
|
|
|
|
|
Single wyporium row or None.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._query_one("wyporium", """
|
|
|
|
SELECT * FROM wyporium
|
|
|
|
SELECT * FROM wyporium
|
|
|
|
WHERE item_in_id=?
|
|
|
|
WHERE item_in_id=?
|
|
|
|
""", item_id)
|
|
|
|
""", (item_id,))
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def search_item_name(self, term, item_type=None):
|
|
|
|
def search_item_name(self, term, item_type=None):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
@ -92,42 +170,50 @@ class MHDB(object):
|
|
|
|
query += "AND type = ?"
|
|
|
|
query += "AND type = ?"
|
|
|
|
args += [item_type]
|
|
|
|
args += [item_type]
|
|
|
|
|
|
|
|
|
|
|
|
cursor = self.conn.execute(query, args)
|
|
|
|
return self._query_all("search_item", query, tuple(args),
|
|
|
|
return cursor.fetchall()
|
|
|
|
no_cache=True, model_cls=model.Item)
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_by_name(self, name):
|
|
|
|
def get_monsters(self):
|
|
|
|
v = self._get_memoized("monster", """
|
|
|
|
return self._query_all("monsters", """
|
|
|
|
SELECT * FROM monsters
|
|
|
|
SELECT * FROM monsters
|
|
|
|
WHERE name=?
|
|
|
|
""", model_cls=model.Monster)
|
|
|
|
""", name)
|
|
|
|
|
|
|
|
return v[0] if v else None
|
|
|
|
def get_monster_names(self):
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
List of unicode strings.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
return self._query_all("monster_names", """
|
|
|
|
|
|
|
|
SELECT name FROM monsters
|
|
|
|
|
|
|
|
""", model_cls=field_model("name"))
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster(self, monster_id):
|
|
|
|
def get_monster(self, monster_id):
|
|
|
|
v = self._get_memoized("monster", """
|
|
|
|
return self._query_one("monster", """
|
|
|
|
SELECT * FROM monsters
|
|
|
|
SELECT * FROM monsters
|
|
|
|
WHERE _id=?
|
|
|
|
WHERE _id=?
|
|
|
|
""", monster_id)
|
|
|
|
""", (monster_id,), model_cls=model.Monster)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_by_name(self, name):
|
|
|
|
|
|
|
|
return self._query_one("monster", """
|
|
|
|
|
|
|
|
SELECT * FROM monsters
|
|
|
|
|
|
|
|
WHERE name=?
|
|
|
|
|
|
|
|
""", (name,), model_cls=model.Monster)
|
|
|
|
|
|
|
|
|
|
|
|
def get_quest(self, quest_id):
|
|
|
|
def get_quest(self, quest_id):
|
|
|
|
v = self._get_memoized("quest", """
|
|
|
|
return self._query_one("quest", """
|
|
|
|
SELECT * FROM quests
|
|
|
|
SELECT * FROM quests
|
|
|
|
WHERE _id=?
|
|
|
|
WHERE _id=?
|
|
|
|
""", quest_id)
|
|
|
|
""", (quest_id,), model_cls=model.Quest)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_quests(self):
|
|
|
|
def get_quests(self):
|
|
|
|
v = self._get_memoized("quests", """
|
|
|
|
return self._query_all("quests", """
|
|
|
|
SELECT * FROM quests
|
|
|
|
SELECT * FROM quests
|
|
|
|
""")
|
|
|
|
""", model_cls=model.Quest)
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_quest_rewards(self, quest_id):
|
|
|
|
def get_quest_rewards(self, quest_id):
|
|
|
|
v = self._get_memoized("quest_rewards", """
|
|
|
|
return self._query_all("quest_rewards", """
|
|
|
|
SELECT * FROM quest_rewards
|
|
|
|
SELECT * FROM quest_rewards
|
|
|
|
WHERE quest_id=?
|
|
|
|
WHERE quest_id=?
|
|
|
|
""", quest_id)
|
|
|
|
""", (quest_id,))
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_rewards(self, monster_id, rank=None):
|
|
|
|
def get_monster_rewards(self, monster_id, rank=None):
|
|
|
|
q = """
|
|
|
|
q = """
|
|
|
|
@ -136,19 +222,18 @@ class MHDB(object):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
if rank is not None:
|
|
|
|
if rank is not None:
|
|
|
|
q += "AND rank=?"
|
|
|
|
q += "AND rank=?"
|
|
|
|
v = self._get_memoized("monster_rewards", q, monster_id, rank)
|
|
|
|
args = (monster_id, rank)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
v = self._get_memoized("monster_rewards", q, monster_id)
|
|
|
|
args = (monster_id,)
|
|
|
|
return v
|
|
|
|
return self._query_all("monster_rewards", q, args)
|
|
|
|
|
|
|
|
|
|
|
|
def get_quest_monsters(self, quest_id):
|
|
|
|
def get_quest_monsters(self, quest_id):
|
|
|
|
v = self._get_memoized("quest_monsters", """
|
|
|
|
return self._query_all("quest_monsters", """
|
|
|
|
SELECT monster_id, unstable FROM monster_to_quest
|
|
|
|
SELECT monster_id, unstable FROM monster_to_quest
|
|
|
|
WHERE quest_id=?
|
|
|
|
WHERE quest_id=?
|
|
|
|
""", quest_id)
|
|
|
|
""", (quest_id,))
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_quest_objects(self, item_id):
|
|
|
|
def get_item_quests(self, item_id):
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
Get a list of quests that provide the specified item in quest
|
|
|
|
Get a list of quests that provide the specified item in quest
|
|
|
|
reqards. Returns a list of quest objects, which encapsulate the
|
|
|
|
reqards. Returns a list of quest objects, which encapsulate the
|
|
|
|
@ -163,79 +248,70 @@ class MHDB(object):
|
|
|
|
|
|
|
|
|
|
|
|
quests = []
|
|
|
|
quests = []
|
|
|
|
for r in rows:
|
|
|
|
for r in rows:
|
|
|
|
quest_row = self.get_quest(r["quest_id"])
|
|
|
|
quest_id = r["quest_id"]
|
|
|
|
rewards_rows = self.get_quest_rewards(r["quest_id"])
|
|
|
|
quest = self.get_quest(quest_id)
|
|
|
|
quests.append(model.Quest(quest_row, rewards_rows))
|
|
|
|
quest.rewards = self.get_quest_rewards(quest_id)
|
|
|
|
|
|
|
|
quests.append(quest)
|
|
|
|
|
|
|
|
|
|
|
|
return quests
|
|
|
|
return quests
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_monsters(self, item_id):
|
|
|
|
def get_item_monsters(self, item_id):
|
|
|
|
v = self._get_memoized("item_monsters", """
|
|
|
|
return self._query_all("item_monsters", """
|
|
|
|
SELECT DISTINCT monster_id, rank FROM hunting_rewards
|
|
|
|
SELECT DISTINCT monster_id, rank FROM hunting_rewards
|
|
|
|
WHERE item_id=?
|
|
|
|
WHERE item_id=?
|
|
|
|
""", item_id)
|
|
|
|
""", (item_id,))
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_item_gathering(self, item_id):
|
|
|
|
def get_item_gathering(self, item_id):
|
|
|
|
v = self._get_memoized("item_gathering", """
|
|
|
|
return self._query_all("item_gathering", """
|
|
|
|
SELECT * FROM gathering
|
|
|
|
SELECT * FROM gathering
|
|
|
|
WHERE item_id=?
|
|
|
|
WHERE item_id=?
|
|
|
|
""", item_id)
|
|
|
|
""", (item_id,))
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_location(self, location_id):
|
|
|
|
def get_location(self, location_id):
|
|
|
|
v = self._get_memoized("location", """
|
|
|
|
self._query_one("location", """
|
|
|
|
SELECT * FROM locations
|
|
|
|
SELECT * FROM locations
|
|
|
|
WHERE _id=?
|
|
|
|
WHERE _id=?
|
|
|
|
""", location_id)
|
|
|
|
""", (location_id,), model_cls=model.Location)
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_locations(self):
|
|
|
|
def get_locations(self):
|
|
|
|
v = self._get_memoized("locations", """
|
|
|
|
return self._query_all("locations", """
|
|
|
|
SELECT * FROM locations
|
|
|
|
SELECT * FROM locations
|
|
|
|
""")
|
|
|
|
""", model_cls=model.Location)
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_damage(self, monster_id):
|
|
|
|
def get_monster_damage(self, monster_id):
|
|
|
|
v = self._get_memoized("monster_damage", """
|
|
|
|
return self._query_all("monster_damage", """
|
|
|
|
SELECT * FROM monster_damage
|
|
|
|
SELECT * FROM monster_damage
|
|
|
|
WHERE monster_id=?
|
|
|
|
WHERE monster_id=?
|
|
|
|
""", monster_id)
|
|
|
|
""", (monster_id,), collection_cls=model.MonsterDamage)
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_weapons(self):
|
|
|
|
def get_weapons(self):
|
|
|
|
v = self._get_memoized("weapons", """
|
|
|
|
return self._query_all("weapons", """
|
|
|
|
SELECT * FROM weapons
|
|
|
|
SELECT * FROM weapons
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
""")
|
|
|
|
""", model_cls=model.Weapon)
|
|
|
|
|
|
|
|
|
|
|
|
return v
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_weapon(self, weapon_id):
|
|
|
|
def get_weapon(self, weapon_id):
|
|
|
|
v = self._get_memoized("weapon", """
|
|
|
|
return self._query_one("weapon", """
|
|
|
|
SELECT * FROM weapons
|
|
|
|
SELECT * FROM weapons
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
WHERE weapons._id=?
|
|
|
|
WHERE weapons._id=?
|
|
|
|
""", weapon_id)
|
|
|
|
""", (weapon_id,), model_cls=model.Weapon)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_weapon_by_name(self, name):
|
|
|
|
def get_weapon_by_name(self, name):
|
|
|
|
v = self._get_memoized("weapon", """
|
|
|
|
return self._query_one("weapon", """
|
|
|
|
SELECT * FROM weapons
|
|
|
|
SELECT * FROM weapons
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
LEFT JOIN items ON weapons._id = items._id
|
|
|
|
WHERE items.name=?
|
|
|
|
WHERE items.name=?
|
|
|
|
""", name)
|
|
|
|
""", (name,), model_cls=model.Weapon)
|
|
|
|
return v[0] if v else None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_monster_breaks(self, monster_id):
|
|
|
|
def get_monster_breaks(self, monster_id):
|
|
|
|
v = self._get_memoized("monster_breaks", """
|
|
|
|
"""
|
|
|
|
|
|
|
|
List of strings.
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
def model(row):
|
|
|
|
|
|
|
|
return row["condition"][len("Break "):]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return self._query_all("monster_breaks", """
|
|
|
|
SELECT DISTINCT condition FROM hunting_rewards
|
|
|
|
SELECT DISTINCT condition FROM hunting_rewards
|
|
|
|
WHERE monster_id=? AND condition LIKE 'Break %'
|
|
|
|
WHERE monster_id=? AND condition LIKE 'Break %'
|
|
|
|
""", monster_id)
|
|
|
|
""", (monster_id,), model_cls=model)
|
|
|
|
|
|
|
|
|
|
|
|
return [row["condition"][len("Break "):] for row in v]
|
|
|
|
|
|
|
|
|