Use self.photodb.sql_ methods instead of running own cursors.
All in the name of centralization. Also improved SQLness of Tag.convert_to_synonym.
This commit is contained in:
parent
2edb9a1d57
commit
144e97d365
1 changed files with 90 additions and 79 deletions
|
@ -87,11 +87,12 @@ class GroupableMixin:
|
||||||
|
|
||||||
# Groupables are only allowed to have 1 parent.
|
# Groupables are only allowed to have 1 parent.
|
||||||
# Unlike photos which can exist in multiple albums.
|
# Unlike photos which can exist in multiple albums.
|
||||||
cur = self.photodb.sql.cursor()
|
parent_row = self.photodb.sql_select_one(
|
||||||
cur.execute('SELECT parentid FROM %s WHERE memberid == ?' % self.group_table, [member.id])
|
'SELECT parentid FROM %s WHERE memberid == ?' % self.group_table,
|
||||||
fetch = cur.fetchone()
|
[member.id]
|
||||||
if fetch is not None:
|
)
|
||||||
parent_id = fetch[0]
|
if parent_row is not None:
|
||||||
|
parent_id = parent_row[0]
|
||||||
if parent_id == self.id:
|
if parent_id == self.id:
|
||||||
return
|
return
|
||||||
that_group = self.group_getter(id=parent_id)
|
that_group = self.group_getter(id=parent_id)
|
||||||
|
@ -154,37 +155,32 @@ class GroupableMixin:
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def get_children(self):
|
def get_children(self):
|
||||||
cur = self.photodb.sql.cursor()
|
child_rows = self.photodb.sql_select(
|
||||||
|
'SELECT memberid FROM %s WHERE parentid == ?' % self.group_table,
|
||||||
|
[self.id]
|
||||||
|
)
|
||||||
|
child_ids = [row[0] for row in child_rows]
|
||||||
|
children = [self.group_getter(id=child_id) for child_id in child_ids]
|
||||||
|
|
||||||
cur.execute('SELECT memberid FROM %s WHERE parentid == ?' % self.group_table, [self.id])
|
|
||||||
fetches = cur.fetchall()
|
|
||||||
results = []
|
|
||||||
for fetch in fetches:
|
|
||||||
memberid = fetch[0]
|
|
||||||
child = self.group_getter(id=memberid)
|
|
||||||
results.append(child)
|
|
||||||
if isinstance(self, Tag):
|
if isinstance(self, Tag):
|
||||||
results.sort(key=lambda x: x.name)
|
children.sort(key=lambda x: x.name)
|
||||||
else:
|
else:
|
||||||
results.sort(key=lambda x: x.id)
|
children.sort(key=lambda x: x.id)
|
||||||
return results
|
return children
|
||||||
|
|
||||||
def get_parent(self):
|
def get_parent(self):
|
||||||
'''
|
'''
|
||||||
Return the group of which this is a member, or None.
|
Return the group of which this is a member, or None.
|
||||||
Returned object will be of the same type as calling object.
|
Returned object will be of the same type as calling object.
|
||||||
'''
|
'''
|
||||||
cur = self.photodb.sql.cursor()
|
parent_row = self.photodb.sql_select_one(
|
||||||
cur.execute(
|
'SELECT parentid FROM %s WHERE memberid == ?' % self.group_table,
|
||||||
'SELECT * FROM %s WHERE memberid == ?' % self.group_table,
|
|
||||||
[self.id]
|
[self.id]
|
||||||
)
|
)
|
||||||
fetch = cur.fetchone()
|
if parent_row is None:
|
||||||
if fetch is None:
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
parentid = fetch[self.group_sql_index['parentid']]
|
return self.group_getter(id=parent_row[0])
|
||||||
return self.group_getter(id=parentid)
|
|
||||||
|
|
||||||
@decorators.transaction
|
@decorators.transaction
|
||||||
def join_group(self, group, *, commit=True):
|
def join_group(self, group, *, commit=True):
|
||||||
|
@ -437,12 +433,11 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def get_associated_directories(self):
|
def get_associated_directories(self):
|
||||||
cur = self.photodb.sql.cursor()
|
directory_rows = self.photodb.sql_select(
|
||||||
cur.execute(
|
|
||||||
'SELECT directory FROM album_associated_directories WHERE albumid == ?',
|
'SELECT directory FROM album_associated_directories WHERE albumid == ?',
|
||||||
[self.id]
|
[self.id]
|
||||||
)
|
)
|
||||||
directories = [x[0] for x in cur.fetchall()]
|
directories = [x[0] for x in directory_rows]
|
||||||
directories = [pathclass.Path(x) for x in directories]
|
directories = [pathclass.Path(x) for x in directories]
|
||||||
return directories
|
return directories
|
||||||
|
|
||||||
|
@ -459,12 +454,12 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
def has_photo(self, photo):
|
def has_photo(self, photo):
|
||||||
if not isinstance(photo, Photo):
|
if not isinstance(photo, Photo):
|
||||||
raise TypeError('`photo` must be of type %s' % Photo)
|
raise TypeError('`photo` must be of type %s' % Photo)
|
||||||
cur = self.photodb.sql.cursor()
|
|
||||||
cur.execute(
|
rel_row = self.photodb.sql_select_one(
|
||||||
'SELECT * FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
'SELECT 1 FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
||||||
[self.id, photo.id]
|
[self.id, photo.id]
|
||||||
)
|
)
|
||||||
return cur.fetchone() is not None
|
return rel_row is not None
|
||||||
|
|
||||||
@decorators.required_feature('album.edit')
|
@decorators.required_feature('album.edit')
|
||||||
# GroupableMixin.join_group already has @transaction.
|
# GroupableMixin.join_group already has @transaction.
|
||||||
|
@ -666,9 +661,7 @@ class Photo(ObjectBase):
|
||||||
'''
|
'''
|
||||||
Reload the row from the database and do __init__ with them.
|
Reload the row from the database and do __init__ with them.
|
||||||
'''
|
'''
|
||||||
cur = self.photodb.sql.cursor()
|
row = self.photodb.sql_select_one('SELECT * FROM photos WHERE id == ?', [self.id])
|
||||||
cur.execute('SELECT * FROM photos WHERE id == ?', [self.id])
|
|
||||||
row = cur.fetchone()
|
|
||||||
self.__init__(self.photodb, row)
|
self.__init__(self.photodb, row)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
@ -863,10 +856,11 @@ class Photo(ObjectBase):
|
||||||
'''
|
'''
|
||||||
Return the albums of which this photo is a member.
|
Return the albums of which this photo is a member.
|
||||||
'''
|
'''
|
||||||
cur = self.photodb.sql.cursor()
|
album_rows = self.photodb.sql_select(
|
||||||
cur.execute('SELECT albumid FROM album_photo_rel WHERE photoid == ?', [self.id])
|
'SELECT albumid FROM album_photo_rel WHERE photoid == ?',
|
||||||
fetches = cur.fetchall()
|
[self.id]
|
||||||
albums = [self.photodb.get_album(id=fetch[0]) for fetch in fetches]
|
)
|
||||||
|
albums = [self.photodb.get_album(id=row[0]) for row in album_rows]
|
||||||
return albums
|
return albums
|
||||||
|
|
||||||
def get_tags(self):
|
def get_tags(self):
|
||||||
|
@ -891,20 +885,21 @@ class Photo(ObjectBase):
|
||||||
tag = self.photodb.get_tag(name=tag)
|
tag = self.photodb.get_tag(name=tag)
|
||||||
|
|
||||||
if check_children:
|
if check_children:
|
||||||
tags = tag.walk_children()
|
tag_options = tag.walk_children()
|
||||||
else:
|
else:
|
||||||
tags = [tag]
|
tag_options = [tag]
|
||||||
|
|
||||||
cur = self.photodb.sql.cursor()
|
tag_by_id = {t.id: t for t in tag_options}
|
||||||
for tag in tags:
|
tag_option_ids = helpers.sql_listify(tag_by_id)
|
||||||
cur.execute(
|
rel_row = self.photodb.sql_select_one(
|
||||||
'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
'SELECT tagid FROM photo_tag_rel WHERE photoid == ? AND tagid IN %s' % tag_option_ids,
|
||||||
[self.id, tag.id]
|
[self.id]
|
||||||
)
|
)
|
||||||
if cur.fetchone() is not None:
|
|
||||||
return tag
|
|
||||||
|
|
||||||
return False
|
if rel_row is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return tag_by_id[rel_row[0]]
|
||||||
|
|
||||||
def make_thumbnail_filepath(self):
|
def make_thumbnail_filepath(self):
|
||||||
'''
|
'''
|
||||||
|
@ -1247,36 +1242,51 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
'''
|
'''
|
||||||
mastertag = self.photodb.get_tag(name=mastertag)
|
mastertag = self.photodb.get_tag(name=mastertag)
|
||||||
|
|
||||||
# Migrate the old tag's synonyms to the new one
|
|
||||||
# UPDATE is safe for this operation because there is no chance of duplicates.
|
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
|
|
||||||
|
# Migrate the old tag's synonyms to the new one
|
||||||
|
# UPDATE is safe for this operation because there is no chance of duplicates.
|
||||||
data = {
|
data = {
|
||||||
'mastername': (self.name, mastertag.name),
|
'mastername': (self.name, mastertag.name),
|
||||||
}
|
}
|
||||||
self.photodb.sql_update(table='tag_synonyms', pairs=data, where_key='mastername')
|
self.photodb.sql_update(table='tag_synonyms', pairs=data, where_key='mastername')
|
||||||
|
|
||||||
# Iterate over all photos with the old tag, and swap them to the new tag
|
# Because these were two separate tags, perhaps in separate trees, it
|
||||||
# if they don't already have it.
|
# is possible for a photo to have both at the moment.
|
||||||
cur = self.photodb.sql.cursor()
|
#
|
||||||
cur.execute('SELECT photoid FROM photo_tag_rel WHERE tagid == ?', [self.id])
|
# If they already have both, the deletion of the syn rel will happen
|
||||||
fetches = cur.fetchall()
|
# when the syn tag is deleted.
|
||||||
|
# If they only have the syn, we will UPDATE it to the master.
|
||||||
|
# If they only have the master, nothing needs to happen.
|
||||||
|
|
||||||
for fetch in fetches:
|
# Find photos that have the old tag and DON'T already have the new one.
|
||||||
photoid = fetch[0]
|
query = '''
|
||||||
cur.execute(
|
SELECT photoid FROM photo_tag_rel p1
|
||||||
'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
WHERE tagid == ?
|
||||||
[photoid, mastertag.id]
|
AND NOT EXISTS (
|
||||||
)
|
SELECT 1 FROM photo_tag_rel p2
|
||||||
if cur.fetchone() is None:
|
WHERE p1.photoid == p2.photoid
|
||||||
data = {
|
AND tagid == ?
|
||||||
'photoid': photoid,
|
)
|
||||||
'tagid': mastertag.id,
|
'''
|
||||||
}
|
bindings = [self.id, mastertag.id]
|
||||||
self.photodb.sql_insert(table='photo_tag_rel', data=data)
|
replace_photoids = [row[0] for row in self.photodb.sql_execute(query, bindings)]
|
||||||
|
|
||||||
# Then delete the relationships with the old tag
|
# For those photos that only had the syn, simply replace with master.
|
||||||
self.delete()
|
if replace_photoids:
|
||||||
|
query = '''
|
||||||
|
UPDATE photo_tag_rel
|
||||||
|
SET tagid = ?
|
||||||
|
WHERE tagid == ?
|
||||||
|
AND photoid IN %s
|
||||||
|
''' % helpers.sql_listify(replace_photoids)
|
||||||
|
bindings = [mastertag.id, self.id]
|
||||||
|
self.photodb.sql_execute(query, bindings)
|
||||||
|
|
||||||
|
# For photos that have the old tag and DO already have the new one,
|
||||||
|
# don't worry because the old rels will be deleted when the tag is
|
||||||
|
# deleted.
|
||||||
|
self.delete(commit=False)
|
||||||
|
|
||||||
# Enjoy your new life as a monk.
|
# Enjoy your new life as a monk.
|
||||||
mastertag.add_synonym(self.name, commit=False)
|
mastertag.add_synonym(self.name, commit=False)
|
||||||
|
@ -1321,11 +1331,13 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def get_synonyms(self):
|
def get_synonyms(self):
|
||||||
cur = self.photodb.sql.cursor()
|
syn_rows = self.photodb.sql_select(
|
||||||
cur.execute('SELECT name FROM tag_synonyms WHERE mastername == ?', [self.name])
|
'SELECT name FROM tag_synonyms WHERE mastername == ?',
|
||||||
fetches = [fetch[0] for fetch in cur.fetchall()]
|
[self.name]
|
||||||
fetches.sort()
|
)
|
||||||
return fetches
|
syn_names = [row[0] for row in syn_rows]
|
||||||
|
syn_names.sort()
|
||||||
|
return syn_names
|
||||||
|
|
||||||
@decorators.required_feature('tag.edit')
|
@decorators.required_feature('tag.edit')
|
||||||
# GroupableMixin.join_group already has @transaction.
|
# GroupableMixin.join_group already has @transaction.
|
||||||
|
@ -1384,13 +1396,12 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
if synname == self.name:
|
if synname == self.name:
|
||||||
raise exceptions.NoSuchSynonym(synname)
|
raise exceptions.NoSuchSynonym(synname)
|
||||||
|
|
||||||
cur = self.photodb.sql.cursor()
|
syn_exists = self.photodb.sql_select_one(
|
||||||
cur.execute(
|
'SELECT 1 FROM tag_synonyms WHERE mastername == ? AND name == ?',
|
||||||
'SELECT * FROM tag_synonyms WHERE mastername == ? AND name == ?',
|
|
||||||
[self.name, synname]
|
[self.name, synname]
|
||||||
)
|
)
|
||||||
fetch = cur.fetchone()
|
|
||||||
if fetch is None:
|
if syn_exists is None:
|
||||||
raise exceptions.NoSuchSynonym(synname)
|
raise exceptions.NoSuchSynonym(synname)
|
||||||
|
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
|
|
Loading…
Reference in a new issue