witten
/
luminotes
Archived
1
0
Fork 0

Added basic note searching for SQLite. Should really be using SQLite's full-text search instead.

In sql_load_notes, no longer adding offset clause if start = 0 since SQLite doesn't like offset without limit.
Switched from using "ilike" to "like" with lower(), since "ilike" is a PostgreSQL-specific extension.
Moved BACKEND flags from Database to Persistent to prevent need from circular imports (model files importing controller.Database).
This commit is contained in:
Dan Helfman 2008-08-19 17:48:33 -07:00
parent 73219b74ce
commit 410f6f8cbf
3 changed files with 49 additions and 25 deletions

View File

@ -103,13 +103,20 @@ class Notebook( Persistent ):
def sql_load_notes( self, start = 0, count = None ): def sql_load_notes( self, start = 0, count = None ):
""" """
Return a SQL string to load a list of all the notes within this notebook. Return a SQL string to load a list of all the notes within this notebook.
Note: If the database backend is SQLite, a start parameter cannot be given without also
providing a count parameter.
""" """
if count is not None: if count is not None:
limit_clause = " limit %s" % count limit_clause = " limit %s" % count
else: else:
limit_clause = "" limit_clause = ""
return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where notebook_id = %s order by revision desc%s offset %s;" % ( quote( self.object_id ), limit_clause, start ) if start:
offset_clause = " offset %s" % start
else:
offset_clause = ""
return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where notebook_id = %s order by revision desc%s%s;" % ( quote( self.object_id ), limit_clause, offset_clause )
def sql_load_non_startup_notes( self ): def sql_load_non_startup_notes( self ):
""" """
@ -168,7 +175,7 @@ class Notebook( Persistent ):
return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where notebook_id = %s and lower( title ) = lower( %s );" % ( quote( self.object_id ), quote( title ) ) return "select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id from note_current where notebook_id = %s and lower( title ) = lower( %s );" % ( quote( self.object_id ), quote( title ) )
@staticmethod @staticmethod
def sql_search_notes( user_id, first_notebook_id, search_text ): def sql_search_notes( user_id, first_notebook_id, search_text, database_backend ):
""" """
Return a SQL string to perform a full-text search for notes within notebooks readable by the Return a SQL string to perform a full-text search for notes within notebooks readable by the
given user whose contents contain the given search_text. This is a case-insensitive search. given user whose contents contain the given search_text. This is a case-insensitive search.
@ -176,29 +183,44 @@ class Notebook( Persistent ):
@type search_text: unicode @type search_text: unicode
@param search_text: text to search for within the notes @param search_text: text to search for within the notes
""" """
# strip out all search operators if database_backend == Persistent.POSTGRESQL_BACKEND:
search_text = Notebook.SEARCH_OPERATORS.sub( u"", search_text ).strip() # strip out all search operators
search_text = Notebook.SEARCH_OPERATORS.sub( u"", search_text ).strip()
# join all words with boolean "and" operator # join all words with boolean "and" operator
search_text = u"&".join( Notebook.WHITESPACE_PATTERN.split( search_text ) ) search_text = u"&".join( Notebook.WHITESPACE_PATTERN.split( search_text ) )
return \ return \
""" """
select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id, null, select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id, null,
headline( drop_html_tags( contents ), query ) as summary from ( headline( drop_html_tags( contents ), query ) as summary from (
select
note_current.id, note_current.revision, note_current.title, note_current.contents,
note_current.notebook_id, note_current.startup, note_current.deleted_from_id,
rank_cd( search, query ) as rank, note_current.user_id, null, query
from
note_current, user_notebook, to_tsquery( 'default', %s ) query
where
note_current.notebook_id = user_notebook.notebook_id and user_notebook.user_id = %s and
note_current.deleted_from_id is null and
query @@ search order by note_current.notebook_id = %s desc, rank desc limit 20
) as sub;
""" % ( quote( search_text ), quote( user_id ),
quote( first_notebook_id ) )
else:
# TODO: use SQLite's FTS (full text search) support instead
return \
"""
select select
note_current.id, note_current.revision, note_current.title, note_current.contents, note_current.*
note_current.notebook_id, note_current.startup, note_current.deleted_from_id,
rank_cd( search, query ) as rank, note_current.user_id, null, query
from from
note_current, user_notebook, to_tsquery( 'default', %s ) query note_current, user_notebook
where where
note_current.notebook_id = user_notebook.notebook_id and user_notebook.user_id = %s and note_current.notebook_id = user_notebook.notebook_id and user_notebook.user_id = %s and
note_current.deleted_from_id is null and note_current.deleted_from_id is null and
query @@ search order by note_current.notebook_id = %s desc, rank desc limit 20 lower( note_current.contents ) like %s
) as sub; order by note_current.notebook_id = %s desc, rank desc limit 20
""" % ( quote( search_text ), quote( user_id ), """ % ( quote( user_id ), quote_fuzzy( search_text ), quote( first_notebook_id ) )
quote( first_notebook_id ) )
@staticmethod @staticmethod
def sql_search_titles( notebook_id, search_text ): def sql_search_titles( notebook_id, search_text ):
@ -220,11 +242,11 @@ class Notebook( Persistent ):
where where
notebook_id = %s and notebook_id = %s and
deleted_from_id is null and deleted_from_id is null and
title ilike %s lower( title ) like %s
order by order by
revision desc limit 20; revision desc limit 20;
""" % ( quote( notebook_id ), """ % ( quote( notebook_id ),
quote_fuzzy( search_text ) ) quote_fuzzy( search_text.lower() ) )
def sql_highest_note_rank( self ): def sql_highest_note_rank( self ):
""" """

View File

@ -3,6 +3,9 @@ from pytz import utc
class Persistent( object ): class Persistent( object ):
POSTGRESQL_BACKEND = 0
SQLITE_BACKEND = 1
""" """
A persistent database object with a unique id. A persistent database object with a unique id.
""" """

View File

@ -2,7 +2,6 @@ import sha
import random import random
from copy import copy from copy import copy
from Persistent import Persistent, quote from Persistent import Persistent, quote
from controller.Database import Database
class User( Persistent ): class User( Persistent ):
@ -303,16 +302,16 @@ class User( Persistent ):
storage for all the user's notes (including past revisions) and their uploaded files. It does storage for all the user's notes (including past revisions) and their uploaded files. It does
not include storage for the notebooks themselves. not include storage for the notebooks themselves.
""" """
if database_backend == Database.POSTGRESQL_BACKEND: if database_backend == Persistent.POSTGRESQL_BACKEND:
# this counts bytes for the contents of each column # this counts bytes for the contents of each column
note_size_clause = "pg_column_size( note.* )" note_size_clause = "pg_column_size( note.* )"
else: else:
# this isn't perfect, because length() counts UTF-8 characters instead of bytes # this isn't perfect, because length() counts UTF-8 characters instead of bytes.
# some columns are left out because they can be null, which screws up the addition
note_size_clause = \ note_size_clause = \
""" """
length( note.id ) + length( note.revision ) + length( note.title ) + length( note.contents ) + length( note.id ) + length( note.revision ) + length( note.title ) + length( note.contents ) +
length( note.notebook_id ) + length( note.startup ) + length( note.deleted_from_id ) + length( note.notebook_id ) + length( note.startup ) + length( note.user_id )
length( note.rank ) + length( note.search ) + length( note.user_id )
""" """
return \ return \