Changelog¶
v3.1.0 (2025-11-20)¶
Fix bug in
Model.to_dict()where relationship fields may not get populated when multiple relationships reference the same model. Thanks bharadwajyarlagadda!Add support for Python 3.13.
Drop support for Python 3.7.
v3.0.0 (2023-01-26)¶
Fix bug in Session/AsynSession methods
first(),one(),one_or_none(),save(), andsave_all()that would result insqlalchemy.exc.InvalidRequestErrordue tounique()not being applied to the results.Add support for Python 3.11 and 3.12.
Drop support for SQLAlchemy < 2.0. (breaking change)
v2.0.1 (2022-10-11)¶
Update README for v2.
v2.0.0 (2022-05-06)¶
The v2 release is a major rewrite of the library with many incompatibilities and breaking changes from v1. Please see the Migrating to v2.0 section in the docs for details.
v1.3.0 (2021-04-28)¶
Fix compatibility issues with SQLAlchemy 1.4.
The following features are incompatible with SQLAlchemy 1.4 and will raise an exception if used:
sqlservice.Query.entitiessqlservice.Query.join_entitiessqlservice.Query.all_entitiessqlservice.SQLClient.prune
v1.2.2 (2021-03-29)¶
Pin supported SQLAlchemy version to
>=1.0,<1.4due to incompatibilities with SQAlchemy 1.4.
v1.2.1 (2020-01-17)¶
Rename
dataargument to_datainModelBase.__init__()andModelBase.update()to avoid conflict when an ORM model has a column attribute named"data".Add official support for Python 3.8.
v1.2.0 (2020-01-01)¶
Fix issue where all sessions in memory were closed in
SQLClient.disconnect().Add configuration keyword arguments to
SQLClient.__init__().
v1.1.3 (2018-09-26)¶
If a key in
ModelBase.__dict_args__['adapters']isNone, then don’t serialize that key when callingModel.to_dict().
v1.1.2 (2018-09-23)¶
Fix handling of string keys in
ModelBase.__dict_args__['adapters']that resulted in an unhandledTypeErrorexception in some cases.
v1.1.1 (2018-09-07)¶
Fix mishandling of case where new mappings passed to
SQLClient.bulk_diff_update()aren’t different than previous mappings.
v1.1.0 (2018-09-05)¶
Add
SQLClient.bulk_common_update()andcore.bulk_common_update().Add
SQLClient.bulk_diff_update()andcore.bulk_diff_update().Move logic in
SQLClient.bulk_insert()andbulk_insert_many()tocore.bulk_insert()andcore.bulk_insert_many()respectively.
v1.0.2 (2018-08-20)¶
Minor optimization to
SQLQuery.save()to not create an intermediate list when saving multiple items.
v1.0.1 (2018-08-20)¶
Add missing handling for generators in
SQLQuery.save().
v1.0.0 (2018-08-19)¶
Drop support for Python 2.7. (breaking change)
Don’t mutate
modelsargument when passed in as a list toSQLClient.save|core.save.Allow generators to be passed into
SQLClient.save|core.saveandSQLClient.destroy|core.destroy.Remove deprecated methods: (breaking change)
SQLClient.shutdown()(useSQLClient.disconnect())SQLQuery.chain()SQLQuery.pluck()SQLQuery.key_by()SQLQuery.map()SQLQuery.reduce()SQLQuery.reduce_right()SQLQuery.stack_by()
v0.23.0 (2018-08-06)¶
Add
SQLClient.DEFAULT_CONFIGclass attribute as way to override config defaults at the class level via subclassing.Rename
SQLClient.shutdown()todisconnect()but keepshutdown()as a deprecated alias.Deprecate
SQLClient.shutdown(). UseSQLClient.disconnect()instead. Will be removed inv1.Deprecate
SQLQuerymethods below. Usepydashlibrary directly or re-implement in subclass ofSQLQueryand pass toSQLClient()viaquery_classargument. Methods will be removed inv1:SQLQuery.chain()SQLQuery.pluck()SQLQuery.key_by()SQLQuery.map()SQLQuery.reduce()SQLQuery.reduce_right()SQLQuery.stack_by()
v0.22.1 (2018-07-15)¶
Support Python 3.7.
v0.22.0 (2018-04-12)¶
Change default behavior of
SQLClient.transaction()to not override the current session’sautoflushsetting (useSQLClient.transaction(autoflush=True)instead. (breaking change)Add boolean
autoflushoption toSQLClient.transaction()to set session’sautoflushvalue for the duration of the transaction.Add new
sqlservice.eventdecorators:on_init_scalaron_init_collectionon_modifiedon_bulk_replaceon_dispose_collection
v0.21.0 (2018-04-02)¶
Add
SQLClient.ping()method that performs a basic connection check.
v0.20.0 (2018-03-20)¶
Add
ModelBase.class_registry()that returns the declarative class registry from declarative metadata. Roughly equivalent toModelBase._decl_class_registrybut with_sa_*keys removed.Pass model instance as third optional argument to
ModelBase.__dict_args__['adapters']handlers.Expose default
dictadapater assqlservice.model.default_dict_adapter.
v0.19.0 (2018-03-19)¶
Support model class names as valid keys in
ModelBase.__dict_args__['adapaters']. Works similar to string namesused insqlalchemy.orm.relationship.Support model class orm descriptors (e.g. columns, relationships) as valid keys in
ModelBase.__dict_args__['adapaters'].
v0.18.0 (2018-03-12)¶
Remove
readonlyargument fromSQLClient.transactionand replace with separatecommitandrollback. (breaking change)The default is
commit=Trueandrollback=False. This behavior mirrors the previous behavior.When
rollback=True, thecommitargument is ignored and the top-level transaction is always rolled back. This is likereadonly=Truein version0.17.0.When
commit=Falseandrollback=False, the “transaction” isn’t finalized and is left open. This is likereadonly=Truein versions<=0.16.1.
v0.17.0 (2018-03-12)¶
Rollback instead of commit in a readonly transaction issued by
SQLClient.transaction. (potential breaking change)There’s a potential breaking change for the case where there’s nested a write transaction under a readonly transaction. Previously, the write transaction would be committed when the readonly transaction finalized since commit was being called instead of rollback. However with this change, the settings of the first transaction before any nesting will now determine whether the entire transaction is committed or rollbacked.
v0.16.1 (2018-02-26)¶
Use
repr(self.url)inSQLClient.__repr__()instead ofstr()to mask connection password if provided.
v0.16.0 (2018-02-21)¶
Support a database URI string as the configuration value for
SQLClient. For example, previously had to doSQLClient({'SQL_DATABASE_URI': '<db_uri>'})but now can doSQLClient('<db_uri>').Add
repr()support toSQLClient.
v0.15.0 (2018-02-13)¶
Add
SQL_POOL_PRE_PINGconfig option toSQLClientthat setspool_pre_pingargument to engine. Requires SQLAlchemy >= 1.2. Thanks dsully!
v0.14.2 (2017-10-17)¶
Fix
Query.search()so thatdictfilter-by criteria will be applied to the base model class of the query if it’s set (i.e. makedb.query(ModelA).join(ModelB).search({'a_only_field': 'foo'})work so that{'a_only_field': 'foo'}is filtered onModelA.a_only_fieldinstead ofModelB). This also applies toQuery.find()andQuery.find_one()which usesearch()internally.
v0.14.1 (2017-09-09)¶
Fix typo in
SQL_ENCODINGconfig option mapping to SQLAlchemy parameter. Thanks dsully!
v0.14.0 (2017-08-03)¶
Make
declarative_basepass extra keyword arguments tosqlalchemy.ext.declarative.declarative_base.Remove
ModelBase.metaclassandModelBase.metadatahooks for hoisting those values todeclarative_base(). Instead, pass optionalmetadataandmetaclassarguments directly todeclarative_base. (breaking change)Replace broken
declarative_basedecorator usage with new decorator-only function,as_declarative. Previously,@declarative_baseonly worked as a decorator when not “called” (i.e.@declarative_baseworked but@declarative_base(...)failed).
v0.13.0 (2017-07-11)¶
Add
ModelBase.__dict_args__attribute for providing arguments toModelBase.to_dict.Add
adaptersoption toModelBase.__dict_args__for mapping model value types to custom serializatoin handlers duringModelBase.to_dict()call.
v0.12.1 (2017-04-04)¶
Bump minimum requirement for pydash to
v4.0.1.Revert removal of
Query.pluckbut nowpluckworks with a deep path and path list (e.g.['a', 'b', 0, 'c']to get'value'in{'a': {'b': [{'c': 'value'}]}}which is something thatQuery.mapdoesn’t support.
v0.12.0 (2017-04-03)¶
Bump minimum requirement for pydash to
v4.0.0. (breaking change)Remove
Query.pluckin favor orQuery.mapsincemapcan do everythingpluckcould. (breaking change)Rename
Query.index_bytoQuery.key_by. (breaking change)Rename
callbackargument toiterateeforQuerymethods:key_bystack_bymapreducereduce_right
v0.11.0 (2017-03-10)¶
Make
SQLClient.save()update the declarative model registry whenever an model class isn’t in it. This allows saving to work when aSQLClientinstance was created before models have been imported yet.Make
SQLClient.expunge()support multiple instances.Make
SQLClient.save()andSQLQuery.save()handle saving empty dictionaries.
v0.10.0 (2017-02-13)¶
Add
engine_optionsargument toSQLClient()to provide additional engine options beyond what is supported by theconfigargument.Add
SQLClient.bulk_insertfor performing an INSERT with a multi-row VALUES clause.Add
SQLClient.bulk_insert_manyfor performing anexecutemany()DBAPI call.Add additional
SQLClient.sessionproxy properties onSQLClient.<proxy>:bulk_insert_mappingsbulk_save_objectsbulk_update_mappingsis_activeis_modifiedno_autoflushpreapre
Store
SQLClient.modelsas a staticdictinstead of computed property but recompute if an attribute error is detected forSQLClient.<Model>to handle the case of a late model class import.Fix handling of duplicate base class names during
SQLClient.modelscreation for model classes that are defined in different submodules. Previously, duplicate model class names prevented those models from being saved viaSQLClient.save().
v0.9.1 (2017-01-12)¶
Fix handling of
scopefuncoption inSQLClient.create_session.
v0.9.0 (2017-01-10)¶
Add
session_classargument toSQLClient()to override the default session class used by the session maker.Add
session_optionsargument toSQLClient()to provide additional session options beyond what is supported by theconfigargument.
v0.8.0 (2016-12-09)¶
Rename
sqlservice.QuerytoSQLQuery. (breaking change)Remove
sqlservice.SQLServiceclass in favor of utilizingSQLQueryfor thesaveanddestroymethods for a model class. (breaking change)Add
SQLQuery.save().Add
SQLQuery.destroy().Add
SQLQuery.model_classproperty.Replace
service_classargument withquery_classinSQLClient.__init__(). (breaking change)Remove
SQLClient.services. (breaking change)When a model class name is used for attribute access on a
SQLClientinstance, return an instance ofSQLQuery(ModelClass)instead ofSQLService(ModelClass). (breaking change)
v0.7.2 (2016-11-29)¶
Fix passing of
synchronize_sessionargument inSQLService.destroyandSQLClient.destroy. Argument was mistakenly not being used when calling underlying delete method.
v0.7.1 (2016-11-04)¶
Add additional database session proxy attributes to
SQLClient:SQLClient.scalar -> SQLClient.session.scalarSQLClient.invalidate -> SQLClient.session.invalidateSQLClient.expire -> SQLClient.session.expireSQLClient.expire_all -> SQLClient.session.expire_allSQLClient.expunge -> SQLClient.session.expungeSQLClient.expunge_all -> SQLClient.session.expunge_allSQLClient.prune -> SQLClient.session.prune
Fix compatibility issue with pydash
v3.4.7.
v0.7.0 (2016-10-28)¶
Add
core.make_identityfactory function for easily creating basic identity functions from a list of model column objects that can be used withsave().Import
core.save,core.destroy,core.transaction, andcore.make_identityinto make package namespace.
v0.6.3 (2016-10-17)¶
Fix model instance merging in
core.savewhen providing a custom identity function.
v0.6.2 (2016-10-17)¶
Expose
identityargument inSQLClient.saveandSQLService.save.
v0.6.1 (2016-10-17)¶
Fix bug where the
modelsvariable was mistakenly redefined during loop iteration incore.save.
v0.6.0 (2016-10-17)¶
Add
identityargument tosavemethod to allow a custom identity function to support upserting on something other than just the primary key values.Make
Queryentity methodsentities,join_entities, andall_entitiesreturn entity objects instead of model classes. (breaking change)Add
Querymethodsmodel_classes,join_model_classes, andall_model_classesreturn the model classes belonging to a query.
v0.5.1 (2016-09-28)¶
Fix issue where calling
<Model>.update(data)did not correctly update a relationship field when both<Model>.<relationship-column>anddata[<relationship-column>]were both instances of a model class.
v0.5.0 (2016-09-20)¶
Allow
Service.find_one,Service.find, andQuery.searchto accept a list of lists as the criterion argument.Rename ModelBase metaclass class attribute from
ModelBase.MetatoModelBase.metaclass. (breaking change)Add support for defining the
metadataobject onModelBase.metadataand having it used when callingdeclarative_base.Add
metadataandmetaclassarguments todeclarative_basethat taken precedence over the corresponding class attributes set on the passed in declarative base type.Rename Model argument/attribute in
SQLClientto__init__tomodel_class. (breaking change)Remove
Query.topmethod. (breaking change)Proxy
SQLService.__getattr__togetattr(SQLService.query(), attr)so thatSQLServicenow acts as a proxy to a query instance that uses itsmodel_classas the primary query entity.Move
SQLService.findandSQLService.find_onetoQuery.Improve docs.
v0.4.3 (2016-07-11)¶
Fix issue where updating nested relationship values can lead to conflicting state assertion error in SQLAlchemy’s identity map.
v0.4.2 (2016-07-11)¶
Fix missing
beforeandaftercallback argument passing fromcore.savetocore._add.
v0.4.1 (2016-07-11)¶
Fix missing
beforeandaftercallback argument passing fromSQLService.savetoSQLClient.save.
v0.4.0 (2016-07-11)¶
Add support for
beforeandaftercallbacks incore.save,SQLClient.save, andSQLService.savewhich are invoked before/aftersession.addis called for each model instance.
v0.3.0 (2016-07-06)¶
Support additional engine and session configuration values for
SQLClient.New engine config options:
SQL_ECHO_POOLSQL_ENCODINGSQL_CONVERT_UNICODESQL_ISOLATION_LEVEL
New session config options:
SQL_EXPIRE_ON_COMMIT
Add
SQLClient.reflectmethod.Rename
SQLClient.service_registryandSQLClient.model_registrytoservicesandmodels. (breaking change)Support
SQLClient.__getitem__as proxy toSQLClient.__getattr__where bothdb[User]anddb['User']both map todb.User.Add
SQLService.countmethod.Add
Querymethods:index_by: ConvertsQuery.all()to adictof models indexed bycallback(pydash.index_by)stack_by: ConvertsQuery.all()to adictof lists of models indexed bycallback(pydash.group_by)map: MapsQuery.all()to acallback(pydash.map_)reduce: ReducesQuery.all()throughcallback(pydash.reduce_)reduce_right: ReducesQuery.all()throughcallbackfrom right (pydash.reduce_right)pluck: Retrieves value of of specified property from all elements ofQuery.all()(pydash.pluck)chain: Initializes a chain object withQuery.all()(pydash.chain)
Rename
Queryproperties: (breaking change)model_classestoentitiesjoined_model_classestojoin_entitiesall_model_classestoall_entities
v0.2.0 (2016-06-15)¶
Add Python 2.7 compatibility.
Add concept of
model_registryandservice_registrytoSQLClientclass:SQLClient.model_registryreturns mapping of ORM model names to ORM model classes bound toSQLClient.Model.SQLServiceinstances are created with each model class bound to declarative base,SQLClient.Modeland stored inSQLClient.service_registry.Access to each model class
SQLServiceinstance is available via attribute access toSQLClient. The attribute name corresponds to the model class name (e.g. given aUserORM model, it would be accessible atsqlclient.User.
Add new methods to
SQLClientclass:save: Generic saving of model class instances similar toSQLService.savebut works for any model class instance.destroy: Generic deletion of model class instances ordictcontaining primary keys where model class is explicitly passed in. Similar toSQLService.destroy.
Rename
SQLService.deletetodestroy. (breaking change)Change
SQLServiceinitialization signature toSQLService(db, model_class)and remove class attributemodel_classin favor of instance attribute. (breaking change)Add properties to
SQLClientclass:service_registrymodel_registry
Add properties to
Queryclass:model_classes: Returns list of model classes used to duringQuerycreation.joined_model_classes: Returns list of joined model classes ofQuery.all_model_classes: ReturnsQuery.model_classes+Query.joined_model_classes.
Remove methods from
SQLServiceclass: (breaking change)query_onequery_manydefault_order_by(default order by determination moved toQuery.search)
Remove
sqlservice.service.transactiondecorator in favor of using transaction context manager within methods. (breaking change)Fix incorrect passing of
SQL_DATABASE_URIvalue toSQLClient.create_engineinSQLClient.__init__.
v0.1.0 (2016-05-24)¶
First release.