Merge pull request #175 from datastax/PYTHON-114
Add docs section for UDTs
This commit is contained in:
@@ -30,6 +30,9 @@ Contents
|
||||
:doc:`query_paging`
|
||||
Notes on paging large query results.
|
||||
|
||||
:doc:`user_defined_types`
|
||||
Working with Cassandra 2.1's user-defined types.
|
||||
|
||||
:doc:`security`
|
||||
An overview of the security features of the driver.
|
||||
|
||||
@@ -58,6 +61,7 @@ If you would like to contribute, please feel free to open a pull request.
|
||||
performance
|
||||
query_paging
|
||||
security
|
||||
user_defined_types
|
||||
|
||||
Indices and Tables
|
||||
==================
|
||||
|
||||
@@ -63,6 +63,8 @@ If no class is registered for a user-defined type, query results
|
||||
will use a ``namedtuple`` class and data may only be inserted
|
||||
though prepared statements.
|
||||
|
||||
See :ref:`udts` for more details.
|
||||
|
||||
Customizing Encoders for Non-prepared Statements
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Starting with version 2.1 of the driver, it is possible to customize
|
||||
|
||||
90
docs/user_defined_types.rst
Normal file
90
docs/user_defined_types.rst
Normal file
@@ -0,0 +1,90 @@
|
||||
.. _udts:
|
||||
|
||||
User Defined Types
|
||||
==================
|
||||
Cassandra 2.1 introduced user-defined types (UDTs). You can create a
|
||||
new type through ``CREATE TYPE`` statements in CQL::
|
||||
|
||||
CREATE TYPE address (street text, zip int);
|
||||
|
||||
Version 2.1 of the python driver adds support for user-defined types.
|
||||
|
||||
Registering a Class to Map to a UDT
|
||||
-----------------------------------
|
||||
You can tell the python driver to return columns of a specific UDT as
|
||||
instances of a class by registering them with your :class:`~.Cluster`
|
||||
instance through :meth:`.Cluster.register_user_type`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cluster = Cluster(protocol_version=3)
|
||||
session = cluster.connect()
|
||||
session.set_keyspace('mykeyspace')
|
||||
session.execute("CREATE TYPE address (street text, zipcode int)")
|
||||
session.execute("CREATE TABLE users (id int PRIMARY KEY, location address)")
|
||||
|
||||
# create a class to map to the "address" UDT
|
||||
class Address(object):
|
||||
|
||||
def __init__(self, street, zipcode):
|
||||
self.street = street
|
||||
self.zipcode = zipcode
|
||||
|
||||
cluster.register_user_type('mykeyspace', 'address', Address)
|
||||
|
||||
# insert a row using an instance of Address
|
||||
session.execute("INSERT INTO users (id, location) VALUES (%s, %s)",
|
||||
(0, Address("123 Main St.", 78723)))
|
||||
|
||||
# results will include Address instances
|
||||
results = session.execute("SELECT * FROM users")
|
||||
row = results[0]
|
||||
print row.id, row.location.street, row.location.zipcode
|
||||
|
||||
Using UDTs Without Registering Them
|
||||
-----------------------------------
|
||||
Although it is recommended to register your types with
|
||||
:meth:`.Cluster.register_user_type`, the driver gives you some options
|
||||
for working with unregistered UDTS.
|
||||
|
||||
When you use prepared statements, the driver knows what data types to
|
||||
expect for each placeholder. This allows you to pass any object you
|
||||
want for a UDT, as long as it has attributes that match the field names
|
||||
for the UDT:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
cluster = Cluster(protocol_version=3)
|
||||
session = cluster.connect()
|
||||
session.set_keyspace('mykeyspace')
|
||||
session.execute("CREATE TYPE address (street text, zipcode int)")
|
||||
session.execute("CREATE TABLE users (id int PRIMARY KEY, location address)")
|
||||
|
||||
class Foo(object):
|
||||
|
||||
def __init__(self, street, zipcode, otherstuff):
|
||||
self.street = street
|
||||
self.zipcode = zipcode
|
||||
self.otherstuff = otherstuff
|
||||
|
||||
insert_statement = session.prepare("INSERT INTO users (id, location) VALUES (?, ?)")
|
||||
|
||||
# since we're using a prepared statement, we don't *have* to register
|
||||
# a class to map to the UDT to insert data. The object just needs to have
|
||||
# "street" and "zipcode" attributes (which Foo does):
|
||||
session.execute(insert_statement, [0, Foo("123 Main St.", 78723, "some other stuff")]
|
||||
|
||||
# when we query data, UDT columns that don't have a class registered
|
||||
# will be returned as namedtuples:
|
||||
results = session.execute("SELECT * FROM users")
|
||||
first_row = results[0]
|
||||
address = first_row.address
|
||||
print address # prints "Address(street='123 Main St.', zipcode=78723)"
|
||||
street = address.street
|
||||
zipcode = address.street
|
||||
|
||||
As shown in the code example, inserting data for UDT columns without registering
|
||||
a class works fine for prepared statements. However, **you must register a
|
||||
class to insert UDT columns with unprepared statements**. You can still query
|
||||
UDT columns without registered classes using unprepared statements, they will
|
||||
simply return ``namedtuple`` instances (just like prepared statements do).
|
||||
Reference in New Issue
Block a user