### 1.5.5.1 How It Works

Each `QueryBuilder` object returns a number of `Query` objects. These `Query` objects have most of there operators overloaded so that they return correctly encoded strings when compared to values or other`Query` objects. Unfortunately it is not possible to use `and`, `or` or `not` operators so instead the `Query` objects use `&`, `|` or `~` instead.

It is actually possible to write your where clauses as SQL if you are using an SQL driver. Changing the first line of our from `where = query.firstName == "John"` to `where = 'Person.firstName="John"'` we have:

    >>> where = 'Person.firstName="John"'
    >>> rows = database['Person'].select(where=where)
    >>> print rows
    {'Smith': <Row firstName="John", surname="Smith">}

and we get the same result. In fact the code `column.firstName == 'John'` from the first example actually returns the SQL encoded string (`'Person.firstName="John"'`) so the two approaches are the same.

There are two advantages of using the `QueryBuilder` approach rather than writing your own where clauses as strings:

1. The `QueryBuilder` automatiacally handles any data conversion. This is pretty trivial in the example above as the string `"John"` requires on conversion but if you are doing a query on a date it would be a little more complicated. Using the `QueryBuilder` takes care of it for you.
2. If a new driver was written for the `web.database.object` module it may require where clauses in a different format from SQL strings. If you write your code using a `QueryBuilder` you can avoid this complication.