Updating the SongsManager to use SQLAlchemy

bzr-revno: 284
This commit is contained in:
Raoul Snyman 2009-01-17 13:58:16 +00:00
parent 7022a05316
commit 11bede8fd8
8 changed files with 113 additions and 207 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd"> <!DOCTYPE UserProject SYSTEM "UserProject-4.0.dtd">
<!-- eric4 user project file for project openlp.org 2.0 --> <!-- eric4 user project file for project openlp.org 2.0 -->
<!-- Saved: 2009-01-03, 01:14:22 --> <!-- Saved: 2009-01-17, 13:06:08 -->
<!-- Copyright (C) 2009 Raoul Snyman, raoulsnyman@openlp.org --> <!-- Copyright (C) 2009 Raoul Snyman, raoulsnyman@openlp.org -->
<UserProject version="4.0"> <UserProject version="4.0">
</UserProject> </UserProject>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Tasks SYSTEM "Tasks-4.2.dtd"> <!DOCTYPE Tasks SYSTEM "Tasks-4.2.dtd">
<!-- eric4 tasks file for project openlp.org 2.0 --> <!-- eric4 tasks file for project openlp.org 2.0 -->
<!-- Saved: 2009-01-03, 01:14:23 --> <!-- Saved: 2009-01-17, 13:06:08 -->
<Tasks version="4.2"> <Tasks version="4.2">
<Task priority="1" completed="False" bugfix="False"> <Task priority="1" completed="False" bugfix="False">
<Summary>TODO: what is the tags for bridge, pre-chorus?</Summary> <Summary>TODO: what is the tags for bridge, pre-chorus?</Summary>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-4.4.dtd"> <!DOCTYPE Project SYSTEM "Project-4.4.dtd">
<!-- eric4 project file for project openlp.org 2.0 --> <!-- eric4 project file for project openlp.org 2.0 -->
<!-- Saved: 2009-01-03, 01:14:22 --> <!-- Saved: 2009-01-17, 13:05:58 -->
<!-- Copyright (C) 2009 Raoul Snyman, raoulsnyman@openlp.org --> <!-- Copyright (C) 2009 Raoul Snyman, raoulsnyman@openlp.org -->
<Project version="4.4"> <Project version="4.4">
<ProgLanguage mixed="0">Python</ProgLanguage> <ProgLanguage mixed="0">Python</ProgLanguage>
@ -65,9 +65,7 @@
<Source>openlp/core/test/testplugins/testplugin2/testplugin2.py</Source> <Source>openlp/core/test/testplugins/testplugin2/testplugin2.py</Source>
<Source>openlp/plugins/bibles/bibleplugin.py</Source> <Source>openlp/plugins/bibles/bibleplugin.py</Source>
<Source>openlp/plugins/bibles/forms/bibleimportdialog.py</Source> <Source>openlp/plugins/bibles/forms/bibleimportdialog.py</Source>
<Source>openlp/plugins/bibles/forms/bibleimportprogressform.py</Source>
<Source>openlp/plugins/bibles/forms/bibleimportform.py</Source> <Source>openlp/plugins/bibles/forms/bibleimportform.py</Source>
<Source>openlp/plugins/bibles/forms/bibleimportprogressdialog.py</Source>
<Source>openlp/plugins/bibles/lib/biblemanager.py</Source> <Source>openlp/plugins/bibles/lib/biblemanager.py</Source>
<Source>openlp/plugins/bibles/lib/bibleDBimpl.py</Source> <Source>openlp/plugins/bibles/lib/bibleDBimpl.py</Source>
<Source>openlp/plugins/bibles/lib/bibleOSISimpl.py</Source> <Source>openlp/plugins/bibles/lib/bibleOSISimpl.py</Source>
@ -113,6 +111,8 @@
<Source>openlp/migration/migratesongs.py</Source> <Source>openlp/migration/migratesongs.py</Source>
<Source>openlp/migration/display.py</Source> <Source>openlp/migration/display.py</Source>
<Source>openlp/migration/migratebibles.py</Source> <Source>openlp/migration/migratebibles.py</Source>
<Source>openlp/plugins/songs/lib/songclasses.py</Source>
<Source>openlp/plugins/songs/lib/songtables.py</Source>
</Sources> </Sources>
<Forms> <Forms>
<Form>resources/forms/openlpexportform.ui</Form> <Form>resources/forms/openlpexportform.ui</Form>

View File

@ -27,7 +27,7 @@ from songbookform import SongBookForm
from editsongdialog import Ui_EditSongDialog from editsongdialog import Ui_EditSongDialog
from openlp.plugins.songs.lib.songtable import * from openlp.plugins.songs.lib.models import Session, Song, Author, Topic
class EditSongForm(QWidget, Ui_EditSongDialog): class EditSongForm(QWidget, Ui_EditSongDialog):
""" """
@ -42,18 +42,18 @@ class EditSongForm(QWidget, Ui_EditSongDialog):
self.songmanager = songmanager self.songmanager = songmanager
self.authors_form = AuthorsForm(self.songmanager) self.authors_form = AuthorsForm(self.songmanager)
self.topics_form = TopicsForm(self.songmanager) self.topics_form = TopicsForm(self.songmanager)
self.song_book_form = SongBookForm(self.songmanager) self.song_book_form = SongBookForm(self.songmanager)
self.initialise() self.initialise()
self.AuthorsListView.setColumnCount(2) self.AuthorsListView.setColumnCount(2)
self.AuthorsListView.setColumnHidden(0, True) self.AuthorsListView.setColumnHidden(0, True)
self.AuthorsListView.setColumnWidth(1, 200) self.AuthorsListView.setColumnWidth(1, 200)
self.AuthorsListView.setShowGrid(False) self.AuthorsListView.setShowGrid(False)
self.AuthorsListView.setSortingEnabled(False) self.AuthorsListView.setSortingEnabled(False)
self.AuthorsListView.setAlternatingRowColors(True) self.AuthorsListView.setAlternatingRowColors(True)
self.savebutton = self.ButtonBox.button(QtGui.QDialogButtonBox.Save) self.savebutton = self.ButtonBox.button(QtGui.QDialogButtonBox.Save)
def initialise(self): def initialise(self):
list = self.songmanager.get_authors() list = self.songmanager.get_authors()
self.AuthorsSelectionComboItem.clear() self.AuthorsSelectionComboItem.clear()
@ -66,23 +66,23 @@ class EditSongForm(QWidget, Ui_EditSongDialog):
else: else:
self.songid = songid self.songid = songid
self.song = self.songmanager.get_song(songid) self.song = self.songmanager.get_song(songid)
self.TitleEditItem.setText(self.song.title) self.TitleEditItem.setText(self.song.title)
self.LyricsTextEdit.setText(self.song.lyrics) self.LyricsTextEdit.setText(self.song.lyrics)
self.CopyrightEditItem.setText(self.song.copyright) self.CopyrightEditItem.setText(self.song.copyright)
self.AuthorsListView.clear() # clear the results self.AuthorsListView.clear() # clear the results
self.AuthorsListView.setHorizontalHeaderLabels(QtCore.QStringList(["","Author"])) self.AuthorsListView.setHorizontalHeaderLabels(QtCore.QStringList(["","Author"]))
self.AuthorsListView.setVerticalHeaderLabels(QtCore.QStringList([""])) self.AuthorsListView.setVerticalHeaderLabels(QtCore.QStringList([""]))
self.AuthorsListView.setRowCount(0) self.AuthorsListView.setRowCount(0)
for author in self.song.authors: for author in self.song.authors:
c = self.AuthorsListView.rowCount() c = self.AuthorsListView.rowCount()
self.AuthorsListView.setRowCount(c+1) self.AuthorsListView.setRowCount(c+1)
twi = QtGui.QTableWidgetItem(str(author.id)) twi = QtGui.QTableWidgetItem(str(author.id))
self.AuthorsListView.setItem(c , 0, twi) self.AuthorsListView.setItem(c , 0, twi)
twi = QtGui.QTableWidgetItem(str(author.display_name)) twi = QtGui.QTableWidgetItem(str(author.display_name))
self.AuthorsListView.setItem(c , 1, twi) self.AuthorsListView.setItem(c , 1, twi)
self.AuthorsListView.setRowHeight(c, 20) self.AuthorsListView.setRowHeight(c, 20)
self._validate_song() self._validate_song()
@pyqtSignature("") @pyqtSignature("")
def on_AddAuthorsButton_clicked(self): def on_AddAuthorsButton_clicked(self):
@ -90,7 +90,7 @@ class EditSongForm(QWidget, Ui_EditSongDialog):
Slot documentation goes here. Slot documentation goes here.
""" """
self.authors_form.load_form() self.authors_form.load_form()
self.authors_form.show() self.authors_form.show()
@pyqtSignature("") @pyqtSignature("")
def on_AddTopicButton_clicked(self): def on_AddTopicButton_clicked(self):
@ -100,18 +100,18 @@ class EditSongForm(QWidget, Ui_EditSongDialog):
self.topics_form.load_form() self.topics_form.load_form()
self.topics_form.show() self.topics_form.show()
@pyqtSignature("") @pyqtSignature("")
def on_AddSongBookButton_clicked(self): def on_AddSongBookButton_clicked(self):
""" """
Slot documentation goes here. Slot documentation goes here.
""" """
self.song_book_form.load_form() self.song_book_form.load_form()
self.song_book_form.show() self.song_book_form.show()
def _validate_song(self): def _validate_song(self):
""" """
Check the validity of the form. Only display the 'save' if the data can be saved. Check the validity of the form. Only display the 'save' if the data can be saved.
""" """
valid = True # Lets be nice and assume the data is correct. valid = True # Lets be nice and assume the data is correct.
if len(self.TitleEditItem.displayText()) == 0: #Song title missing if len(self.TitleEditItem.displayText()) == 0: #Song title missing
valid = False valid = False
@ -122,23 +122,23 @@ class EditSongForm(QWidget, Ui_EditSongDialog):
valid = False valid = False
self._color_widget(self.CopyrightEditItem, True) self._color_widget(self.CopyrightEditItem, True)
else: else:
self._color_widget(self.CopyrightEditItem, False) self._color_widget(self.CopyrightEditItem, False)
if valid: if valid:
self.ButtonBox.addButton(self.savebutton, QtGui.QDialogButtonBox.AcceptRole) # hide the save button tile screen is valid self.ButtonBox.addButton(self.savebutton, QtGui.QDialogButtonBox.AcceptRole) # hide the save button tile screen is valid
else: else:
self.ButtonBox.removeButton(self.savebutton) # hide the save button tile screen is valid self.ButtonBox.removeButton(self.savebutton) # hide the save button tile screen is valid
def _color_widget(self, slot, invalid): def _color_widget(self, slot, invalid):
r = Qt.QPalette(slot.palette()) r = Qt.QPalette(slot.palette())
if invalid == True: if invalid == True:
r.setColor(Qt.QPalette.Base, Qt.QColor('darkRed')) r.setColor(Qt.QPalette.Base, Qt.QColor('darkRed'))
else: else:
r.setColor(Qt.QPalette.Base, Qt.QColor('white')) r.setColor(Qt.QPalette.Base, Qt.QColor('white'))
slot.setPalette(r) slot.setPalette(r)
slot.setAutoFillBackground(True) slot.setAutoFillBackground(True)
def on_TitleEditItem_lostFocus(self): def on_TitleEditItem_lostFocus(self):
self._validate_song() self._validate_song()
def on_CopyrightEditItem_lostFocus(self): def on_CopyrightEditItem_lostFocus(self):
self._validate_song() self._validate_song()

View File

@ -23,10 +23,10 @@ from sqlalchemy.orm import scoped_session, sessionmaker, mapper, relation
from openlp.plugins.songs.lib.tables import * from openlp.plugins.songs.lib.tables import *
from openlp.plugins.songs.lib.classes import * from openlp.plugins.songs.lib.classes import *
Session = None session = None
def init_models(url): def init_models(url):
Session = scoped_session(sessionmaker(autoflush=True, autocommit=False, session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=create_engine(url))) bind=create_engine(url)))

View File

@ -21,215 +21,121 @@ Place, Suite 330, Boston, MA 02111-1307 USA
import os, os.path import os, os.path
import sys import sys
from songDBimpl import SongDBImpl from sqlalchemy.orm import asc, desc, like
from openlp.plugins.songs.lib.models import init_models, metadata, session, \
songs_table, Song, Author, Topic
import logging import logging
class SongManager(): class SongManager():
"""
The Song Manager provides a central location for all database code. This
class takes care of connecting to the database and running all the queries.
"""
global log global log
log=logging.getLogger("SongManager") log=logging.getLogger("SongManager")
log.info("Song manager loaded") log.info("Song manager loaded")
def __init__(self, config): def __init__(self, config):
""" """
Finds all the bibles defined for the system Creates the connection to the database, and creates the tables if they
Creates an Interface Object for each bible containing connection information don't exist.
Throws Exception if no Bibles are found.
Init confirms the bible exists and stores the database path.
""" """
self.config = config self.config = config
log.debug( "Song Initialising") log.debug( "Song Initialising")
self.songDBCache = None self.db_url = u''
self.authorcache = None db_type = self.config.get_db_type()
self.songPath = self.config.get_data_path() if db_type == u'sqlite':
self.songSuffix = "sqlite" self.db_url = u'sqlite://' + self.config.get_data_path() + \
log.debug("Song Path %s and suffix %s", self.songPath, self.songSuffix ) u'songs.sqlite'
self.dialogobject = None else:
self.db_url = self.config.get_db_type + 'u://' + \
files = self.config.get_files(self.songSuffix) self.config.get_db_username + u':' + \
if len(files) > 0: self.config.get_db_password + u'@' + \
log.debug("Song File %s", files ) self.config.get_db_hostname + u'/' + \
self.songDBCache = SongDBImpl(self.songPath,files[0], self.songSuffix) self.config.get_db_database
ini_models(self.db_url)
if not songs_table.exists():
metadata.create_all()
log.debug( "Song Initialised") log.debug( "Song Initialised")
def have_song_database(self):
if self.songDBCache == None:
return False
return True
def process_dialog(self, dialogobject): def process_dialog(self, dialogobject):
self.dialogobject = dialogobject self.dialogobject = dialogobject
def get_song(self, songid): def get_songs(self):
""" """
Returns the details of a song Returns the details of a song
""" """
return self.songDBCache.get_song(songid) return session.query(Song).order_by(title).all()
def get_authors(self, reload=False): def search_song_title(self, keywords):
"""
Searches the song title for keywords.
"""
return session.query(Song).filter(search_title.like(u'%' + keywords + u'%'))
def search_song_lyrics(self, keywords):
"""
Searches the song lyrics for keywords.
"""
return session.query(Song).filter(search_lyrics.like(u'%' + keywords + u'%'))
def get_song(self, id):
"""
Returns the details of a song
"""
return session.query(Song).get(id)
def save_song(self, song):
"""
Saves a song to the database
"""
try:
session.add(song)
session.commit()
return True
except:
return False
def delete_song(self, song):
try:
session.delete(song)
session.commit()
return True
except:
return False
def get_authors(self):
""" """
Returns a list of all the authors Returns a list of all the authors
""" """
if self.authorcache == None or reload == True: return session.query(Author).order_by(display_name).all()
self.authorcache = self.songDBCache.get_authors()
return self.authorcache def get_author(self, id):
def get_author(self, authorid):
""" """
Details of the Author Details of the Author
""" """
return self.songDBCache.get_author(authorid) return session.query(Author).get(id)
def save_author(self, author): def save_author(self, author):
""" """
Save the Author and refresh the cache Save the Author and refresh the cache
""" """
self.songDBCache.save_author(author) try:
self.get_authors(True) # Updates occured refresh the cache session.add(author)
return True session.commit()
return True
except:
return False
def delete_author(self, authorid): def delete_author(self, authorid):
""" """
Delete the author and refresh the author cache Delete the author and refresh the author cache
""" """
self.songDBCache.delete_author(authorid) try:
self.get_authors(True) # Updates occured refresh the cache session.delete(author)
return True session.commit()
return True
def get_song_authors_for_author(self, authorid): except:
""" return False
Returns the details of a song
"""
return self.songDBCache.get_song_authors_for_author(authorid)
def get_song_authors_for_song(self, songid):
"""
Returns the details of a song
"""
return self.songDBCache.get_song_authors_for_song(songid)
def get_bible_books(self,bible):
"""
Returns a list of the books of the bible from the database
"""
log.debug("get_bible_books %s", bible)
return self.bibleDBCache[bible].get_bible_books()
def get_book_chapter_count(self, bible, book):
"""
Returns the number of Chapters for a given book
"""
log.debug( "get_book_chapter_count %s,%s", bible, book)
return self.bibleDBCache[bible].get_max_bible_book_chapter(book)
def get_book_verse_count(self, bible, book, chapter):
"""
Returns all the number of verses for a given
book and chapterMaxBibleBookVerses
"""
log.debug( "get_book_verse_count %s,%s,%s", bible, book, chapter)
return self.bibleDBCache[bible].get_max_bible_book_verses(book, chapter)
def get_verse_from_text(self, bible, versetext):
"""
Returns all the number of verses for a given
book and chapterMaxBibleBookVerses
"""
log.debug( "get_verses_from_text %s,%s", bible, versetext)
return self.bibleDBCache[bible].get_verses_from_text(versetext)
def save_meta_data(self, bible, version, copyright, permissions):
"""
Saves the bibles meta data
"""
log.debug( "save_meta %s,%s, %s,%s", bible, version, copyright, permissions)
self.bibleDBCache[bible].save_meta("Version", version)
self.bibleDBCache[bible].save_meta("Copyright", copyright)
self.bibleDBCache[bible].save_meta("Permissins", permissions)
def get_meta_data(self, bible, key):
"""
Returns the meta data for a given key
"""
log.debug( "get_meta %s,%s", bible, key)
self.bibleDBCache[bible].get_meta(key)
def get_verse_text(self, bible, bookname, schapter, echapter, sverse, everse = 0 ):
"""
Returns a list of verses for a given Book, Chapter and ranges of verses.
If the end verse(everse) is less then the start verse(sverse)
then only one verse is returned
bible - Which bible to use.
Rest can be guessed at !
"""
text = []
#log.debug( self.bibleDBCache)
#log.debug( self.bibleHTTPCache)
log.debug( "get_verse_text %s,%s,%s,%s,%s,%s", bible,bookname, schapter,echapter, sverse, everse)
# bookid = self.booksOfBible[bookname] # convert to id ie Genesis --> 1 Revelation --> 73
# # SORT OUT BOOKNAME BOOK ID.
# # NAME COMES IN TO ID AND BACK TO NAME ?
# c = self.bibleDBCache[bible].getBibleChapter(bookname, chapter) # check to see if book/chapter exists
# bookabbrev = ""
# log.debug( "Bible Chapter %s", c )
# if not c:
# self._loadBook(bible,bookid, bookname, bookabbrev)
# self._loadChapter(bible, bookid,bookname, chapter)
if schapter == echapter:
text = self.bibleDBCache[bible].get_bible_text(bookname, schapter, sverse, everse)
else:
for i in range (schapter, echapter + 1):
if i == schapter:
start = sverse
end = self.get_book_verse_count(bible, bookname,i )[0]
elif i == echapter:
start = 1
end = everse
else:
start = 1
end = self.get_book_verse_count(bible, bookname,i )[0]
txt = self.bibleDBCache[bible].get_bible_text(bookname, i, start, end)
text.extend(txt)
return text
def _load_book(self, bible, bookid, bookname, bookabbrev):
log.debug( "load_book %s,%s,%s,%s", bible, bookid, bookname, bookabbrev)
cl = self.bibleDBCache[bible].get_bible_book(bookname)
log.debug( "get bible book %s" , cl)
if not cl :
self.bibleDBCache[bible].create_book(bookid, bookname, bookabbrev)
def _loadChapter(self, bible, bookid, bookname, chapter):
log.debug( "load_chapter %s,%s,%s,%s", bible, bookid,bookname, chapter)
try :
chaptlist = self.bibleHTTPCache[bible].get_bible_chapter(bible, bookid,bookname, chapter)
self.bibleDBCache[bible].create_chapter(bookname, chapter, chaptlist)
except :
log.error("Errow thrown %s", sys.exc_info()[1])
def _is_new_bible(self, name):
"""
Check cache to see if new bible
"""
for b , o in self.bibleDBCache.iteritems():
log.debug( b )
if b == name :
return False
return True
def get_song_from_title(self,searchtext):
log.debug("get song from title %s", searchtext)
return self.songDBCache.get_song_from_title(searchtext)
def get_song_from_lyrics(self,searchtext):
log.debug("get song from lyrics %s", searchtext)
return self.songDBCache.get_song_from_lyrics(searchtext)
def get_song_from_author(self,searchtext):
log.debug("get song from author %s", searchtext)
return self.songDBCache.get_song_from_author(searchtext)
def dump_songs(self):
self.songDBCache.dump_songs()