SQL Database-based Data Services
================================

.. py:module:: pyslet.odata2.sqlds

This module defines a general (but abstract) implementation of the
EDM-based data-access-layer (DAL) using Python's DB API: 
http://www.python.org/dev/peps/pep-0249/

It also contains a concrete implementation derived from the above
that uses the standard SQLite module for storage.  For more information
about SQLite see: http://www.sqlite.org/


Data Access Layer API
---------------------

Entity Containers
~~~~~~~~~~~~~~~~~

There are primarily two use cases here:

1.	Create a derived class of :py:class:`SQLEntityContainer` to provide
	platform specific modifications to the way SQL queries are constructed
	and database connections are created and managed.

2.	Create a derived class of :py:class:`SQLEntityContainer` to provide
	modified name mappings for a specific database and metadata model.

These two use cases can be supported through multiple (diamond)
inheritance. This makes it easier for you to separate the code required.
In practice, implementations for different database platforms are likely
to be shared (perhaps as part of future releases of Pyslet itself)
whereas modifications to the name mangler to map this API to an existing
database will be project specific.

For example, to achieve platform specific modifications you'll override
SQLEntityContainer and provide new implementations for methods such as
:py:meth:`SQLEntityContainer.get_collection_class`::

	class MyDBContainer(SQLEntityContainer):
		
		def get_collection_class(self):
			return MyDBEntityCollection
	
To achieve modified property name mappings you'll override
SQLEntityContainer and provide new implementations for methods such as
:py:meth:`SQLEntityContainer.mangle_name`::

	class SouthwindDBContainer(SQLEntityContainer):
		
		def mangle_name(self,source_path):
			# do some custom name mangling here....

Normally, you'll want to achieve both use cases, so to actually
instantiate your database you'll select the container class that
represents the database platform and then combine it with the class that
contains your data-specific modifications::

	import MyDB, Southwind

	# easy to configure constants at the top of your script
	DBCONTAINER_CLASS=MyDB.MyDBContainer
	DBCONTAINER_ARGS={
		'username':"southwind",
		'password':"password"
		}

	MAX_CONNECTIONS=100
	
	class SouthwindDB(Southwind.SouthwindDBContainer,DBCONTAINER_CLASS):
		pass
	
	# .... load the metadata from disk and then do something like this 
	db=SouthwindDB(container=SouthwindMetadata,max_connections=MAX_CONNECTIONS,**DBCONTAINER_ARGS)
	

..	autoclass:: SQLEntityContainer
	:members:
	:show-inheritance:
 
For an example of how to create a platform-specific implementation see
`SQLite`_ below.
 
Entity Collections
~~~~~~~~~~~~~~~~~~

These classes are documented primarily to facilitate the creation of
alternative implementations designed to run over other DB API based data
layers.  The documentation goes a bit further than is necessary to help
promote an understanding of the way the API is implemented.


..	autoclass:: SQLEntityCollection
	:members:
	:show-inheritance:

..	autoclass:: SQLCollectionBase
	:members:
	:show-inheritance:

..	autoclass:: SQLNavigationCollection
	:members:
	:show-inheritance:

..	autoclass:: SQLForeignKeyCollection
	:members:
	:show-inheritance:

..	autoclass:: SQLReverseKeyCollection
	:members:
	:show-inheritance:

..	autoclass:: SQLAssociationCollection
	:members:
	:show-inheritance:


SQLite
------

This module also contains a fully functional implementation of the API
based on the sqlite3 module.  The first job with any SQL implementation
is to create a base collection class that implements any custom
expression handling.

In the case of SQLite we override a handful of the standard SQL
functions only.  Notice that this class is derived from
:py:class:`SQLCollectionBase`, an abstract class.  If your SQL
platform adheres to the SQL standard very closely, or you are happy for
SQL-level errors to be generated when unsupported SQL syntax is
generated by some filter or orderby expressions then you can skip the
process of creating customer collection classes completely. 

..	autoclass:: SQLiteEntityCollectionBase
	:members:
	:show-inheritance:

To ensure that our custom implementations are integrated in to all the
collection classes we have to create specific classes for all collection
types.  These classes have no implementation!

..	autoclass:: SQLiteEntityCollection
	:show-inheritance:

..	autoclass:: SQLiteForeignKeyCollection
	:show-inheritance:

..	autoclass:: SQLiteReverseKeyCollection
	:show-inheritance:

..	autoclass:: SQLiteAssociationCollection
	:show-inheritance:

Finally, we can override the main container class to provide a complete
implementation of our API using the sqlite3 module.

..	autoclass:: SQLiteEntityContainer
	:members:
	:show-inheritance:


Utility Classes
---------------

Some miscellaneous classes documented mainly to make the implementation
of the collection classes easier to understand.

..	autoclass:: SQLTransaction
	:members:
	:show-inheritance:

..	autoclass:: SQLParams
	:members:
	:show-inheritance:

..	autoclass:: QMarkParams
	:members:
	:show-inheritance:

..	autoclass:: NumericParams
	:members:
	:show-inheritance:

..	autoclass:: NamedParams
	:members:
	:show-inheritance:


Misc Definitions
----------------

..	autodata:: SQL_TIMEOUT

..	autoclass:: UnparameterizedLiteral
	:members:
	:show-inheritance:

..	autodata:: SQLOperatorPrecedence

..	autoclass:: DummyLock
	:members:
	:show-inheritance:


Exceptions
----------

..	autoclass:: DatabaseBusy
	:members:
	:show-inheritance:

..	autoclass:: SQLError
	:members:
	:show-inheritance:
