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 ):
"""
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:
limit_clause = " limit %s" % count
else:
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 ):
"""
@ -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 ) )
@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
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
@param search_text: text to search for within the notes
"""
# strip out all search operators
search_text = Notebook.SEARCH_OPERATORS.sub( u"", search_text ).strip()
if database_backend == Persistent.POSTGRESQL_BACKEND:
# strip out all search operators
search_text = Notebook.SEARCH_OPERATORS.sub( u"", search_text ).strip()
# join all words with boolean "and" operator
search_text = u"&".join( Notebook.WHITESPACE_PATTERN.split( search_text ) )
# join all words with boolean "and" operator
search_text = u"&".join( Notebook.WHITESPACE_PATTERN.split( search_text ) )
return \
"""
select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id, null,
headline( drop_html_tags( contents ), query ) as summary from (
return \
"""
select id, revision, title, contents, notebook_id, startup, deleted_from_id, rank, user_id, null,
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
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
note_current.*
from
note_current, user_notebook, to_tsquery( 'default', %s ) query
note_current, user_notebook
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 ) )
lower( note_current.contents ) like %s
order by note_current.notebook_id = %s desc, rank desc limit 20
""" % ( quote( user_id ), quote_fuzzy( search_text ), quote( first_notebook_id ) )
@staticmethod
def sql_search_titles( notebook_id, search_text ):
@ -220,11 +242,11 @@ class Notebook( Persistent ):
where
notebook_id = %s and
deleted_from_id is null and
title ilike %s
lower( title ) like %s
order by
revision desc limit 20;
""" % ( quote( notebook_id ),
quote_fuzzy( search_text ) )
quote_fuzzy( search_text.lower() ) )
def sql_highest_note_rank( self ):
"""

View File

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

View File

@ -2,7 +2,6 @@ import sha
import random
from copy import copy
from Persistent import Persistent, quote
from controller.Database import Database
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
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
note_size_clause = "pg_column_size( note.* )"
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 = \
"""
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.rank ) + length( note.search ) + length( note.user_id )
length( note.notebook_id ) + length( note.startup ) + length( note.user_id )
"""
return \