mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
STart work on write api for many-one fields
This commit is contained in:
parent
f3f4bdb023
commit
579142ee45
@ -22,6 +22,7 @@ from calibre.utils.localization import calibre_langcode_to_name
|
|||||||
class Field(object):
|
class Field(object):
|
||||||
|
|
||||||
is_many = False
|
is_many = False
|
||||||
|
is_many_many = False
|
||||||
|
|
||||||
def __init__(self, name, table):
|
def __init__(self, name, table):
|
||||||
self.name, self.table = name, table
|
self.name, self.table = name, table
|
||||||
@ -299,6 +300,7 @@ class ManyToOneField(Field):
|
|||||||
class ManyToManyField(Field):
|
class ManyToManyField(Field):
|
||||||
|
|
||||||
is_many = True
|
is_many = True
|
||||||
|
is_many_many = True
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
Field.__init__(self, *args, **kwargs)
|
Field.__init__(self, *args, **kwargs)
|
||||||
|
@ -128,8 +128,8 @@ def one_one_in_other(book_id_val_map, db, field, *args):
|
|||||||
if deleted:
|
if deleted:
|
||||||
db.conn.executemany('DELETE FROM %s WHERE book=?'%field.metadata['table'],
|
db.conn.executemany('DELETE FROM %s WHERE book=?'%field.metadata['table'],
|
||||||
deleted)
|
deleted)
|
||||||
for book_id in book_id_val_map:
|
for book_id in deleted:
|
||||||
field.table.book_col_map.pop(book_id, None)
|
field.table.book_col_map.pop(book_id[0], None)
|
||||||
updated = {k:v for k, v in book_id_val_map.iteritems() if v is not None}
|
updated = {k:v for k, v in book_id_val_map.iteritems() if v is not None}
|
||||||
if updated:
|
if updated:
|
||||||
db.conn.executemany('INSERT OR REPLACE INTO %s(book,%s) VALUES (?,?)'%(
|
db.conn.executemany('INSERT OR REPLACE INTO %s(book,%s) VALUES (?,?)'%(
|
||||||
@ -154,6 +154,87 @@ def custom_series_index(book_id_val_map, db, field, *args):
|
|||||||
return {s[0] for s in sequence}
|
return {s[0] for s in sequence}
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
# Many-One fields {{{
|
||||||
|
|
||||||
|
def many_one(book_id_val_map, db, field, allow_case_change, *args):
|
||||||
|
dirtied = set()
|
||||||
|
m = field.metadata
|
||||||
|
dt = m['datatype']
|
||||||
|
kmap = icu_lower if dt == 'text' else lambda x:x
|
||||||
|
rid_map = {kmap(v):k for k, v in field.table.id_map.iteritems()}
|
||||||
|
book_id_item_id_map = {k:rid_map.get(kmap(v), None) if v is not None else
|
||||||
|
None for k, v in book_id_val_map.iteritems()}
|
||||||
|
if allow_case_change:
|
||||||
|
for book_id, item_id in book_id_item_id_map.iteritems():
|
||||||
|
nval = book_id_val_map[book_id]
|
||||||
|
if (item_id is not None and nval != field.table.id_map[item_id]):
|
||||||
|
# Change of case
|
||||||
|
db.conn.execute('UPDATE %s SET %s=? WHERE id=?'%(
|
||||||
|
m['table'], m['column']), (nval, item_id))
|
||||||
|
field.table.id_map[item_id] = nval
|
||||||
|
dirtied |= field.table.col_book_map[item_id]
|
||||||
|
|
||||||
|
deleted = {k:v for k, v in book_id_val_map.iteritems() if v is None}
|
||||||
|
updated = {k:v for k, v in book_id_val_map.iteritems() if v is not None}
|
||||||
|
|
||||||
|
if deleted:
|
||||||
|
db.conn.executemany('DELETE FROM %s WHERE book=?'%m['link_table'],
|
||||||
|
tuple((book_id,) for book_id in deleted))
|
||||||
|
for book_id in deleted:
|
||||||
|
field.table.book_col_map.pop(book_id, None)
|
||||||
|
field.table.col_book_map.discard(book_id)
|
||||||
|
dirtied |= set(deleted)
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
new_items = {k:v for k, v in updated.iteritems() if
|
||||||
|
book_id_item_id_map[k] is None}
|
||||||
|
changed_items = {k:book_id_item_id_map[k] for k in updated if
|
||||||
|
book_id_item_id_map[k] is not None}
|
||||||
|
def sql_update(imap):
|
||||||
|
db.conn.executemany(
|
||||||
|
'DELETE FROM {0} WHERE book=?; INSERT INTO {0}(book,{1}) VALUES(?, ?)'
|
||||||
|
.format(m['link_table'], m['link_column']),
|
||||||
|
tuple((book_id, book_id, item_id) for book_id, item_id in
|
||||||
|
imap.iteritems()))
|
||||||
|
|
||||||
|
if new_items:
|
||||||
|
imap = {}
|
||||||
|
for book_id, val in new_items.iteritems():
|
||||||
|
db.conn.execute('INSERT INTO %s(%s) VALUES (?)'%(
|
||||||
|
m['table'], m['column']), (val,))
|
||||||
|
imap[book_id] = item_id = db.conn.last_insert_rowid()
|
||||||
|
field.table.id_map[item_id] = val
|
||||||
|
field.table.col_book_map[item_id] = {book_id}
|
||||||
|
field.table.book_col_map[book_id] = item_id
|
||||||
|
sql_update(imap)
|
||||||
|
dirtied |= set(imap)
|
||||||
|
|
||||||
|
if changed_items:
|
||||||
|
imap = {}
|
||||||
|
sql_update(changed_items)
|
||||||
|
for book_id, item_id in changed_items.iteritems():
|
||||||
|
old_item_id = field.table.book_col_map[book_id]
|
||||||
|
if old_item_id != item_id:
|
||||||
|
field.table.book_col_map[book_id] = item_id
|
||||||
|
field.table.col_book_map[item_id].add(book_id)
|
||||||
|
field.table.col_book_map[old_item_id].discard(book_id)
|
||||||
|
imap[book_id] = item_id
|
||||||
|
sql_update(imap)
|
||||||
|
dirtied |= set(imap)
|
||||||
|
|
||||||
|
# Remove no longer used items
|
||||||
|
remove = {item_id for item_id, book_ids in
|
||||||
|
field.table.col_book_map.iteritems() if not book_ids}
|
||||||
|
if remove:
|
||||||
|
db.conn.executemany('DELETE FROM %s WHERE id=?'%m['table'],
|
||||||
|
tuple((item_id,) for item_id in remove))
|
||||||
|
for item_id in remove:
|
||||||
|
del field.table.id_map[item_id]
|
||||||
|
del field.table.col_book_map[item_id]
|
||||||
|
|
||||||
|
return dirtied
|
||||||
|
# }}}
|
||||||
|
|
||||||
def dummy(book_id_val_map, *args):
|
def dummy(book_id_val_map, *args):
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
@ -170,10 +251,13 @@ class Writer(object):
|
|||||||
self.set_books_func = dummy
|
self.set_books_func = dummy
|
||||||
elif self.name[0] == '#' and self.name.endswith('_index'):
|
elif self.name[0] == '#' and self.name.endswith('_index'):
|
||||||
self.set_books_func = custom_series_index
|
self.set_books_func = custom_series_index
|
||||||
elif field.is_many:
|
elif field.is_many_many:
|
||||||
# TODO: Implement this
|
# TODO: Implement this
|
||||||
pass
|
pass
|
||||||
# TODO: Remember to change commas to | when writing authors to sqlite
|
# TODO: Remember to change commas to | when writing authors to sqlite
|
||||||
|
elif field.is_many:
|
||||||
|
# TODO: Implement this
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
self.set_books_func = (one_one_in_books if field.metadata['table']
|
self.set_books_func = (one_one_in_books if field.metadata['table']
|
||||||
== 'books' else one_one_in_other)
|
== 'books' else one_one_in_other)
|
||||||
@ -185,6 +269,7 @@ class Writer(object):
|
|||||||
book_id_val_map.iteritems() if self.accept_vals(v)}
|
book_id_val_map.iteritems() if self.accept_vals(v)}
|
||||||
if not book_id_val_map:
|
if not book_id_val_map:
|
||||||
return set()
|
return set()
|
||||||
dirtied = self.set_books_func(book_id_val_map, db, self.field)
|
dirtied = self.set_books_func(book_id_val_map, db, self.field,
|
||||||
|
allow_case_change)
|
||||||
return dirtied
|
return dirtied
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user