1515"""
1616API module/class for interacting with a design document in a database.
1717"""
18- from ._2to3 import iteritems_
18+ from ._2to3 import iteritems_ , STRTYPE
19+ from ._common_util import QUERY_LANGUAGE , codify
1920from .document import Document
2021from .view import View , QueryIndexView
2122from .error import CloudantArgumentError , CloudantException
22- from ._common_util import QUERY_LANGUAGE
2323
2424class DesignDocument (Document ):
2525 """
2626 Encapsulates a specialized version of a
2727 :class:`~cloudant.document.Document`. A DesignDocument object is
2828 instantiated with a reference to a database and
29- provides an API to view management, list and show
30- functions, search indexes, etc. When instantiating a DesignDocument or
29+ provides an API to view management, index management, list and show
30+ functions, etc. When instantiating a DesignDocument or
3131 when setting the document id (``_id``) field, the value must start with
3232 ``_design/``. If it does not, then ``_design/`` will be prepended to
3333 the provided document id value.
3434
35- Note: Currently only the view management API exists. Remaining design
36- document functionality will be added later.
35+ Note: Currently only the view management and search index management API
36+ exists. Remaining design document functionality will be added later.
3737
3838 :param database: A database instance used by the DesignDocument. Can be
3939 either a ``CouchDatabase`` or ``CloudantDatabase`` instance.
@@ -45,6 +45,7 @@ def __init__(self, database, document_id=None):
4545 document_id = '_design/{0}' .format (document_id )
4646 super (DesignDocument , self ).__init__ (database , document_id )
4747 self .setdefault ('views' , dict ())
48+ self .setdefault ('indexes' , dict ())
4849
4950 @property
5051 def views (self ):
@@ -56,6 +57,17 @@ def views(self):
5657 """
5758 return self .get ('views' )
5859
60+ @property
61+ def indexes (self ):
62+ """
63+ Provides an accessor property to the indexes dictionary in the
64+ locally cached DesignDocument.
65+
66+ :returns: Dictionary containing index names and index objects
67+ as key/value
68+ """
69+ return self .get ('indexes' )
70+
5971 def add_view (self , view_name , map_func , reduce_func = None , ** kwargs ):
6072 """
6173 Appends a MapReduce view to the locally cached DesignDocument View
@@ -79,6 +91,26 @@ def add_view(self, view_name, map_func, reduce_func=None, **kwargs):
7991 view = View (self , view_name , map_func , reduce_func , ** kwargs )
8092 self .views .__setitem__ (view_name , view )
8193
94+ def add_search_index (self , index_name , search_func , analyzer = None ):
95+ """
96+ Appends a Cloudant search index to the locally cached DesignDocument
97+ indexes dictionary.
98+
99+ :param str index_name: Name used to identify the search index.
100+ :param str search_func: Javascript search index function.
101+ :param analyzer: Optional analyzer for this search index.
102+ """
103+ if self .get_index (index_name ) is not None :
104+ msg = ('An index with name {0} already exists in this design doc'
105+ .format (index_name ))
106+ raise CloudantArgumentError (msg )
107+ if analyzer is not None :
108+ search = {'index' : codify (search_func ), 'analyzer' : analyzer }
109+ else :
110+ search = {'index' : codify (search_func )}
111+
112+ self .indexes .__setitem__ (index_name , search )
113+
82114 def update_view (self , view_name , map_func , reduce_func = None , ** kwargs ):
83115 """
84116 Modifies/overwrites an existing MapReduce view definition in the
@@ -104,6 +136,27 @@ def update_view(self, view_name, map_func, reduce_func=None, **kwargs):
104136 view = View (self , view_name , map_func , reduce_func , ** kwargs )
105137 self .views .__setitem__ (view_name , view )
106138
139+ def update_search_index (self , index_name , search_func , analyzer = None ):
140+ """
141+ Modifies/overwrites an existing Cloudant search index in the
142+ locally cached DesignDocument indexes dictionary.
143+
144+ :param str index_name: Name used to identify the search index.
145+ :param str search_func: Javascript search index function.
146+ :param analyzer: Optional analyzer for this search index.
147+ """
148+ search = self .get_index (index_name )
149+ if search is None :
150+ msg = ('An index with name {0} does not exist in this design doc'
151+ .format (index_name ))
152+ raise CloudantArgumentError (msg )
153+ if analyzer is not None :
154+ search = {'index' : codify (search_func ), 'analyzer' : analyzer }
155+ else :
156+ search = {'index' : codify (search_func )}
157+
158+ self .indexes .__setitem__ (index_name , search )
159+
107160 def delete_view (self , view_name ):
108161 """
109162 Removes an existing MapReduce view definition from the locally cached
@@ -123,6 +176,19 @@ def delete_view(self, view_name):
123176
124177 self .views .__delitem__ (view_name )
125178
179+ def delete_index (self , index_name ):
180+ """
181+ Removes an existing index in the locally cached DesignDocument
182+ indexes dictionary.
183+
184+ :param str index_name: Name used to identify the index.
185+ """
186+ index = self .get_index (index_name )
187+ if index is None :
188+ return
189+
190+ self .indexes .__delitem__ (index_name )
191+
126192 def fetch (self ):
127193 """
128194 Retrieves the remote design document content and populates the locally
@@ -154,6 +220,11 @@ def fetch(self):
154220 ** view_def
155221 )
156222
223+ if not self .indexes :
224+ # Ensure indexes dict exists in locally cached DesignDocument.
225+ self .setdefault ('indexes' , dict ())
226+
227+ # pylint: disable-msg=too-many-branches
157228 def save (self ):
158229 """
159230 Saves changes made to the locally cached DesignDocument object's data
@@ -180,11 +251,36 @@ def save(self):
180251 # Ensure empty views dict is not saved remotely.
181252 self .__delitem__ ('views' )
182253
254+ if self .indexes :
255+ if self .get ('language' , None ) != QUERY_LANGUAGE :
256+ for index_name , search in self .iterindexes ():
257+ # Check the instance of the javascript search function
258+ if not isinstance (search ['index' ], STRTYPE ):
259+ msg = (
260+ 'Function for search index {0} must '
261+ 'be of type string.'
262+ ).format (index_name )
263+ raise CloudantException (msg )
264+ else :
265+ for index_name , index in self .iterindexes ():
266+ if not isinstance (index ['index' ], dict ):
267+ msg = (
268+ 'Definition for query text index {0} must '
269+ 'be of type dict.'
270+ ).format (index_name )
271+ raise CloudantException (msg )
272+ else :
273+ # Ensure empty indexes dict is not saved remotely.
274+ self .__delitem__ ('indexes' )
275+
183276 super (DesignDocument , self ).save ()
184277
185278 if not self .views :
186279 # Ensure views dict exists in locally cached DesignDocument.
187280 self .setdefault ('views' , dict ())
281+ if not self .indexes :
282+ # Ensure indexes dict exists in locally cached DesignDocument.
283+ self .setdefault ('indexes' , dict ())
188284
189285 def __setitem__ (self , key , value ):
190286 """
@@ -216,6 +312,24 @@ def iterviews(self):
216312 for view_name , view in iteritems_ (self .views ):
217313 yield view_name , view
218314
315+ def iterindexes (self ):
316+ """
317+ Provides a way to iterate over the locally cached DesignDocument
318+ indexes dictionary.
319+
320+ For example:
321+
322+ .. code-block:: python
323+
324+ for index_name, search_func in ddoc.iterindexes():
325+ # Perform search index processing
326+
327+ :returns: Iterable containing index name and associated
328+ index object
329+ """
330+ for index_name , search_func in iteritems_ (self .indexes ):
331+ yield index_name , search_func
332+
219333 def list_views (self ):
220334 """
221335 Retrieves a list of available View objects in the locally cached
@@ -225,6 +339,15 @@ def list_views(self):
225339 """
226340 return list (self .views .keys ())
227341
342+ def list_indexes (self ):
343+ """
344+ Retrieves a list of available indexes in the locally cached
345+ DesignDocument.
346+
347+ :returns: List of index names
348+ """
349+ return list (self .indexes .keys ())
350+
228351 def get_view (self , view_name ):
229352 """
230353 Retrieves a specific View from the locally cached DesignDocument by
@@ -236,6 +359,17 @@ def get_view(self, view_name):
236359 """
237360 return self .views .get (view_name )
238361
362+ def get_index (self , index_name ):
363+ """
364+ Retrieves a specific index from the locally cached DesignDocument
365+ indexes dictionary by name.
366+
367+ :param str index_name: Name used to identify the index.
368+
369+ :returns: Index dictionary for the specified index name
370+ """
371+ return self .indexes .get (index_name )
372+
239373 def info (self ):
240374 """
241375 Retrieves the design document view information data, returns dictionary
0 commit comments