# Lightweight Transactions (Compare-and-set)

Lightweight Transactions (LWTs) are mostly pass-through CQL for the driver. However,
the server returns some specialized results indicating the outcome and optional state
preceding the transaction.

For pertinent execution parameters, see [`Statement.serial_consistency_level`](https://python-driver.docs.scylladb.com/stable/api/cassandra/query.md#cassandra.query.Statement.serial_consistency_level).

This section discusses working with specialized result sets returned by the server for LWTs,
and how to work with them using the driver.

## Specialized Results

The result returned from a LWT request is always a single row result. It will always have
prepended a special column named `[applied]`. How this value appears in your results depends
on the row factory in use. See below for examples.

The value of this `[applied]` column is boolean value indicating whether or not the transaction was applied.
If `True`, it is the only column in the result. If `False`, the additional columns depend on the LWT operation being
executed:

- When using a `UPDATE ... IF "col" = ...` clause, the result will contain the `[applied]` column, plus the existing columns
  and values for any columns in the `IF` clause (and thus the value that caused the transaction to fail).
- When using `INSERT ... IF NOT EXISTS`, the result will contain the `[applied]` column, plus all columns and values
  of the existing row that rejected the transaction.
- `UPDATE .. IF EXISTS` never has additional columns, regardless of `[applied]` status.

How the `[applied]` column manifests depends on the row factory in use. Considering the following (initially empty) table:

```default
CREATE TABLE test.t (
    k int PRIMARY KEY,
    v int,
    x int
)
```

… the following sections show the expected result for a number of example statements, using the three base row factories.

### named_tuple_factory (default)

The name `[applied]` is not a valid Python identifier, so the square brackets are actually removed
from the attribute for the resulting `namedtuple`. The row always has a boolean column `applied` in position 0:

```default
>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
Row(applied=True)

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
Row(applied=False, k=0, v=0, x=None)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
Row(applied=True)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
Row(applied=False, v=1, x=2)
```

### tuple_factory

This return type does not refer to names, but the boolean value `applied` is always present in position 0:

```default
>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
(True,)

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
(False, 0, 0, None)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
(True,)

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
(False, 1, 2)
```

### dict_factory

The retuned `dict` contains the `[applied]` key:

```default
>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
{u'[applied]': True}

>>> session.execute("INSERT INTO t (k,v) VALUES (0,0) IF NOT EXISTS")
{u'x': 2, u'[applied]': False, u'v': 1}

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0")
{u'x': None, u'[applied]': False, u'k': 0, u'v': 0}

>>> session.execute("UPDATE t SET v = 1, x = 2 WHERE k = 0 IF v =0 AND x = 1")
{u'[applied]': True}
```
