[Sqlalchemy-commits] [1474] sqlalchemy/branches/schema/doc: edits etc
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-05-20 17:45:28
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1474] sqlalchemy/branches/schema/doc: edits etc</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1474</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-20 12:45:06 -0500 (Sat, 20 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>edits etc</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt">sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentdbenginetxt">sqlalchemy/branches/schema/doc/build/content/dbengine.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentpluginstxt">sqlalchemy/branches/schema/doc/build/content/plugins.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentunitofworktxt">sqlalchemy/branches/schema/doc/build/content/unitofwork.txt</a></li> <li><a href="#sqlalchemybranchesschemadocscriptsjs">sqlalchemy/branches/schema/doc/scripts.js</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocalphaapihtml">sqlalchemy/branches/schema/doc/alphaapi.html</a></li> <li><a href="#sqlalchemybranchesschemadocalphaimplementationhtml">sqlalchemy/branches/schema/doc/alphaimplementation.html</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocalphaapihtml"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/doc/alphaapi.html (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/alphaapi.html 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/alphaapi.html 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -0,0 +1,27 @@ </span><ins>+<html> +<head> + <link href="style.css" rel="stylesheet" type="text/css"></link> + <link href="docs.css" rel="stylesheet" type="text/css"></link> + <script src="scripts.js"></script> + <title>SQLAlchemy Documentation</title> +</head> +<body> + <h3>What is an Alpha API Feature?</h3> +<p><b>Alpha API</b> indicates that the best way for a particular feature to be presented hasn't been firmly settled on as of yet, and the current way is being introduced on a trial basis. Its spirit is not as much a warning that "this API might change", its more an invitation to the users saying, "heres a new idea I had. I'm not sure if this is the best way to do it. Do you like it ? Should we do this differently? Or is it good the way it is ?". Alpha API features are always small in scope and are presented in releases so that the greatest number of users get some hands-on experience with it; large-scoped API or architectural changes will always be discussed on the mailing list/Wiki first.</p> + +<p>Reasons why a feature might want to change include: + <ul> + <li>The API for the feature is too difficult to use for the typical task, and needs to be more "convenient"</li> + <li>The feature only implements a subsection of what it really should be doing</li> + <li>The feature's interface is inconsistent with that of other features which operate at a similar level</li> + <li>The feature is confusing and is often misunderstood, and would be better replaced by a more manual feature that makes the task clearer</li> + <li>The feature overlaps with another feature and effectively provides too many ways to do the same thing</li> + <li>The feature made some assumptions about the total field of use cases which is not really true, and it breaks in other scenarios</li> + </ul> + +</p> +<p>A good example of what was essentially an "alpha feature" is the <code>private=True</code> flag. This flag on a <code>relation()</code> indicates that child objects should be deleted along with the parent. After this flag experienced some usage by the SA userbase, some users remarked that a more generic and configurable way was Hibernates <code>cascade="all, delete-orphan"</code>, and also that the term <code>cascade</code> was clearer in purpose than the more ambiguous <code>private</code> keyword, which could be construed as a "private variable".</p> + +<center><input type="button" value="close window" onclick="window.close()"></center> +</body> +</html> </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemybranchesschemadocalphaimplementationhtml"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/doc/alphaimplementation.html (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/alphaimplementation.html 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/alphaimplementation.html 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -0,0 +1,16 @@ </span><ins>+<html> +<head> + <link href="style.css" rel="stylesheet" type="text/css"></link> + <link href="docs.css" rel="stylesheet" type="text/css"></link> + <script src="scripts.js"></script> + <title>SQLAlchemy Documentation</title> +</head> +<body> + <h3>What is an Alpha Implementation Feature?</h3> +<p><b>Alpha Implementation</b> indicates a feature where developer confidence in its functionality has not yet been firmly established. This typically includes brand new features for which adequate unit tests have not been completed, and/or features whose scope is broad enough that its not clear what additional unit tests might be needed.</p> + +<p>Alpha implementation is not meant to discourage the usage of a feature, it is only meant to indicate that some difficulties in getting full functionality from the feature may occur, and to encourage the reporting of these difficulties either via the mailing list or through <a href="http://www.sqlalchemy.org/trac/newticket" target="_blank">submitting a ticket</a>.</p> + +<center><input type="button" value="close window" onclick="window.close()"></center> +</body> +</html> </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -1,3 +1,6 @@ </span><ins>+[alpha_api]: javascript:alphaApi() +[alpha_implementation]: javascript:alphaImplementation() + </ins><span class="cx"> Advanced Data Mapping {@name=advdatamapping} </span><span class="cx"> ====================== </span><span class="cx"> </span><span class="lines">@@ -81,8 +84,50 @@ </span><span class="cx"> '_email': mytable.c.email </span><span class="cx"> }) </span><span class="cx"> </span><del>-In a later release, SQLAlchemy will also allow `_get_email` and `_set_email` to be attached directly to the "email" property created by the mapper, and will also allow this association to occur via decorators. </del><ins>+In a later release, SQLAlchemy will also allow `_get_email` and `_set_email` to be attached directly to the "email" property created by the mapper, and +will also allow this association to occur via decorators. </ins><span class="cx"> </span><ins>+ +#### Custom List Classes {@name=customlist} + +Feature Status: [Alpha API][alpha_api] + +A one-to-many or many-to-many relationship results in a list-holding element being attached to all instances of a class. Currently, this list is an instance of `sqlalchemy.util.HistoryArraySet`, is a `UserDict` instance that *decorates* an underlying list object. The implementation of this list can be controlled, and can in fact be any object that implements a `list`-style `append` and `__iter__` method. A common need is for a list-based relationship to actually be a dictionary. This can be achieved by subclassing `dict` to have `list`-like behavior. + +In this example, a class `MyClass` is defined, which is associated with a parent object `MyParent`. The collection of `MyClass` objects on each `MyParent` object will be a dictionary, storing each `MyClass` instance keyed to its `name` attribute. + + {python} + # a class to be stored in the list + class MyClass(object): + def __init__(self, name): + self.name = name + + # create a dictionary that will act like a list, and store + # instances of MyClass + class MyDict(dict): + def append(self, item): + self[item.name] = item + def __iter__(self): + return self.values() + + # parent class + class MyParent(object): + # this class-level attribute provides the class to be + # used by the 'myclasses' attribute + myclasses = MyDict + + # mappers, constructed normally + mapper(MyClass, myclass_table) + mapper(MyParent, myparent_table, properties={ + 'myclasses' : relation(MyClass) + }) + + # elements on 'myclasses' can be accessed via string keyname + myparent = MyParent() + myparent.myclasses.append(MyClass('this is myclass')) + myclass = myparent.myclasses['this is myclass'] + + </ins><span class="cx"> #### Custom Join Conditions {@name=customjoin} </span><span class="cx"> </span><span class="cx"> When creating relations on a mapper, most examples so far have illustrated the mapper and relationship joining up based on the foreign keys of the tables they represent. in fact, this "automatic" inspection can be completely circumvented using the `primaryjoin` and `secondaryjoin` arguments to `relation`, as in this example which creates a User object which has a relationship to all of its Addresses which are in Boston: </span><span class="lines">@@ -277,7 +322,6 @@ </span><span class="cx"> </span><span class="cx"> The main WHERE clause as well as the limiting clauses are coerced into a subquery; this subquery represents the desired result of objects. A containing query, which handles the eager relationships, is joined against the subquery to produce the result. </span><span class="cx"> </span><del>- </del><span class="cx"> ### More on Mapper Options {@name=options} </span><span class="cx"> </span><span class="cx"> The `options` method on the `Query` object, first introduced in [datamapping_relations_options](rel:datamapping_relations_options), produces a new `Query` object by creating a copy of the underlying `Mapper` and placing modified properties on it. The `options` method is also directly available off the `Mapper` object itself, so that the newly copied `Mapper` can be dealt with directly. The `options` method takes a variable number of `MapperOption` objects which know how to change specific things about the mapper. The five available options are `eagerload`, `lazyload`, `noload`, `deferred` and `extension`. </span><span class="lines">@@ -309,6 +353,8 @@ </span><span class="cx"> </span><span class="cx"> ### Mapping a Class with Table Inheritance {@name=inheritance} </span><span class="cx"> </span><ins>+Feature Status: [Alpha Implementation][alpha_implementation] + </ins><span class="cx"> Inheritance in databases comes in three forms: *single table inheritance*, where several types of classes are stored in one table, *concrete table inheritance*, where each type of class is stored in its own table, and *multiple table inheritance*, where the parent/child classes are stored in their own tables that are joined together in a select. </span><span class="cx"> </span><span class="cx"> There is also a concept of `polymorphic` loading, which indicates if multiple kinds of classes can be loaded in one pass. </span><span class="lines">@@ -535,7 +581,7 @@ </span><span class="cx"> </span><span class="cx"> ### Circular Mapping {@name=circular} </span><span class="cx"> </span><del>-Oftentimes it is necessary for two mappers to be related to each other. With a datamodel that consists of Users that store Addresses, you might have an Address object and want to access the "user" attribute on it, or have a User object and want to get the list of Address objects. The easiest way to do this is via the `backreference` keyword described in [datamapping_relations_backreferences](rel:datamapping_relations_backreferences). Although even when backreferences are used, it is sometimes necessary to explicitly specify the relations on both mappers pointing to each other. </del><ins>+Oftentimes it is necessary for two mappers to be related to each other. With a datamodel that consists of Users that store Addresses, you might have an Address object and want to access the "user" attribute on it, or have a User object and want to get the list of Address objects. The easiest way to do this is via the `backref` keyword described in [datamapping_relations_backreferences](rel:datamapping_relations_backreferences). Although even when backreferences are used, it is sometimes necessary to explicitly specify the relations on both mappers pointing to each other. </ins><span class="cx"> To achieve this involves creating the first mapper by itself, then creating the second mapper referencing the first, then adding references to the first mapper to reference the second: </span><span class="cx"> </span><span class="cx"> {python} </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentdbenginetxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/dbengine.txt (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/dbengine.txt 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/build/content/dbengine.txt 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -47,7 +47,7 @@ </span><span class="cx"> </span><span class="cx"> Options that can be specified include the following: </span><span class="cx"> </span><del>-* strategy='plain' : the Strategy describes the general configuration used to create this Engine. The two available values are `plain`, which is the default, and `threadlocal`, which applies a "thread-local context" to implicit executions performed by the Engine. This context is further described in the sections below. </del><ins>+* strategy='plain' : the Strategy describes the general configuration used to create this Engine. The two available values are `plain`, which is the default, and `threadlocal`, which applies a "thread-local context" to implicit executions performed by the Engine. This context is further described in [dbengine_connections_context](rel:dbengine_connections_context). </ins><span class="cx"> * pool=None : an instance of `sqlalchemy.pool.Pool` to be used as the underlying source for connections, overriding the engine's connect arguments (pooling is described in [pooling](rel:pooling)). If None, a default `Pool` (usually `QueuePool`, or `SingletonThreadPool` in the case of SQLite) will be created using the engine's connect arguments. </span><span class="cx"> </span><span class="cx"> Example: </span><span class="lines">@@ -120,7 +120,7 @@ </span><span class="cx"> </span><span class="cx"> #### Implicit Connection Contexts {@name=context} </span><span class="cx"> </span><del>-SQL operations can also be performed using the `Engine` alone without explicitly referencing a `Connection`. The operation is executed with a connection that is allocated internally. This type of connection, i.e. the automatically allocated connection when calling `execute()` directly off of an `Engine`, is called an **implicit connection**. </del><ins>+An **implicit connection** refers to connections that are allocated by the `Engine` internally. There are two general cases when this occurs: when using the various `execute()` methods that are available off the `Engine` object itself, and when calling the `execute()` method on constructed SQL objects, which are described in [sqlconstruction](rel:sqlconstruction). </ins><span class="cx"> </span><span class="cx"> {python title="Implicit Connection"} </span><span class="cx"> engine = create_engine('sqlite:///:memory:') </span><span class="lines">@@ -129,12 +129,14 @@ </span><span class="cx"> print row['col1'], row['col2'] </span><span class="cx"> result.close() </span><span class="cx"> </span><del>-When using implicit connections, the returned `ResultProxy` has a `close()` method which will return the resources used by the `Connection`. While the implicit method of execution seems redundant in light of the explicit `Connection` object available, it is essentially the same methodology used by "bound" schema and statement objects to execute themselves, so the same rules of connection allocation apply. </del><ins>+When using implicit connections, the returned `ResultProxy` has a `close()` method which will return the resources used by the underlying `Connection`. </ins><span class="cx"> </span><del>-The user has two choices, determined when the Engine is first created, as to how the resources of this connection should be used in relation to other connections. This is determined by the `strategy` argument to `create_engine()`, which has two possible values: `plain` and `threadlocal`. In `plain`, every `execute` call uses a distinct connection from the database, which is only released when the `close()` method on the Result is called, or the result object itself and its underlying Connection falls out of scope and is garbage collected. In `threadlocal`, multiple calls to `execute()` within the same thread will use the already-checked out connection resource if one is available, or if none is available will request a connection resource. </del><ins>+The `strategy` keyword argument to `create_engine()` affects the algorithm used to retreive the underlying DBAPI connection used by implicit executions. When set to `plain`, each implicit execution requests a unique connection from the connection pool, which is returned to the pool when the resulting `ResultProxy` falls out of scope (i.e. `__del__()` is called) or its `close()` method is called. If a second implicit execution occurs while the `ResultProxy` from the previous execution is still open, then a second connection is pulled from the pool. </ins><span class="cx"> </span><del>-It is crucial to note that the `plain` and `threadlocal` contexts **do not impact the connect() method on the Engine.** If you are using explicit Connection objects returned by `connect()` method, you have full control over the connection resources used. </del><ins>+When `strategy` is set to `threadlocal`, the `Engine` still checks out a connection which is closeable in the same manner via the `ResultProxy`, except the connection it checks out will be the **same** connection as one which is already checked out, assuming the operation is in the same thread. When all `ResultProxy` objects are closed, the connection is returned to the pool normally. </ins><span class="cx"> </span><ins>+It is crucial to note that the `plain` and `threadlocal` contexts **do not impact the connect() method on the Engine.** `connect()` always returns a unique connection. Implicit connections use a different method off of `Engine` for their operations called `contextual_connect()`. + </ins><span class="cx"> The `plain` strategy is better suited to an application that insures the explicit releasing of the resources used by each execution. This is because each execution uses its own distinct connection resource, and as those resources remain open, multiple connections can be checked out from the pool quickly. Since the connection pool will block further requests when too many connections have been checked out, not keeping track of this can impact an application's stability. </span><span class="cx"> </span><span class="cx"> {python title="Plain Strategy"} </span><span class="lines">@@ -155,8 +157,10 @@ </span><span class="cx"> # release connection 2 </span><span class="cx"> r2.close() </span><span class="cx"> </span><del>-The `threadlocal` strategy is better suited to a programming style which relies upon the `__del__()` method of Connection objects in order to return them to the connection pool, rather than explicitly issuing a `close()` statement upon the `Result` object. This is because all of the executions within a single thread will share the same connection, if one has already been checked out in the current thread. Using this style, an application will use only one connection per thread at most within the scope of all implicit executions. </del><ins>+Advantages to `plain` include that connection resources are immediately returned to the connection pool, without any reliance upon the `__del__()` method; there is no chance of resources being left around by a Python implementation that doesn't necessarily call `__del__()` immediately. </ins><span class="cx"> </span><ins>+The `threadlocal` strategy is better suited to a programming style which relies upon the `__del__()` method of Connection objects in order to return them to the connection pool, rather than explicitly issuing a `close()` statement upon the `ResultProxy` object. This is because all of the executions within a single thread will share the same connection, if one has already been checked out in the current thread. Using this style, an application will use only one connection per thread at most within the scope of all implicit executions. + </ins><span class="cx"> {python title="Threadlocal Strategy"} </span><span class="cx"> db = create_engine('mysql://localhost/test', strategy='threadlocal') </span><span class="cx"> </span><span class="lines">@@ -179,6 +183,8 @@ </span><span class="cx"> </span><span class="cx"> While the `close()` method is still available with the "threadlocal" strategy, it should be used carefully. Above, if we issued a `close()` call on `r1`, and then tried to further work with results from `r2`, `r2` would be in an invalid state since its connection was already returned to the pool. By relying on `__del__()` to automatically clean up resources, this condition will never occur. </span><span class="cx"> </span><ins>+Advantages to `threadlocal` include that resources can be left to clean up after themselves, application code can be more minimal, its guaranteed that only one connection is used per thread, and there is no chance of a "connection pool block", which is when an execution hangs because the current thread has already checked out all remaining resources. + </ins><span class="cx"> To get at the actual `Connection` object which is used by implicit executions, call the `contextual_connection()` method on `Engine`: </span><span class="cx"> </span><span class="cx"> {python title="Contextual Connection"} </span><span class="lines">@@ -192,8 +198,6 @@ </span><span class="cx"> True </span><span class="cx"> </span><span class="cx"> When the `plain` strategy is used, the `contextual_connection()` method is synonymous with the `connect()` method; both return a distinct connection from the pool. </span><del>- -At this point, you're probably saying, "wow, why would anyone *ever* want to use the [insert name here] strategy ??" Advantages to `plain` include that connection resources are immediately returned to the connection pool, without any reliance upon the `__del__()` method; there is no chance of resources being left around by a Python implementation that doesn't necessarily call `__del__()` immediately. Advantages to `threadlocal` include that resources can be left to clean up after themselves, application code can be more minimal, its guaranteed that only one connection is used per thread, and there is no chance of a "connection pool block", which is when an execution hangs because the current thread has already checked out all remaining resources. </del><span class="cx"> </span><span class="cx"> ### Transactions {@name=transactions} </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentpluginstxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/plugins.txt (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/plugins.txt 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/build/content/plugins.txt 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -1,12 +1,12 @@ </span><span class="cx"> Plugins {@name=plugins} </span><span class="cx"> ====================== </span><span class="cx"> </span><del>-(SECTION UNDER CONSTRUCTION) - </del><span class="cx"> SQLAlchemy has a variety of extensions and "mods" available which provide extra functionality to SA, either via explicit usage or by augmenting the core behavior. </span><span class="cx"> </span><span class="cx"> ### threadlocal </span><span class="cx"> </span><ins>+**Author:** Mike Bayer and Daniel Miller + </ins><span class="cx"> Establishes `threadlocal` as the default strategy for new `ComposedSQLEngine` objects, installs a threadlocal `SessionContext` that is attached to all Mappers via a global `MapperExtension`, and establishes the global `SessionContext` under the name `sqlalchemy.objectstore`. Usually this is used in combination with `Tables` that are associated with `BoundMetaData` or `DynamicMetaData`, so that the `Session` does not need to be bound to any `Engine` explicitly. </span><span class="cx"> </span><span class="cx"> {python} </span><span class="lines">@@ -118,35 +118,161 @@ </span><span class="cx"> # assume "threadlocal" strategy is enabled, and there is no transaction in progress </span><span class="cx"> </span><span class="cx"> result = table.select().execute() # 'result' references a DBAPI connection, bound to the current thread </span><ins>+ </ins><span class="cx"> object = session.select() # the 'select' operation also uses the current thread's connection, </span><span class="cx"> # i.e. the same connection referenced by 'result' </span><ins>+ </ins><span class="cx"> result.close() # return the connection to the pool. now there is no connection </span><span class="cx"> # associated with the current thread. the next execution will re-check out a </span><span class="cx"> # connection and re-attach to the current thread. </span><span class="cx"> </span><span class="cx"> ### SessionContext </span><span class="cx"> </span><ins>+**Author:** Daniel Miller + </ins><span class="cx"> This plugin is a generalized version of the `objectstore` object provided by the `threadlocal` plugin: </span><span class="cx"> </span><span class="cx"> {python} </span><ins>+ import sqlalchemy + from sqlalchemy.ext.sessioncontext import SessionContext </ins><span class="cx"> </span><del>- ctx = SessionContext() </del><ins>+ ctx = SessionContext(sqlalchemy.create_session) + </ins><span class="cx"> class User(object): </span><del>- __session__ = ctx </del><ins>+ pass </ins><span class="cx"> </span><del>- mapper(User, users_table) </del><ins>+ mapper(User, users_table, extension=ctx.mapperextension) </ins><span class="cx"> </span><span class="cx"> # 'u' is automatically added to the current session of 'ctx' </span><span class="cx"> u = User() </span><span class="cx"> </span><ins>+ # get the current session and flush </ins><span class="cx"> ctx.current.flush() </span><ins>+ +The construction of each `Session` instance can be customized by providing a "creation function" which returns a new `Session`. The "scope" to which the session is associated, which by default is the current thread, can be customized by providing a "scope callable" which returns a hashable key that represents the current scope: </ins><span class="cx"> </span><ins>+ {python} + import sqlalchemy + from sqlalchemy.ext.sessioncontext import SessionContext + + # create an engine + someengine = sqlalchemy.create_engine('sqlite:///') + + # a function to return a Session bound to our engine + def make_session(): + return sqlalchemy.create_session(bind_to=someengine) + + # global declaration of "scope" + scope = "scope1" + + # a function to return the current "session scope" + def global_scope_func(): + return scope + + # create SessionContext with our two functions + ctx = SessionContext(make_session, scopefunc=global_scope_func) + + # get the session corresponding to "scope1", bound to engine "someengine": + session = ctx.current + + # switch the "scope" + scope = "scope2" + + # get the session corresponding to "scope2", bound to engine "someengine": + session = ctx.current + + </ins><span class="cx"> ### ActiveMapper </span><span class="cx"> </span><ins>+**Author:** Jonathan LaCour + +ActiveMapper is a so-called "declarative layer" which allows the construction of a class, a `Table`, and a `Mapper` all in one step: + + {python} + class Person(ActiveMapper): + class mapping: + id = column(Integer, primary_key=True) + full_name = column(String) + first_name = column(String) + middle_name = column(String) + last_name = column(String) + birth_date = column(DateTime) + ssn = column(String) + gender = column(String) + home_phone = column(String) + cell_phone = column(String) + work_phone = column(String) + prefs_id = column(Integer, foreign_key=ForeignKey('preferences.id')) + addresses = one_to_many('Address', colname='person_id', backref='person') + preferences = one_to_one('Preferences', colname='pref_id', backref='person') + + def __str__(self): + s = '%s\n' % self.full_name + s += ' * birthdate: %s\n' % (self.birth_date or 'not provided') + s += ' * fave color: %s\n' % (self.preferences.favorite_color or 'Unknown') + s += ' * personality: %s\n' % (self.preferences.personality_type or 'Unknown') + + for address in self.addresses: + s += ' * address: %s\n' % address.address_1 + s += ' %s, %s %s\n' % (address.city, address.state, address.postal_code) + + return s + + + class Preferences(ActiveMapper): + class mapping: + __table__ = 'preferences' + id = column(Integer, primary_key=True) + favorite_color = column(String) + personality_type = column(String) + + + class Address(ActiveMapper): + class mapping: + id = column(Integer, primary_key=True) + type = column(String) + address_1 = column(String) + city = column(String) + state = column(String) + postal_code = column(String) + person_id = column(Integer, foreign_key=ForeignKey('person.id')) + +More discussion on ActiveMapper can be found at [Jonathan LaCour's Blog](http://cleverdevil.org/computing/35/declarative-mapping-with-sqlalchemy) as well as the [SQLAlchemy Wiki](http://www.sqlalchemy.org/trac/wiki/ActiveMapper). + +### SqlSoup + +**Author:** Jonathan Ellis + +SqlSoup creates mapped classes on the fly from tables. It is essentially a nicer version of the "row data gateway" pattern. + + {python} + >>> from sqlalchemy.ext.sqlsoup import SqlSoup + >>> soup = SqlSoup('sqlite://filename=:memory:') + + >>> users = soup.users.select() + >>> users.sort() + >>> users + [Class_Users(name='Bhargan Basepair',email='bas...@ex...',password='basepair',classname=None,admin=1), + Class_Users(name='Joe Student',email='st...@ex...',password='student',classname=None,admin=0)] + +Read more about SqlSoup on [Jonathan Ellis' Blog](http://spyced.blogspot.com/2006/04/introducing-sqlsoup.html). + </ins><span class="cx"> ### ProxyEngine </span><span class="cx"> </span><ins>+**Author:** Jason Pellerin + +The `ProxyEngine` is used to "wrap" an `Engine`, and via subclassing `ProxyEngine` one can instrument the functionality of an arbitrary `Engine` instance through the decorator pattern. It also provides a `connect()` method which will send all `Engine` requests to different underlying engines. Its functionality in that regard is largely superceded now by `DynamicMetaData` which is a better solution. + + {python} + from sqlalchemy.ext.proxy import ProxyEngine + proxy = ProxyEngine() + + proxy.connect('postgres://user:pw@host/db') + </ins><span class="cx"> ### SelectResults </span><span class="cx"> </span><ins>+**Author:** Jonas Borgström + </ins><span class="cx"> SelectResults gives generator-like behavior to the results returned from the `select` and `select_by` method of `Query`. It supports three modes of operation; per-query, per-mapper, and per-application. </span><span class="cx"> </span><span class="cx"> {python title="SelectResults with a Query Object"} </span><span class="lines">@@ -181,7 +307,3 @@ </span><span class="cx"> mapper(MyClass, mytable) </span><span class="cx"> session.query(MyClass).select(mytable.c.column=="something").order_by([mytable.c.column])[2:7] </span><span class="cx"> </span><del>- -### LegacySession - -(this plugin probably doesnt even work right now) </del><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentunitofworktxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/unitofwork.txt (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/unitofwork.txt 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/build/content/unitofwork.txt 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -1,3 +1,6 @@ </span><ins>+[alpha_api]: javascript:alphaApi() +[alpha_implementation]: javascript:alphaImplementation() + </ins><span class="cx"> Session / Unit of Work {@name=unitofwork} </span><span class="cx"> ============ </span><span class="cx"> </span><span class="lines">@@ -310,6 +313,8 @@ </span><span class="cx"> </span><span class="cx"> #### merge() {@name=merge} </span><span class="cx"> </span><ins>+Feature Status: [Alpha Implementation][alpha_implementation] + </ins><span class="cx"> `merge()` is used to return the persistent version of an instance that is not attached to this Session. When passed an instance, if an instance with its database identity already exists within this Session, it is returned. If the instance does not exist in this Session, it is loaded from the database and then returned. </span><span class="cx"> </span><span class="cx"> A future version of `merge()` will also update the Session's instance with the state of the given instance (hence the name "merge"). </span><span class="lines">@@ -328,6 +333,8 @@ </span><span class="cx"> </span><span class="cx"> ### Cascade rules {@name=cascade} </span><span class="cx"> </span><ins>+Feature Status: [Alpha Implementation][alpha_implementation] + </ins><span class="cx"> Mappers support the concept of configurable *cascade* behavior on `relation()`s. This behavior controls how the Session should treat the instances that have a parent-child relationship with another instance that is operated upon by the Session. Cascade is indicated as a comma-separated list of string keywords, with the possible values `all`, `delete`, `save-update`, `refresh-expire`, `merge`, `expunge`, and `delete-orphan`. </span><span class="cx"> </span><span class="cx"> Cascading is configured by setting the `cascade` keyword argument on a `relation()`: </span></span></pre></div> <a id="sqlalchemybranchesschemadocscriptsjs"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/scripts.js (1473 => 1474)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/scripts.js 2006-05-19 00:13:01 UTC (rev 1473) +++ sqlalchemy/branches/schema/doc/scripts.js 2006-05-20 17:45:06 UTC (rev 1474) </span><span class="lines">@@ -16,3 +16,10 @@ </span><span class="cx"> } </span><span class="cx"> } </span><span class="cx"> </span><ins>+function alphaApi() { + window.open("alphaapi.html", "_blank", "width=600,height=400, scrollbars=yes,resizable=yes,toolbar=no"); +} + +function alphaImplementation() { + window.open("alphaimplementation.html", "_blank", "width=600,height=400, scrollbars=yes,resizable=yes,toolbar=no"); +} </ins><span class="cx">\ No newline at end of file </span></span></pre> </div> </div> </body> </html> |