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:
parent
73219b74ce
commit
410f6f8cbf
|
@ -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 ):
|
||||
"""
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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 \
|
||||
|
|
Reference in New Issue