Check-in [f2db928450]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Updated morglib.database documentation.
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA1: f2db9284504411616c4627609ae534f4438a4114
User & Date: mvnathan 2014-09-18 21:07:15.581
Context
2014-09-18
21:13
Use between operator for numeric property range constraints instead of the relational operators. check-in: 0caa6b62ab user: mvnathan tags: dev
21:07
Updated morglib.database documentation. check-in: f2db928450 user: mvnathan tags: dev
06:29
Implemented database sanity check. check-in: 4c162d2c43 user: mvnathan tags: dev
Changes
Unified Diff Ignore Whitespace Patch
Changes to py/morglib/database.py.
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        @param reason (any) Additional information about connection failure.

        Typically, reason will be a string explaining the problem with
        the tasks file. However, this parameter can be any object and
        will, via the base class constructor, be converted to a string.

        '''
        msg = '{} is not a Morg database'.format(tasks_file)
        database_error.__init__(self, msg, reason)

class sql_error(database_error):
    '''For reporting inability to execute SQL queries.'''

    def __init__(self, query, reason = None):
        '''Construct SQL error.







|







102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
        @param reason (any) Additional information about connection failure.

        Typically, reason will be a string explaining the problem with
        the tasks file. However, this parameter can be any object and
        will, via the base class constructor, be converted to a string.

        '''
        msg = 'cannot use database {}'.format(tasks_file)
        database_error.__init__(self, msg, reason)

class sql_error(database_error):
    '''For reporting inability to execute SQL queries.'''

    def __init__(self, query, reason = None):
        '''Construct SQL error.
147
148
149
150
151
152
153
154











155
156
157
158
159
160
161
        msg = ('property error: name = "{}", type = {}, range = {}'.
               format(n, t, r))
        database_error.__init__(self, msg, e)

#--------------------------- TASKS DATABASE -----------------------------

class database:
    '''Encapsulation of interface to Morg tasks database.'''












    # Substantial changes to the structure of the Morg database should be
    # accompanied by increments to the following version number.
    SCHEMA_VERSION = 1

    # Hard-coded string to help identify whether an SQLite file is a Morg
    # database or not.







|
>
>
>
>
>
>
>
>
>
>
>







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
        msg = ('property error: name = "{}", type = {}, range = {}'.
               format(n, t, r))
        database_error.__init__(self, msg, e)

#--------------------------- TASKS DATABASE -----------------------------

class database:
    '''Encapsulation of interface to Morg tasks database.

    This class provides clients a high-level API for dealing with the
    Morg database. With it, you can add and remove tasks and properties
    and even execute arbitrary SQL queries.

    The Morg application instantiates this class early on and then passes
    that object to all <tt>morglib.command</tt> instances to allow them
    to easily implement their respective functionalities by manipulating
    the Morg database as required.

    '''

    # Substantial changes to the structure of the Morg database should be
    # accompanied by increments to the following version number.
    SCHEMA_VERSION = 1

    # Hard-coded string to help identify whether an SQLite file is a Morg
    # database or not.
173
174
175
176
177
178
179
180


181





182




183





184


















185
186
187
188


189

190
191
192
193
194
195
196
197
198
199
200
201
202
203
        creating the entire directory hierarchy specified in the
        tasks_file parameter).

        Failure to open the SQLite file will result in a connection_error
        exception.

        Once the database has been successfully opened, the constructor
        will proceed to check if the database is empty and, if so, create


        the basic structure required by Morg. Part of that structure is a





        table named <tt>property</tt>, which contains the definitions of




        the initial set of task properties defined by Morg.
























        These initial properties are specified via the properties
        parameter, which is a dict that maps strings to 2-tuples. The key
        is the name of a property. The 2-tuple corresponding to the
        property name contains the property type and its range. The


        property type can be one of the following strings:


        @li <tt>integer</tt>
        @li <tt>real</tt>
        @li <tt>text</tt>

        Case does not matter.

        The property range may be either <tt>None</tt> or a string
        describing the range of values that particular property may take
        on. Commas can be used to separate items in a list of discrete
        values. Double dots can be used for numeric ranges. Here are a
        few illustrative examples:

        @verbatim







|
>
>
|
>
>
>
>
>
|
>
>
>
>
|
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|
|
>
>
|
>





<
<







184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242


243
244
245
246
247
248
249
        creating the entire directory hierarchy specified in the
        tasks_file parameter).

        Failure to open the SQLite file will result in a connection_error
        exception.

        Once the database has been successfully opened, the constructor
        will proceed to check if the database is empty or not. In an
        empty database, Morg will create a watermark table so that it can
        subsequently identify that SQLite file as one that it can use.

        Failure to create the watermark table will usually lead to a
        sql_error. However, to populate the watermark table, Morg uses
        the current time, host name, user name, and an SHA-1 hex string.
        Thus, depending on exactly which of these steps fails, some other
        exception may also be raised. (Though that should be quite rare.)

        If the database is not empty, Morg will perform a sanity check
        using the watermark table to see if the database to which it is
        connected was its creation and, therefore, usable by it. If that
        is not the case, the constructor will raise a sanity_check_error.

        Please note that the watermark system Morg uses is not foolproof.
        You can easily enough insert and populate such a table in an
        arbitrary SQLite file and trick Morg into using that file as its
        database. Alternatively, you can remove the watermark table from
        an actual Morg database and prevent Morg from using that.

        However, it requires a small amount of effort to manually mangle
        SQLite files in this way and the payoff, at least in this case,
        is pretty much non-existent. Thus, the purpose of the watermark
        is simply to record some metadata and to assure Morg that the
        SQLite file it is using is most likely a valid Morg database
        rather than to enforce some strict, tamperproof barrier that
        prevents intentional or unintentional cross-application data
        pollution.

        After the watermark creation or verification phase, the
        constructor proceeds to creating the basic database structure
        required by Morg. At the very least, Morg needs a <tt>task</tt>
        table to record all your tasks as well as several property tables
        that define and record the various properties associated with
        tasks. Preexisting task and property tables will be left
        untouched.

        However, the database constructor allows you to define new
        properties during initialization. These initial properties are
        specified via the properties parameter, which is a dict that maps
        strings to 2-tuples. The key is the name of a property. The
        2-tuple corresponding to the property name contains the property
        type and its range.

        The property type can be one of the following (case-insensitive)
        strings:

        @li <tt>integer</tt>
        @li <tt>real</tt>
        @li <tt>text</tt>



        The property range may be either <tt>None</tt> or a string
        describing the range of values that particular property may take
        on. Commas can be used to separate items in a list of discrete
        values. Double dots can be used for numeric ranges. Here are a
        few illustrative examples:

        @verbatim
Changes to wiki/todo.wiki.
14
15
16
17
18
19
20

21
22
23
24


25
26
  *  Instantiate database object in <tt>main()</tt>.
  *  Create <tt>morg</tt> table on database init.
  *  Create <tt>task</tt> table on database init.
  *  Create <tt>property</tt> table on database init.
  *  Add default properties dict.
  *  Create <tt>property_NNN</tt> tables on database init.
  *  Implement sanity check on database initialization.


<h2>PENDING</h2>

  *  Update database constructor doc string.


  *  Pass database to all commands' <tt>__call__</tt> method.
  *  Implement <tt>new</tt> command.







>



|
>
>


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  *  Instantiate database object in <tt>main()</tt>.
  *  Create <tt>morg</tt> table on database init.
  *  Create <tt>task</tt> table on database init.
  *  Create <tt>property</tt> table on database init.
  *  Add default properties dict.
  *  Create <tt>property_NNN</tt> tables on database init.
  *  Implement sanity check on database initialization.
  *  Update database constructor doc string.

<h2>PENDING</h2>

  *  Use the BETWEEN operator in property range constraints.
  *  Implement a watermark class to ease verification and "Morgification."
  *  The watermark table should be created and populated in a transaction.
  *  Pass database to all commands' <tt>__call__</tt> method.
  *  Implement <tt>new</tt> command.