Skip to content

Commit fe16669

Browse files
committed
Merge pull request #175 from datastax/PYTHON-114
Add docs section for UDTs
2 parents c7288aa + 11904ed commit fe16669

3 files changed

Lines changed: 96 additions & 0 deletions

File tree

docs/index.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Contents
3030
:doc:`query_paging`
3131
Notes on paging large query results.
3232

33+
:doc:`user_defined_types`
34+
Working with Cassandra 2.1's user-defined types.
35+
3336
:doc:`security`
3437
An overview of the security features of the driver.
3538

@@ -58,6 +61,7 @@ If you would like to contribute, please feel free to open a pull request.
5861
performance
5962
query_paging
6063
security
64+
user_defined_types
6165

6266
Indices and Tables
6367
==================

docs/upgrading.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ If no class is registered for a user-defined type, query results
6363
will use a ``namedtuple`` class and data may only be inserted
6464
though prepared statements.
6565

66+
See :ref:`udts` for more details.
67+
6668
Customizing Encoders for Non-prepared Statements
6769
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6870
Starting with version 2.1 of the driver, it is possible to customize

docs/user_defined_types.rst

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.. _udts:
2+
3+
User Defined Types
4+
==================
5+
Cassandra 2.1 introduced user-defined types (UDTs). You can create a
6+
new type through ``CREATE TYPE`` statements in CQL::
7+
8+
CREATE TYPE address (street text, zip int);
9+
10+
Version 2.1 of the python driver adds support for user-defined types.
11+
12+
Registering a Class to Map to a UDT
13+
-----------------------------------
14+
You can tell the python driver to return columns of a specific UDT as
15+
instances of a class by registering them with your :class:`~.Cluster`
16+
instance through :meth:`.Cluster.register_user_type`:
17+
18+
.. code-block:: python
19+
20+
cluster = Cluster(protocol_version=3)
21+
session = cluster.connect()
22+
session.set_keyspace('mykeyspace')
23+
session.execute("CREATE TYPE address (street text, zipcode int)")
24+
session.execute("CREATE TABLE users (id int PRIMARY KEY, location address)")
25+
26+
# create a class to map to the "address" UDT
27+
class Address(object):
28+
29+
def __init__(self, street, zipcode):
30+
self.street = street
31+
self.zipcode = zipcode
32+
33+
cluster.register_user_type('mykeyspace', 'address', Address)
34+
35+
# insert a row using an instance of Address
36+
session.execute("INSERT INTO users (id, location) VALUES (%s, %s)",
37+
(0, Address("123 Main St.", 78723)))
38+
39+
# results will include Address instances
40+
results = session.execute("SELECT * FROM users")
41+
row = results[0]
42+
print row.id, row.location.street, row.location.zipcode
43+
44+
Using UDTs Without Registering Them
45+
-----------------------------------
46+
Although it is recommended to register your types with
47+
:meth:`.Cluster.register_user_type`, the driver gives you some options
48+
for working with unregistered UDTS.
49+
50+
When you use prepared statements, the driver knows what data types to
51+
expect for each placeholder. This allows you to pass any object you
52+
want for a UDT, as long as it has attributes that match the field names
53+
for the UDT:
54+
55+
.. code-block:: python
56+
57+
cluster = Cluster(protocol_version=3)
58+
session = cluster.connect()
59+
session.set_keyspace('mykeyspace')
60+
session.execute("CREATE TYPE address (street text, zipcode int)")
61+
session.execute("CREATE TABLE users (id int PRIMARY KEY, location address)")
62+
63+
class Foo(object):
64+
65+
def __init__(self, street, zipcode, otherstuff):
66+
self.street = street
67+
self.zipcode = zipcode
68+
self.otherstuff = otherstuff
69+
70+
insert_statement = session.prepare("INSERT INTO users (id, location) VALUES (?, ?)")
71+
72+
# since we're using a prepared statement, we don't *have* to register
73+
# a class to map to the UDT to insert data. The object just needs to have
74+
# "street" and "zipcode" attributes (which Foo does):
75+
session.execute(insert_statement, [0, Foo("123 Main St.", 78723, "some other stuff")]
76+
77+
# when we query data, UDT columns that don't have a class registered
78+
# will be returned as namedtuples:
79+
results = session.execute("SELECT * FROM users")
80+
first_row = results[0]
81+
address = first_row.address
82+
print address # prints "Address(street='123 Main St.', zipcode=78723)"
83+
street = address.street
84+
zipcode = address.street
85+
86+
As shown in the code example, inserting data for UDT columns without registering
87+
a class works fine for prepared statements. However, **you must register a
88+
class to insert UDT columns with unprepared statements**. You can still query
89+
UDT columns without registered classes using unprepared statements, they will
90+
simply return ``namedtuple`` instances (just like prepared statements do).

0 commit comments

Comments
 (0)