Separate cursors for every transaction
This commit is contained in:
parent
13ae208a06
commit
109d5feef1
4 changed files with 132 additions and 85 deletions
|
@ -1,4 +1,5 @@
|
||||||
import converter
|
import converter
|
||||||
|
import logging
|
||||||
import string
|
import string
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -117,6 +118,8 @@ ADDITIONAL_MIMETYPES = {
|
||||||
DEFAULT_DATADIR = '.\\_etiquette'
|
DEFAULT_DATADIR = '.\\_etiquette'
|
||||||
|
|
||||||
DEFAULT_CONFIGURATION = {
|
DEFAULT_CONFIGURATION = {
|
||||||
|
'log_level': logging.DEBUG,
|
||||||
|
|
||||||
'min_tag_name_length': 1,
|
'min_tag_name_length': 1,
|
||||||
'max_tag_name_length': 32,
|
'max_tag_name_length': 32,
|
||||||
'valid_tag_chars': string.ascii_lowercase + string.digits + '_',
|
'valid_tag_chars': string.ascii_lowercase + string.digits + '_',
|
||||||
|
|
|
@ -13,14 +13,14 @@ else:
|
||||||
|
|
||||||
if port == 443:
|
if port == 443:
|
||||||
http = gevent.pywsgi.WSGIServer(
|
http = gevent.pywsgi.WSGIServer(
|
||||||
listener=('', port),
|
listener=('0.0.0.0', port),
|
||||||
application=etiquette.site,
|
application=etiquette.site,
|
||||||
keyfile='C:\\git\\etiquette\\etiquette\\https\\etiquette.key',
|
keyfile='C:\\git\\etiquette\\etiquette\\https\\etiquette.key',
|
||||||
certfile='C:\\git\\etiquette\\etiquette\\https\\etiquette.crt',
|
certfile='C:\\git\\etiquette\\etiquette\\https\\etiquette.crt',
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
http = gevent.pywsgi.WSGIServer(
|
http = gevent.pywsgi.WSGIServer(
|
||||||
listener=('', port),
|
listener=('0.0.0.0', port),
|
||||||
application=etiquette.site,
|
application=etiquette.site,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
123
objects.py
123
objects.py
|
@ -43,8 +43,9 @@ 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.
|
||||||
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [member.id])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchone()
|
cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [member.id])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is not None:
|
if fetch is not None:
|
||||||
parent_id = fetch[constants.SQL_TAGGROUP['parentid']]
|
parent_id = fetch[constants.SQL_TAGGROUP['parentid']]
|
||||||
if parent_id == self.id:
|
if parent_id == self.id:
|
||||||
|
@ -58,14 +59,15 @@ class GroupableMixin:
|
||||||
raise exceptions.RecursiveGrouping('%s is an ancestor of %s' % (member.name, self.name))
|
raise exceptions.RecursiveGrouping('%s is an ancestor of %s' % (member.name, self.name))
|
||||||
|
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
self.photodb.cur.execute('INSERT INTO tag_group_rel VALUES(?, ?)', [self.id, member.id])
|
cur.execute('INSERT INTO tag_group_rel VALUES(?, ?)', [self.id, member.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Commiting - add to group')
|
self.photodb.log.debug('Commiting - add to group')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def children(self):
|
def children(self):
|
||||||
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE parentid == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchall()
|
cur.execute('SELECT * FROM tag_group_rel WHERE parentid == ?', [self.id])
|
||||||
|
fetch = cur.fetchall()
|
||||||
results = []
|
results = []
|
||||||
for f in fetch:
|
for f in fetch:
|
||||||
memberid = f[constants.SQL_TAGGROUP['memberid']]
|
memberid = f[constants.SQL_TAGGROUP['memberid']]
|
||||||
|
@ -91,6 +93,7 @@ class GroupableMixin:
|
||||||
Otherwise they'll just be raised up one level.
|
Otherwise they'll just be raised up one level.
|
||||||
'''
|
'''
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
|
cur = self.photodb.sql.cursor()
|
||||||
if delete_children:
|
if delete_children:
|
||||||
for child in self.children():
|
for child in self.children():
|
||||||
child.delete(delete_children=delete_children, commit=False)
|
child.delete(delete_children=delete_children, commit=False)
|
||||||
|
@ -99,15 +102,15 @@ class GroupableMixin:
|
||||||
parent = self.parent()
|
parent = self.parent()
|
||||||
if parent is None:
|
if parent is None:
|
||||||
# Since this group was a root, children become roots by removing the row.
|
# Since this group was a root, children become roots by removing the row.
|
||||||
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE parentid == ?', [self.id])
|
cur.execute('DELETE FROM tag_group_rel WHERE parentid == ?', [self.id])
|
||||||
else:
|
else:
|
||||||
# Since this group was a child, its parent adopts all its children.
|
# Since this group was a child, its parent adopts all its children.
|
||||||
self.photodb.cur.execute(
|
cur.execute(
|
||||||
'UPDATE tag_group_rel SET parentid == ? WHERE parentid == ?',
|
'UPDATE tag_group_rel SET parentid == ? WHERE parentid == ?',
|
||||||
[parent.id, self.id]
|
[parent.id, self.id]
|
||||||
)
|
)
|
||||||
# Note that this part comes after the deletion of children to prevent issues of recursion.
|
# Note that this part comes after the deletion of children to prevent issues of recursion.
|
||||||
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - delete tag')
|
self.photodb.log.debug('Committing - delete tag')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -117,8 +120,9 @@ class GroupableMixin:
|
||||||
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.
|
||||||
'''
|
'''
|
||||||
self.photodb.cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchone()
|
cur.execute('SELECT * FROM tag_group_rel WHERE memberid == ?', [self.id])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -144,8 +148,9 @@ class GroupableMixin:
|
||||||
'''
|
'''
|
||||||
Leave the current group and become independent.
|
Leave the current group and become independent.
|
||||||
'''
|
'''
|
||||||
|
cur = self.photodb.sql.cursor()
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
self.photodb.cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
cur.execute('DELETE FROM tag_group_rel WHERE memberid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - leave group')
|
self.photodb.log.debug('Committing - leave group')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -184,7 +189,8 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
raise ValueError('Not the same PhotoDB')
|
raise ValueError('Not the same PhotoDB')
|
||||||
if self.has_photo(photo):
|
if self.has_photo(photo):
|
||||||
return
|
return
|
||||||
self.photodb.cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute('INSERT INTO album_photo_rel VALUES(?, ?)', [self.id, photo.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - add photo to album')
|
self.photodb.log.debug('Committing - add photo to album')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -205,8 +211,9 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
def delete(self, *, delete_children=False, commit=True):
|
def delete(self, *, delete_children=False, commit=True):
|
||||||
self.photodb.log.debug('Deleting album {album:r}'.format(album=self))
|
self.photodb.log.debug('Deleting album {album:r}'.format(album=self))
|
||||||
GroupableMixin.delete(self, delete_children=delete_children, commit=False)
|
GroupableMixin.delete(self, delete_children=delete_children, commit=False)
|
||||||
self.photodb.cur.execute('DELETE FROM albums WHERE id == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE albumid == ?', [self.id])
|
cur.execute('DELETE FROM albums WHERE id == ?', [self.id])
|
||||||
|
cur.execute('DELETE FROM album_photo_rel WHERE albumid == ?', [self.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - delete album')
|
self.photodb.log.debug('Committing - delete album')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -216,7 +223,7 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
title = self.title
|
title = self.title
|
||||||
if description is None:
|
if description is None:
|
||||||
description = self.description
|
description = self.description
|
||||||
self.photodb.cur.execute(
|
cur.execute(
|
||||||
'UPDATE albums SET title=?, description=? WHERE id == ?',
|
'UPDATE albums SET title=?, description=? WHERE id == ?',
|
||||||
[title, description, self.id]
|
[title, description, self.id]
|
||||||
)
|
)
|
||||||
|
@ -229,11 +236,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('Must be a %s' % Photo)
|
raise TypeError('Must be a %s' % Photo)
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'SELECT * FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
'SELECT * FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
||||||
[self.id, photo.id]
|
[self.id, photo.id]
|
||||||
)
|
)
|
||||||
return self.photodb.cur.fetchone() is not None
|
return cur.fetchone() is not None
|
||||||
|
|
||||||
def photos(self):
|
def photos(self):
|
||||||
photos = []
|
photos = []
|
||||||
|
@ -252,7 +260,8 @@ class Album(ObjectBase, GroupableMixin):
|
||||||
def remove_photo(self, photo, *, commit=True):
|
def remove_photo(self, photo, *, commit=True):
|
||||||
if not self.has_photo(photo):
|
if not self.has_photo(photo):
|
||||||
return
|
return
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'DELETE FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
'DELETE FROM album_photo_rel WHERE albumid == ? AND photoid == ?',
|
||||||
[self.id, photo.id]
|
[self.id, photo.id]
|
||||||
)
|
)
|
||||||
|
@ -309,8 +318,9 @@ 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.
|
||||||
'''
|
'''
|
||||||
self.photodb.cur.execute('SELECT * FROM photos WHERE id == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
row = self.photodb.cur.fetchone()
|
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):
|
||||||
|
@ -338,8 +348,9 @@ class Photo(ObjectBase):
|
||||||
|
|
||||||
self.photodb.log.debug('Applying tag {tag:s} to photo {pho:s}'.format(tag=tag, pho=self))
|
self.photodb.log.debug('Applying tag {tag:s} to photo {pho:s}'.format(tag=tag, pho=self))
|
||||||
now = int(helpers.now())
|
now = int(helpers.now())
|
||||||
self.photodb.cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id])
|
cur = self.photodb.sql.cursor()
|
||||||
self.photodb.cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
|
cur.execute('INSERT INTO photo_tag_rel VALUES(?, ?)', [self.id, tag.id])
|
||||||
|
cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - add photo tag')
|
self.photodb.log.debug('Committing - add photo tag')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -348,8 +359,9 @@ class Photo(ObjectBase):
|
||||||
'''
|
'''
|
||||||
Return the albums of which this photo is a member.
|
Return the albums of which this photo is a member.
|
||||||
'''
|
'''
|
||||||
self.photodb.cur.execute('SELECT albumid FROM album_photo_rel WHERE photoid == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchall()
|
cur.execute('SELECT albumid FROM album_photo_rel WHERE photoid == ?', [self.id])
|
||||||
|
fetch = cur.fetchall()
|
||||||
albums = [self.photodb.get_album(f[0]) for f in fetch]
|
albums = [self.photodb.get_album(f[0]) for f in fetch]
|
||||||
return albums
|
return albums
|
||||||
|
|
||||||
|
@ -368,9 +380,10 @@ class Photo(ObjectBase):
|
||||||
Delete the Photo and its relation to any tags and albums.
|
Delete the Photo and its relation to any tags and albums.
|
||||||
'''
|
'''
|
||||||
self.photodb.log.debug('Deleting photo {photo:r}'.format(photo=self))
|
self.photodb.log.debug('Deleting photo {photo:r}'.format(photo=self))
|
||||||
self.photodb.cur.execute('DELETE FROM photos WHERE id == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
self.photodb.cur.execute('DELETE FROM photo_tag_rel WHERE photoid == ?', [self.id])
|
cur.execute('DELETE FROM photos WHERE id == ?', [self.id])
|
||||||
self.photodb.cur.execute('DELETE FROM album_photo_rel WHERE photoid == ?', [self.id])
|
cur.execute('DELETE FROM photo_tag_rel WHERE photoid == ?', [self.id])
|
||||||
|
cur.execute('DELETE FROM album_photo_rel WHERE photoid == ?', [self.id])
|
||||||
|
|
||||||
if delete_file:
|
if delete_file:
|
||||||
path = self.real_path.absolute_path
|
path = self.real_path.absolute_path
|
||||||
|
@ -453,7 +466,8 @@ class Photo(ObjectBase):
|
||||||
|
|
||||||
|
|
||||||
if return_filepath != self.thumbnail:
|
if return_filepath != self.thumbnail:
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'UPDATE photos SET thumbnail = ? WHERE id == ?',
|
'UPDATE photos SET thumbnail = ? WHERE id == ?',
|
||||||
[return_filepath, self.id]
|
[return_filepath, self.id]
|
||||||
)
|
)
|
||||||
|
@ -480,12 +494,13 @@ class Photo(ObjectBase):
|
||||||
else:
|
else:
|
||||||
tags = [tag]
|
tags = [tag]
|
||||||
|
|
||||||
|
cur = self.photodb.sql.cursor()
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
self.photodb.cur.execute(
|
cur.execute(
|
||||||
'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
||||||
[self.id, tag.id]
|
[self.id, tag.id]
|
||||||
)
|
)
|
||||||
if self.photodb.cur.fetchone() is not None:
|
if cur.fetchone() is not None:
|
||||||
return tag
|
return tag
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
@ -545,7 +560,8 @@ class Photo(ObjectBase):
|
||||||
self.area = self.width * self.height
|
self.area = self.width * self.height
|
||||||
self.ratio = round(self.width / self.height, 2)
|
self.ratio = round(self.width / self.height, 2)
|
||||||
|
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'UPDATE photos SET width=?, height=?, area=?, ratio=?, duration=?, bytes=? WHERE id==?',
|
'UPDATE photos SET width=?, height=?, area=?, ratio=?, duration=?, bytes=? WHERE id==?',
|
||||||
[self.width, self.height, self.area, self.ratio, self.duration, self.bytes, self.id],
|
[self.width, self.height, self.area, self.ratio, self.duration, self.bytes, self.id],
|
||||||
)
|
)
|
||||||
|
@ -558,13 +574,15 @@ class Photo(ObjectBase):
|
||||||
|
|
||||||
self.photodb.log.debug('Removing tag {t} from photo {p}'.format(t=repr(tag), p=repr(self)))
|
self.photodb.log.debug('Removing tag {t} from photo {p}'.format(t=repr(tag), p=repr(self)))
|
||||||
tags = list(tag.walk_children())
|
tags = list(tag.walk_children())
|
||||||
|
|
||||||
|
cur = self.photodb.sql.cursor()
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
self.photodb.cur.execute(
|
cur.execute(
|
||||||
'DELETE FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
'DELETE FROM photo_tag_rel WHERE photoid == ? AND tagid == ?',
|
||||||
[self.id, tag.id]
|
[self.id, tag.id]
|
||||||
)
|
)
|
||||||
now = int(helpers.now())
|
now = int(helpers.now())
|
||||||
self.photodb.cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
|
cur.execute('UPDATE photos SET tagged_at = ? WHERE id == ?', [now, self.id])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - remove photo tag')
|
self.photodb.log.debug('Committing - remove photo tag')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -604,7 +622,8 @@ class Photo(ObjectBase):
|
||||||
except OSError:
|
except OSError:
|
||||||
spinal.copy_file(old_path, new_path)
|
spinal.copy_file(old_path, new_path)
|
||||||
|
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'UPDATE photos SET filepath = ? WHERE filepath == ?',
|
'UPDATE photos SET filepath = ? WHERE filepath == ?',
|
||||||
[new_path.absolute_path, old_path.absolute_path]
|
[new_path.absolute_path, old_path.absolute_path]
|
||||||
)
|
)
|
||||||
|
@ -687,7 +706,8 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
raise exceptions.TagExists(synname)
|
raise exceptions.TagExists(synname)
|
||||||
|
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
self.photodb.cur.execute('INSERT INTO tag_synonyms VALUES(?, ?)', [synname, self.name])
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute('INSERT INTO tag_synonyms VALUES(?, ?)', [synname, self.name])
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - add synonym')
|
self.photodb.log.debug('Committing - add synonym')
|
||||||
|
@ -707,7 +727,8 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
# Migrate the old tag's synonyms to the new one
|
# Migrate the old tag's synonyms to the new one
|
||||||
# UPDATE is safe for this operation because there is no chance of duplicates.
|
# 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
|
||||||
self.photodb.cur.execute(
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute(
|
||||||
'UPDATE tag_synonyms SET mastername = ? WHERE mastername == ?',
|
'UPDATE tag_synonyms SET mastername = ? WHERE mastername == ?',
|
||||||
[mastertag.name, self.name]
|
[mastertag.name, self.name]
|
||||||
)
|
)
|
||||||
|
@ -722,10 +743,10 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
for relationship in generator:
|
for relationship in generator:
|
||||||
photoid = relationship[constants.SQL_PHOTOTAG['photoid']]
|
photoid = relationship[constants.SQL_PHOTOTAG['photoid']]
|
||||||
query = 'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?'
|
query = 'SELECT * FROM photo_tag_rel WHERE photoid == ? AND tagid == ?'
|
||||||
self.photodb.cur.execute(query, [photoid, mastertag.id])
|
cur.execute(query, [photoid, mastertag.id])
|
||||||
if self.photodb.cur.fetchone() is None:
|
if cur.fetchone() is None:
|
||||||
query = 'INSERT INTO photo_tag_rel VALUES(?, ?)'
|
query = 'INSERT INTO photo_tag_rel VALUES(?, ?)'
|
||||||
self.photodb.cur.execute(query, [photoid, mastertag.id])
|
cur.execute(query, [photoid, mastertag.id])
|
||||||
|
|
||||||
# Then delete the relationships with the old tag
|
# Then delete the relationships with the old tag
|
||||||
self.delete()
|
self.delete()
|
||||||
|
@ -740,9 +761,10 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.photodb.log.debug('Deleting tag {tag:r}'.format(tag=self))
|
self.photodb.log.debug('Deleting tag {tag:r}'.format(tag=self))
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
GroupableMixin.delete(self, delete_children=delete_children, commit=False)
|
GroupableMixin.delete(self, delete_children=delete_children, commit=False)
|
||||||
self.photodb.cur.execute('DELETE FROM tags WHERE id == ?', [self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
self.photodb.cur.execute('DELETE FROM photo_tag_rel WHERE tagid == ?', [self.id])
|
cur.execute('DELETE FROM tags WHERE id == ?', [self.id])
|
||||||
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE mastername == ?', [self.name])
|
cur.execute('DELETE FROM photo_tag_rel WHERE tagid == ?', [self.id])
|
||||||
|
cur.execute('DELETE FROM tag_synonyms WHERE mastername == ?', [self.name])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - delete tag')
|
self.photodb.log.debug('Committing - delete tag')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -766,13 +788,14 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
they always resolve to the master tag before application.
|
they always resolve to the master tag before application.
|
||||||
'''
|
'''
|
||||||
synname = self.photodb.normalize_tagname(synname)
|
synname = self.photodb.normalize_tagname(synname)
|
||||||
self.photodb.cur.execute('SELECT * FROM tag_synonyms WHERE name == ?', [synname])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchone()
|
cur.execute('SELECT * FROM tag_synonyms WHERE name == ?', [synname])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
raise exceptions.NoSuchSynonym(synname)
|
raise exceptions.NoSuchSynonym(synname)
|
||||||
|
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
self.photodb.cur.execute('DELETE FROM tag_synonyms WHERE name == ?', [synname])
|
cur.execute('DELETE FROM tag_synonyms WHERE name == ?', [synname])
|
||||||
if commit:
|
if commit:
|
||||||
self.photodb.log.debug('Committing - remove synonym')
|
self.photodb.log.debug('Committing - remove synonym')
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
@ -794,9 +817,10 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
|
|
||||||
self._cached_qualified_name = None
|
self._cached_qualified_name = None
|
||||||
self.photodb._cached_frozen_children = None
|
self.photodb._cached_frozen_children = None
|
||||||
self.photodb.cur.execute('UPDATE tags SET name = ? WHERE id == ?', [new_name, self.id])
|
cur = self.photodb.sql.cursor()
|
||||||
|
cur.execute('UPDATE tags SET name = ? WHERE id == ?', [new_name, self.id])
|
||||||
if apply_to_synonyms:
|
if apply_to_synonyms:
|
||||||
self.photodb.cur.execute(
|
cur.execute(
|
||||||
'UPDATE tag_synonyms SET mastername = ? WHERE mastername = ?',
|
'UPDATE tag_synonyms SET mastername = ? WHERE mastername = ?',
|
||||||
[new_name, self.name]
|
[new_name, self.name]
|
||||||
)
|
)
|
||||||
|
@ -807,8 +831,9 @@ class Tag(ObjectBase, GroupableMixin):
|
||||||
self.photodb.commit()
|
self.photodb.commit()
|
||||||
|
|
||||||
def synonyms(self):
|
def synonyms(self):
|
||||||
self.photodb.cur.execute('SELECT name FROM tag_synonyms WHERE mastername == ?', [self.name])
|
cur = self.photodb.sql.cursor()
|
||||||
fetch = self.photodb.cur.fetchall()
|
cur.execute('SELECT name FROM tag_synonyms WHERE mastername == ?', [self.name])
|
||||||
|
fetch = cur.fetchall()
|
||||||
fetch = [f[0] for f in fetch]
|
fetch = [f[0] for f in fetch]
|
||||||
fetch.sort()
|
fetch.sort()
|
||||||
return fetch
|
return fetch
|
||||||
|
|
|
@ -320,8 +320,9 @@ class PDBAlbumMixin:
|
||||||
Return the album with the `associated_directory` of this value, NOT case-sensitive.
|
Return the album with the `associated_directory` of this value, NOT case-sensitive.
|
||||||
'''
|
'''
|
||||||
filepath = os.path.abspath(filepath)
|
filepath = os.path.abspath(filepath)
|
||||||
self.cur.execute('SELECT * FROM albums WHERE associated_directory == ?', [filepath])
|
cur = self.sql.cursor()
|
||||||
fetch = self.cur.fetchone()
|
cur.execute('SELECT * FROM albums WHERE associated_directory == ?', [filepath])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
raise exceptions.NoSuchAlbum(filepath)
|
raise exceptions.NoSuchAlbum(filepath)
|
||||||
return self.get_album(fetch[constants.SQL_ALBUM['id']])
|
return self.get_album(fetch[constants.SQL_ALBUM['id']])
|
||||||
|
@ -363,7 +364,8 @@ class PDBAlbumMixin:
|
||||||
|
|
||||||
(qmarks, bindings) = helpers.binding_filler(constants.SQL_ALBUM_COLUMNS, data)
|
(qmarks, bindings) = helpers.binding_filler(constants.SQL_ALBUM_COLUMNS, data)
|
||||||
query = 'INSERT INTO albums VALUES(%s)' % qmarks
|
query = 'INSERT INTO albums VALUES(%s)' % qmarks
|
||||||
self.cur.execute(query, bindings)
|
cur = self.sql.cursor()
|
||||||
|
cur.execute(query, bindings)
|
||||||
|
|
||||||
album = objects.Album(self, data)
|
album = objects.Album(self, data)
|
||||||
if photos:
|
if photos:
|
||||||
|
@ -383,8 +385,9 @@ class PDBPhotoMixin:
|
||||||
|
|
||||||
def get_photo_by_path(self, filepath):
|
def get_photo_by_path(self, filepath):
|
||||||
filepath = os.path.abspath(filepath)
|
filepath = os.path.abspath(filepath)
|
||||||
self.cur.execute('SELECT * FROM photos WHERE filepath == ?', [filepath])
|
cur = self.sql.cursor()
|
||||||
fetch = self.cur.fetchone()
|
cur.execute('SELECT * FROM photos WHERE filepath == ?', [filepath])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
raise_no_such_thing(exceptions.NoSuchPhoto, thing_name=filepath)
|
raise_no_such_thing(exceptions.NoSuchPhoto, thing_name=filepath)
|
||||||
photo = objects.Photo(self, fetch)
|
photo = objects.Photo(self, fetch)
|
||||||
|
@ -398,10 +401,10 @@ class PDBPhotoMixin:
|
||||||
return
|
return
|
||||||
# We're going to use a second cursor because the first one may
|
# We're going to use a second cursor because the first one may
|
||||||
# get used for something else, deactivating this query.
|
# get used for something else, deactivating this query.
|
||||||
temp_cur = self.sql.cursor()
|
cur = self.sql.cursor()
|
||||||
temp_cur.execute('SELECT * FROM photos ORDER BY created DESC')
|
cur.execute('SELECT * FROM photos ORDER BY created DESC')
|
||||||
while True:
|
while True:
|
||||||
fetch = temp_cur.fetchone()
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
break
|
break
|
||||||
photo = objects.Photo(self, fetch)
|
photo = objects.Photo(self, fetch)
|
||||||
|
@ -485,7 +488,8 @@ class PDBPhotoMixin:
|
||||||
|
|
||||||
(qmarks, bindings) = helpers.binding_filler(constants.SQL_PHOTO_COLUMNS, data)
|
(qmarks, bindings) = helpers.binding_filler(constants.SQL_PHOTO_COLUMNS, data)
|
||||||
query = 'INSERT INTO photos VALUES(%s)' % qmarks
|
query = 'INSERT INTO photos VALUES(%s)' % qmarks
|
||||||
self.cur.execute(query, bindings)
|
cur = self.sql.cursor()
|
||||||
|
cur.execute(query, bindings)
|
||||||
photo = objects.Photo(self, data)
|
photo = objects.Photo(self, data)
|
||||||
|
|
||||||
if do_metadata:
|
if do_metadata:
|
||||||
|
@ -673,6 +677,10 @@ class PDBPhotoMixin:
|
||||||
print(query)
|
print(query)
|
||||||
generator = helpers.select_generator(self.sql, query)
|
generator = helpers.select_generator(self.sql, query)
|
||||||
|
|
||||||
|
if orderby is None:
|
||||||
|
giveback_orderby = None
|
||||||
|
else:
|
||||||
|
giveback_orderby = [term.replace('RANDOM()', 'random') for term in orderby]
|
||||||
if give_back_parameters:
|
if give_back_parameters:
|
||||||
parameters = {
|
parameters = {
|
||||||
'area': area,
|
'area': area,
|
||||||
|
@ -694,7 +702,7 @@ class PDBPhotoMixin:
|
||||||
'tag_expression': tag_expression,
|
'tag_expression': tag_expression,
|
||||||
'limit': limit,
|
'limit': limit,
|
||||||
'offset': offset,
|
'offset': offset,
|
||||||
'orderby': [term.replace('RANDOM()', 'random') for term in orderby],
|
'orderby': giveback_orderby,
|
||||||
}
|
}
|
||||||
yield parameters
|
yield parameters
|
||||||
|
|
||||||
|
@ -851,15 +859,16 @@ class PDBTagMixin:
|
||||||
tagname = tagname.split('.')[-1].split('+')[0]
|
tagname = tagname.split('.')[-1].split('+')[0]
|
||||||
tagname = self.normalize_tagname(tagname)
|
tagname = self.normalize_tagname(tagname)
|
||||||
|
|
||||||
|
cur = self.sql.cursor()
|
||||||
while True:
|
while True:
|
||||||
# Return if it's a toplevel, or resolve the synonym and try that.
|
# Return if it's a toplevel, or resolve the synonym and try that.
|
||||||
self.cur.execute('SELECT * FROM tags WHERE name == ?', [tagname])
|
cur.execute('SELECT * FROM tags WHERE name == ?', [tagname])
|
||||||
fetch = self.cur.fetchone()
|
fetch = cur.fetchone()
|
||||||
if fetch is not None:
|
if fetch is not None:
|
||||||
return objects.Tag(self, fetch)
|
return objects.Tag(self, fetch)
|
||||||
|
|
||||||
self.cur.execute('SELECT * FROM tag_synonyms WHERE name == ?', [tagname])
|
cur.execute('SELECT * FROM tag_synonyms WHERE name == ?', [tagname])
|
||||||
fetch = self.cur.fetchone()
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
# was not a top tag or synonym
|
# was not a top tag or synonym
|
||||||
raise_no_such_thing(exceptions.NoSuchTag, thing_name=tagname)
|
raise_no_such_thing(exceptions.NoSuchTag, thing_name=tagname)
|
||||||
|
@ -882,7 +891,8 @@ class PDBTagMixin:
|
||||||
|
|
||||||
tagid = self.generate_id('tags')
|
tagid = self.generate_id('tags')
|
||||||
self._cached_frozen_children = None
|
self._cached_frozen_children = None
|
||||||
self.cur.execute('INSERT INTO tags VALUES(?, ?)', [tagid, tagname])
|
cur = self.sql.cursor()
|
||||||
|
cur.execute('INSERT INTO tags VALUES(?, ?)', [tagid, tagname])
|
||||||
if commit:
|
if commit:
|
||||||
self.log.debug('Commiting - new_tag')
|
self.log.debug('Commiting - new_tag')
|
||||||
self.commit()
|
self.commit()
|
||||||
|
@ -916,12 +926,13 @@ class PDBUserMixin:
|
||||||
so they get their own method.
|
so they get their own method.
|
||||||
'''
|
'''
|
||||||
possible = string.digits + string.ascii_uppercase
|
possible = string.digits + string.ascii_uppercase
|
||||||
|
cur = self.sql.cursor()
|
||||||
for retry in range(20):
|
for retry in range(20):
|
||||||
user_id = [random.choice(possible) for x in range(self.config['id_length'])]
|
user_id = [random.choice(possible) for x in range(self.config['id_length'])]
|
||||||
user_id = ''.join(user_id)
|
user_id = ''.join(user_id)
|
||||||
|
|
||||||
self.cur.execute('SELECT * FROM users WHERE id == ?', [user_id])
|
cur.execute('SELECT * FROM users WHERE id == ?', [user_id])
|
||||||
if self.cur.fetchone() is None:
|
if cur.fetchone() is None:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
raise Exception('Failed to create user id after 20 tries.')
|
raise Exception('Failed to create user id after 20 tries.')
|
||||||
|
@ -932,20 +943,22 @@ class PDBUserMixin:
|
||||||
if not helpers.is_xor(id, username):
|
if not helpers.is_xor(id, username):
|
||||||
raise exceptions.NotExclusive('One and only one of `id`, `username` must be passed.')
|
raise exceptions.NotExclusive('One and only one of `id`, `username` must be passed.')
|
||||||
|
|
||||||
|
cur = self.sql.cursor()
|
||||||
if username is not None:
|
if username is not None:
|
||||||
self.cur.execute('SELECT * FROM users WHERE username == ?', [username])
|
cur.execute('SELECT * FROM users WHERE username == ?', [username])
|
||||||
else:
|
else:
|
||||||
self.cur.execute('SELECT * FROM users WHERE id == ?', [id])
|
cur.execute('SELECT * FROM users WHERE id == ?', [id])
|
||||||
|
|
||||||
fetch = self.cur.fetchone()
|
fetch = cur.fetchone()
|
||||||
if fetch is not None:
|
if fetch is not None:
|
||||||
return objects.User(self, fetch)
|
return objects.User(self, fetch)
|
||||||
else:
|
else:
|
||||||
raise exceptions.NoSuchUser(username)
|
raise exceptions.NoSuchUser(username)
|
||||||
|
|
||||||
def login(self, user_id, password):
|
def login(self, user_id, password):
|
||||||
self.cur.execute('SELECT * FROM users WHERE id == ?', [user_id])
|
cur = self.sql.cursor()
|
||||||
fetch = self.cur.fetchone()
|
cur.execute('SELECT * FROM users WHERE id == ?', [user_id])
|
||||||
|
fetch = cur.fetchone()
|
||||||
|
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
raise exceptions.WrongLogin()
|
raise exceptions.WrongLogin()
|
||||||
|
@ -978,8 +991,9 @@ class PDBUserMixin:
|
||||||
if len(password) < self.config['min_password_length']:
|
if len(password) < self.config['min_password_length']:
|
||||||
raise exceptions.PasswordTooShort
|
raise exceptions.PasswordTooShort
|
||||||
|
|
||||||
self.cur.execute('SELECT * FROM users WHERE username == ?', [username])
|
cur = self.sql.cursor()
|
||||||
if self.cur.fetchone() is not None:
|
cur.execute('SELECT * FROM users WHERE username == ?', [username])
|
||||||
|
if cur.fetchone() is not None:
|
||||||
raise exceptions.UserExists(username)
|
raise exceptions.UserExists(username)
|
||||||
|
|
||||||
user_id = self.generate_user_id()
|
user_id = self.generate_user_id()
|
||||||
|
@ -995,7 +1009,7 @@ class PDBUserMixin:
|
||||||
|
|
||||||
(qmarks, bindings) = helpers.binding_filler(constants.SQL_USER_COLUMNS, data)
|
(qmarks, bindings) = helpers.binding_filler(constants.SQL_USER_COLUMNS, data)
|
||||||
query = 'INSERT INTO users VALUES(%s)' % qmarks
|
query = 'INSERT INTO users VALUES(%s)' % qmarks
|
||||||
self.cur.execute(query, bindings)
|
cur.execute(query, bindings)
|
||||||
|
|
||||||
if commit:
|
if commit:
|
||||||
self.log.debug('Committing - register user')
|
self.log.debug('Committing - register user')
|
||||||
|
@ -1069,6 +1083,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
statements = DB_INIT.split(';')
|
statements = DB_INIT.split(';')
|
||||||
for statement in statements:
|
for statement in statements:
|
||||||
self.cur.execute(statement)
|
self.cur.execute(statement)
|
||||||
|
self.sql.commit()
|
||||||
|
|
||||||
# CONFIG
|
# CONFIG
|
||||||
self.config_file = self.data_directory.with_child('config.json')
|
self.config_file = self.data_directory.with_child('config.json')
|
||||||
|
@ -1088,6 +1103,7 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
|
|
||||||
# OTHER
|
# OTHER
|
||||||
self.log = logging.getLogger(__name__)
|
self.log = logging.getLogger(__name__)
|
||||||
|
self.log.setLevel(self.config['log_level'])
|
||||||
self.on_commit_queue = []
|
self.on_commit_queue = []
|
||||||
self._cached_frozen_children = None
|
self._cached_frozen_children = None
|
||||||
|
|
||||||
|
@ -1305,8 +1321,9 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
if table not in ['photos', 'tags', 'groups']:
|
if table not in ['photos', 'tags', 'groups']:
|
||||||
raise ValueError('Invalid table requested: %s.', table)
|
raise ValueError('Invalid table requested: %s.', table)
|
||||||
|
|
||||||
self.cur.execute('SELECT * FROM id_numbers WHERE tab == ?', [table])
|
cur = self.sql.cursor()
|
||||||
fetch = self.cur.fetchone()
|
cur.execute('SELECT * FROM id_numbers WHERE tab == ?', [table])
|
||||||
|
fetch = cur.fetchone()
|
||||||
if fetch is None:
|
if fetch is None:
|
||||||
# Register new value
|
# Register new value
|
||||||
new_id_int = 1
|
new_id_int = 1
|
||||||
|
@ -1318,9 +1335,9 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
|
|
||||||
new_id = str(new_id_int).rjust(self.config['id_length'], '0')
|
new_id = str(new_id_int).rjust(self.config['id_length'], '0')
|
||||||
if do_insert:
|
if do_insert:
|
||||||
self.cur.execute('INSERT INTO id_numbers VALUES(?, ?)', [table, new_id])
|
cur.execute('INSERT INTO id_numbers VALUES(?, ?)', [table, new_id])
|
||||||
else:
|
else:
|
||||||
self.cur.execute('UPDATE id_numbers SET last_id = ? WHERE tab == ?', [new_id, table])
|
cur.execute('UPDATE id_numbers SET last_id = ? WHERE tab == ?', [new_id, table])
|
||||||
return new_id
|
return new_id
|
||||||
|
|
||||||
def get_thing_by_id(self, thing_type, thing_id):
|
def get_thing_by_id(self, thing_type, thing_id):
|
||||||
|
@ -1330,8 +1347,9 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
thing_id = thing_id.id
|
thing_id = thing_id.id
|
||||||
|
|
||||||
query = 'SELECT * FROM %s WHERE id == ?' % thing_map['table']
|
query = 'SELECT * FROM %s WHERE id == ?' % thing_map['table']
|
||||||
self.cur.execute(query, [thing_id])
|
cur = self.sql.cursor()
|
||||||
thing = self.cur.fetchone()
|
cur.execute(query, [thing_id])
|
||||||
|
thing = cur.fetchone()
|
||||||
if thing is None:
|
if thing is None:
|
||||||
return raise_no_such_thing(thing_map['exception'], thing_id=thing_id)
|
return raise_no_such_thing(thing_map['exception'], thing_id=thing_id)
|
||||||
thing = thing_map['class'](self, thing)
|
thing = thing_map['class'](self, thing)
|
||||||
|
@ -1340,12 +1358,13 @@ class PhotoDB(PDBAlbumMixin, PDBPhotoMixin, PDBTagMixin, PDBUserMixin):
|
||||||
def get_things(self, thing_type, orderby=None):
|
def get_things(self, thing_type, orderby=None):
|
||||||
thing_map = _THING_CLASSES[thing_type]
|
thing_map = _THING_CLASSES[thing_type]
|
||||||
|
|
||||||
|
cur = self.sql.cursor()
|
||||||
if orderby:
|
if orderby:
|
||||||
self.cur.execute('SELECT * FROM %s ORDER BY %s' % (thing_map['table'], orderby))
|
cur.execute('SELECT * FROM %s ORDER BY %s' % (thing_map['table'], orderby))
|
||||||
else:
|
else:
|
||||||
self.cur.execute('SELECT * FROM %s' % thing_map['table'])
|
cur.execute('SELECT * FROM %s' % thing_map['table'])
|
||||||
|
|
||||||
things = self.cur.fetchall()
|
things = cur.fetchall()
|
||||||
for thing in things:
|
for thing in things:
|
||||||
thing = thing_map['class'](self, row_tuple=thing)
|
thing = thing_map['class'](self, row_tuple=thing)
|
||||||
yield thing
|
yield thing
|
||||||
|
|
Loading…
Reference in a new issue