Working on select/update from Struct

This commit is contained in:
Doug Blank 2013-11-12 15:24:15 -05:00
parent f80e6422a3
commit 2c1ba1496b

View File

@ -36,6 +36,53 @@ from ..const import GRAMPS_LOCALE as glocale
from ..constfunc import handle2internal from ..constfunc import handle2internal
_ = glocale.translation.gettext _ = glocale.translation.gettext
def parse(string):
"""
Break a string up into a struct-path:
>>> parse("primary.first_name.startswith('Sarah')")
["primary_name", "first_name", "startswith", "('Sarah')"]
"""
retval = []
stack = []
current = ""
for p in range(len(string)):
c = string[p]
if c == ")":
if stack and stack[-1] == "(": # end
stack.pop(-1)
current += c
retval.append(current)
current = ""
elif c == "(":
stack.append(c)
retval.append(current)
current = ""
current += c
elif c in ["'", '"']:
if stack and stack[-1] == c: # end
stack.pop(-1)
current += c
if stack and stack[-1] in ["'", '"', '(']: # in quote or args
pass
else:
current += c
retval.append(current)
current = ""
else: # start
stack.append(c)
current += c
elif stack and stack[-1] in ["'", '"', '(']: # in quote or args
current += c
elif c == ".":
retval.append(current)
current = ""
else:
current += c
if current:
retval.append(current)
return retval
def import_as_dict(filename, user=None): def import_as_dict(filename, user=None):
""" """
Import the filename into a DictionaryDb and return it. Import the filename into a DictionaryDb and return it.
@ -245,7 +292,10 @@ class Struct(object):
def __init__(self, struct, db=None): def __init__(self, struct, db=None):
self.struct = struct self.struct = struct
self.db = db self.db = db
self.transaction = db.get_transaction_class() if self.db:
self.transaction = db.get_transaction_class()
else:
self.transaction = None
def __getitem__(self, path): def __getitem__(self, path):
""" """
@ -253,14 +303,30 @@ class Struct(object):
>>> Struct(struct)["primary_name.surname_list.0.surname"] >>> Struct(struct)["primary_name.surname_list.0.surname"]
""" """
# First, work way down to last part: # Work way down to last part:
return self.getitem_from_path(parse(path))
def getitem_from_path(self, path):
"""
Given a path that is already parsed, return item.
"""
struct = self.struct struct = self.struct
for part in path.split("."): for part in path:
struct = self.getitem(part, struct) struct = self.getitem(part, struct)
if struct is None: if struct is None:
return None return None
return struct return struct
def get_ref_struct(self, item):
"""
If the item is a handle, look up reference object.
"""
if hasattr(item, "classname") and self.db:
obj = self.db.get_from_name_and_handle(item.classname, str(item))
return Struct(obj.to_struct(), self.db)
else:
return item
def getitem(self, item, struct=None): def getitem(self, item, struct=None):
""" """
>>> Struct(struct).getitem("primary_name") >>> Struct(struct).getitem("primary_name")
@ -272,14 +338,21 @@ class Struct(object):
if isinstance(struct, (list, tuple)): if isinstance(struct, (list, tuple)):
pos = int(item) pos = int(item)
if pos < len(struct): if pos < len(struct):
return struct[int(item)] return self.get_ref_struct(struct[int(item)])
else: else:
return None return None
elif isinstance(struct, dict): elif isinstance(struct, dict):
if item in struct: if item in struct.keys():
return struct[item] return self.get_ref_struct(struct[item])
else: else:
return None return None
elif isinstance(struct, Struct):
return self.get_ref_struct(struct[item])
elif hasattr(struct, item):
return getattr(struct, item)
elif item.startswith("("):
args = eval(item[1:-1] + ",")
return struct(*args)
else: else:
return None return None
@ -289,33 +362,40 @@ class Struct(object):
>>> Struct(struct).getitem(["primary_name", "surname_list", "0", "surname"]) >>> Struct(struct).getitem(["primary_name", "surname_list", "0", "surname"])
""" """
path = path.split(".") return self.setitem_from_path(parse(path), value)
def setitem_from_path(self, path, value):
path, item = path[:-1], path[-1] path, item = path[:-1], path[-1]
struct = self[".".join(path)] struct = self.getitem_from_path(path)
if isinstance(struct, (list, tuple)): if isinstance(struct, (list, tuple)):
pos = int(item) pos = int(item)
if pos < len(struct): if pos < len(struct):
struct[int(item)] = value struct[int(item)] = value
elif isinstance(struct, dict): elif isinstance(struct, dict):
struct[item] = value if item in struct.keys():
struct[item] = value
else:
raise AttributeError("no such property: '%s'" % item)
elif isinstance(struct, Struct):
struct.setitem_from_path(path, value)
elif hasattr(struct, item):
setattr(struct, item, value)
else: else:
return return
# update the database self.update_db()
if self.db:
self.update_db()
def update_db(self): def update_db(self):
name = self.struct["_class"] if self.db:
handle = self.struct["handle"] with self.transaction("Struct Update", self.db) as trans:
obj = self.db.get_from_name_and_handle(name, handle) new_obj = from_struct(self.struct)
new_obj = from_struct(self.struct) name, handle = self.struct["_class"], self.struct["handle"]
with self.transaction("Struct Update", self.db) as trans: old_obj = self.db.get_from_name_and_handle(name, handle)
if obj: if old_obj:
commit_func = self.db._tables[name]["commit_func"] commit_func = self.db._tables[name]["commit_func"]
commit_func(new_obj, trans) commit_func(new_obj, trans)
else: else:
add_func = self.db._tables[name]["add_func"] add_func = self.db._tables[name]["add_func"]
add_func(new_obj, trans) add_func(new_obj, trans)
def __str__(self): def __str__(self):
return str(self.struct) return str(self.struct)