gws.base.database¶
Database support.
Base classes for database connections and for the objects that read and
write database tables: layers, models and authorization providers. Concrete
implementations (for PostgreSQL/PostGIS) live in gws.plugin.postgres and
extend the classes in this package.
Submodules¶
manager- the database manager (root.app.databaseMgr). It creates the providers configured underdatabase.providersand finds them by uid or type. A provider that fails to configure is logged and skipped. The manager registers itself as thedbmiddleware.provider- the base database provider. It wraps an SQLAlchemyEngine, hands out connections, reflects and caches table structures and describes tables and columns.connection- the connection object yielded byprovider.begin(), a thin wrapper around an SQLAlchemyConnectionwith fetch helpers.model- the base database model, which reads features with a SELECT built by the model fields and creates, updates and deletes table rows.layer- the base vector layer for a database table, with a default model and finder for the table. The geometry type and CRS are taken from the table description. Without configured models, the layer gets a default model. If no extent is configured, it is computed from the table bounds. Unless finders are configured or search is disabled, the layer gets a default finder.auth_provider- the base authorization provider that checks users with SQL queries.
Providers and connections¶
Layers, models and other objects refer to a provider with dbUid. Without
dbUid they use the default provider passed by their parent or the first
provider of their type (see gws.config.util.configure_database_provider_for).
A provider keeps one SQLAlchemy connection per thread. begin() opens it,
begins a transaction and yields the connection. The outermost begin()
commits on normal exit, rolls back on an exception and closes the connection.
Inner calls join the open transaction, or create a savepoint with
nested=True:
with db.begin() as conn:
conn.execute('INSERT INTO my_table (id) VALUES (:id)', {'id': 1})
with db.begin() as conn2:
# the same connection and transaction, sees the insert
n = conn2.fetch_int('SELECT count(*) FROM my_table')
# committed
The connection itself has no commit() or rollback(). To catch a
database error and continue in the same transaction, wrap the statement in a
savepoint:
try:
with db.begin(nested=True) as conn:
conn.execute('INSERT ...')
except sa.Error:
...
Statements that cannot run in a transaction, like VACUUM, use
autocommit_connection(), which is a separate connection.
The engine is created on activation and is not pickled. Connection pooling is
off unless withPool is set; the pool options disabled,
pre_ping, size, recycle and timeout are passed to the engine.
Table structures are reflected per schema and cached for
schemaCacheLifeTime seconds. describe and describe_column turn
the reflected structure into gws.DataSetDescription and
gws.ColumnDescription objects, which models use to derive their fields.
Models¶
A database model builds its SELECT from the contributions of its fields
(mc.dbSelect), the search query (uids, keyword, shape, sort, limit, extra
conditions and columns) and the configured sqlFilter. If the search asks
for uids, a keyword or a shape, but the table has no primary key or no field
contributes a matching condition, nothing is selected. Writes call the field
hooks (before_create, after_create and so on) around a single INSERT,
UPDATE or DELETE and commit the connection. Reads and writes check the user’s
permissions on the model and raise gws.ForbiddenError if they are
missing. Composite primary keys are not supported. See gws.base.model for
the data flow between records, features and props.
Source code: gws.base.database