diff --git a/README.md b/README.md
index e76539286b96ed90e7b0651d04e21db49267e979..bb158a6e9bd379cfd1d0cb767cabc4017edb6cb7 100644
--- a/README.md
+++ b/README.md
@@ -29,9 +29,9 @@ The advantage of using a querybuilder are manyfold:
 
 # Quickstart
 
-~~~python
+~~~python in
 from uuid import UUID, uuid4 as uuid_gen
-from querybuilder.schemas.helper import table
+from querybuilder.helpers import table
 
 @table
 class person:
@@ -43,27 +43,27 @@ class person:
 This code snippet creates a (non-mutable) table `person`. From those object we can build
 `queries`. Those are not tied to any database.
 
-~~~python
-q = person.select([person.c.birth_year, person.c.name]) # person.c is a shorthand for person.columns
+~~~python in
+q = Person.select([Person.c.birth_year, Person.c.name]) # Person.c is a shorthand for Person.columns
 ~~~
 
 We can then get the string representation of the query `q` by using `str(q)` which returns
 
-~~~sql
-SELECT person.birth_year, person.name FROM person
+~~~sql out (in: "print(str(q))")
+SELECT Person.birth_year, Person.name FROM Person
 ~~~
 
 We can apply simple transformation to `q`. As queries (and most object)
 are immutable by design, each operation returns a new updated query object.
 
-~~~python
+~~~python in
 q2 = q.add_where(q.c.birth_year.gt(1800)).set_limit(10).set_columns(["name"])
 ~~~
 
 Then, formatting the query with `str(q2)` gives:
 
-~~~sql
-SELECT person.name FROM person WHERE person.birth_year > 1800 FETCH FIRST 10 ROWS ONLY
+~~~sql out (in: "print(str(q2))")
+SELECT Person.name FROM Person WHERE Person.birth_year > 1800 FETCH FIRST 10 ROWS ONLY
 ~~~
 
 ## Using an actual database backend
@@ -77,16 +77,16 @@ possible that some queries raise errors when sent to some DBMSs.
 
 ### SQLite
 
-~~~python
-from querybuilder.drivers.sqlite.connector import Connector
+~~~python in
+from querybuilder.drivers.sqlite import Connector
 
 db = Connector(":memory:") # The ":memory:" here is SQLite-specific for in-memory non-persistent database.
 ~~~
 
 We can create the table `person` using `person.create()` which produces the following query:
 
-~~~sql
-CREATE TABLE person (id UUID, name TEXT, birth_year INTEGER)
+~~~sql out (in: "print(str(Person.create()))")
+CREATE TABLE Person (id UUID, name TEXT, birth_year INTEGER)
 ~~~
 
 SQLite does not support `UUID`.
@@ -100,25 +100,25 @@ UserWarning: sqlite does not support UUID, using TEXT type instead
 
 Here is how the query is executed in the SQLite database `db`:
 
-~~~python
-db.execute(person.create())
+~~~python in
+db.execute(Person.create())
 ~~~
 
 We can then create a query to populate the table:
 
-~~~python
-q_insert = person.insert_values(in_columns=(person.c[["name", "birth_year"]]), values=[("Dijkstra", 1930), ("Euler", 1707), ("Steiner", 1796)])
+~~~python in
+q_insert = Person.insert_values(in_columns=(Person.c[["name", "birth_year"]]), values=[("Dijkstra", 1930), ("Euler", 1707), ("Steiner", 1796)])
 db.execute(q_insert)
 ~~~
 
 Now, our table admit three tuples:
-~~~python
-cursor = db.execute(person.select(person.c[1:], orderby=person.c.name))
+~~~python in
+cursor = db.execute(Person.select(Person.c[1:], orderby=Person.c.name))
 results = list(cursor.fetchall())
 print(results)
 ~~~
 gives:
-~~~python
+~~~python out
 [('Dijkstra', 1930), ('Euler', 1707), ('Steiner', 1796)]
 ~~~
 
@@ -131,64 +131,64 @@ The values are safely embedded within `q_insert` (click me to see details).
 </summary>
 
 The query `q_insert` above actually embedded the values within its formatting as shown by its pretty printing `q_insert.pretty_print()`:
-~~~sql
-INSERT INTO person (name, birth_year) VALUES (?, 1930), (?, 1707), (?, 1796)
+~~~sql out (in: "print(str(q_insert))")
+INSERT INTO Person (name, age) VALUES (?, 1930), (?, 1707), (?, 1796)
 -- ↖{0: 'Dijkstra', 1: 'Euler', 2: 'Steiner'}
 ~~~
 
 But it is still safe against injection as the string values will be passed as placeholders to an underlying prepared query:
 
-~~~python
-q_inject = person.insert_values(in_columns=person.c[1:], values= [("\";DROP TABLE person;", 0000)])
+~~~python in
+q_inject = Person.insert_values(in_columns=Person.c[1:], values= [("\";DROP TABLE Person;", 0000)])
 db.execute(q_inject)
 cursor = db.execute(person.select(person.c[1:], where=person.c.birth_year.eq(0)))
 results = list(cursor.fetchall())
 print(results)
 ~~~
 gives:
-~~~python
-[('";DROP TABLE person;', 0)]
+~~~python out
+[('"; DROP TABLE Person;"', 0)]
 ~~~
 
 </details>
 </p>
 
 We can also define updates easily, _e.g._, with the following query:
-~~~python
-q_upd = person.update(dict(id=uuid_gen()), where=person.c.name.eq("Dijkstra"))
+~~~python in
+q_upd = Person.update(dict(id=uuid_gen()), where=Person.c.name.eq("Dijkstra"))
 db.execute(q_upd)
 ~~~
 which pretty prints as:
-~~~sql
-UPDATE person SET id = ? WHERE person.name = ?
+~~~sql out (in: "print(str(q_upd))")
+UPDATE Person SET id = ? WHERE Person.name = ?
 -- ↖{0: UUID('33525c22-f938-4256-b673-e595ff6df828'), 1: 'Dijkstra'}
 ~~~
 
 Of course, deletions are also possible, _e.g._:
-~~~python
-q_del = person.delete(where=person.c.id.isnull())
+~~~python in
+q_del = Person.delete(where=Person.c.id.isnull())
 db.execute(q_del)
 ~~~
 is formatted as:
-~~~sql
-DELETE FROM person WHERE person.id IS NULL
+~~~sql out (in: "print(str(q_del))")
+DELETE FROM Person WHERE Person.id IS NULL
 ~~~
 
 If we throw in more complicated tables,
 we will see that the querybuilder
 can handle some DBMS specificities on its own.
 
-~~~python
-from querybuilder.schemas.helper import table, ColumnSpec
+~~~python in
+from querybuilder.helpers import table, colspec
 @table
 class tag:
-    id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
+    id: colspec(int, primary_key=True, generated_as_identity=True)
     name: str
 ~~~
 
 Calling `tag.create()` yields the following query:
 
-~~~SQL
+~~~sql out (in: "print(str(tag.create()))")
 CREATE TABLE tag (id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, name TEXT)
 ~~~
 
@@ -197,10 +197,10 @@ it is possible to rely on the `AUTOINCREMENT` feature for a similar results.
 This fallback can be observed using the `db.stringify` method
 which returns the dialect-aware (here SQLite) raw formatting of the query,
 namely the query that would be executed by `db.execute`.
-~~~python
+~~~python in
 db.stringify(tag.create())
 ~~~
-~~~SQL
+~~~sql out (in: "db.stringify(tag.create())")
 CREATE TABLE tag (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
 ~~~
 
@@ -208,31 +208,31 @@ CREATE TABLE tag (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
 Note that a warning message notifies the user that the
 `GENERATED ALWAYS AS IDENTITY` constraint has been imperfectly simulated
 by the `AUTOINCREMENT` feature of SQLite.
-~~~python
+~~~python in
 db.execute(tag.create())
 ~~~
 
 
 We can then populate the table through INSERT queries:
-~~~python
+~~~python in
 q_tag = tag.insert_values(in_columns=(tag.c.name,), values=[("mathematician",)])
 ~~~
 
 The string value is automatically passed through a placeholder to avoid SQL injections:
-~~~python
+~~~python in
 q_tag.pretty_print()
 ~~~
-~~~sql
+~~~sql out
 INSERT INTO tag (name) VALUES (?) -- ↖{0: 'mathematician'}
 ~~~
 
 Then to actually insert into the database we simply do:
-~~~python
+~~~python in
 db.execute(q_tag)
 ~~~
 
 We may also want to bulk insert without having to handle values directly by using placeholders.
-~~~python
+~~~python in
 q_tag_bulk = tag.insert_many(in_columns=(tag.c.name,))
 db.executemany(q_tag_bulk, [dict(name=f"value_{i}") for i in range(1000)])
 ~~~
@@ -248,7 +248,7 @@ The query `q_tag_bulk` contains a placeholder with no embedded values.
 Looking at `q_tag_bulk.pretty_print()`, we can see that it uses a placeholder,
 named `:name`,
 which is associated with the special object `MISSING` represented by `ø`.
-~~~sql
+~~~sql out (in: "q_tag_bulk.pretty_print()")
 INSERT INTO tag (name) VALUES (:name) -- ↖{name: ø}
 ~~~
 Indeed, `q_tag_bulk` does not embed the values for the placeholders:
@@ -263,14 +263,14 @@ as illustrated by the above execution.
 </p>
 
 We can also delete those useless tags with the following query:
-~~~python
+~~~python in
 q_delete = tag.delete(where=tag.c.name.like("value_%"))
 db.execute(q_delete)
 ~~~
 
 Finally, we can build a last table with references to connect tag with person:
 
-~~~python
+~~~python in
 @table
 class tag_person:
     person_id: person.c.id
@@ -280,8 +280,8 @@ db.execute(tag_person.create())
 
 The query given by `str(tag_person.create())` is:
 
-~~~sql
-CREATE TABLE tag_person (person_id UUID REFERENCES person(id), tag_id INTEGER REFERENCES tag(id))
+~~~sql out (in: "print(str(tag_person.create()))")
+CREATE TABLE tag_person(person_id TEXT REFERENCES Person(id), tag_id INTEGER REFERENCES tag(id))
 ~~~
 
 Again, within SQLite, the `UUID` type will fallback to `TEXT`.
@@ -291,45 +291,45 @@ the table definitions.
 
 Let us label Dijkstra as a Mathematician:
 
-~~~python
-condition = person.c.name.eq("Dijkstra") & tag.c.name.eq("mathematician")
-q_prod = person.product(tag).select(columns=(person.c.id, tag.c.id), where=condition)
+~~~python in
+condition = Person.c.name.eq("Dijkstra") & tag.c.name.eq("mathematician")
+q_prod = Person.product(tag).select(columns=(Person.c.id, tag.c.id), where=condition)
 ~~~
 
 The query `q_prod` is of the following shape:
 
-~~~sql
-SELECT person.id, tag.id
-FROM person, tag
-WHERE person.name = ? AND tag.name = ?
+~~~sql out (in: "q_prod.pretty_print()")
+SELECT Person.id, tag.id
+FROM Person, tag
+WHERE Person.name = ? AND tag.name = ?
 -- ↖{0: 'Dijkstra', 1: 'mathematician'}
 ~~~
 
 We can insert the result in `tag_person` with:
 
-~~~python
+~~~python in
 db.execute(tag_person.insert(query=q_prod))
 ~~~
 
 Let us check by getting the list of mathematicians using the following complex query
-~~~python
+~~~python in
 q_math = tag_person\
     .inner_join(tag, on=tag.c.id.eq(tag_person.c.tag_id))\
     .inner_join(person, on=person.c.id.eq(tag_person.c.person_id))\
     .select([person.c.name], where=tag.c.name.eq("mathematician"))
 ~~~
 which is formatted as
-~~~sql
-SELECT person.name FROM (tag_person INNER JOIN tag ON tag.id = tag_person.tag_id) INNER JOIN person ON person.id = tag_person.person_id WHERE tag.name = ?
+~~~sql out (in: "print(str(q_math))")
+SELECT Person.name FROM (tag_person INNER JOIN tag ON tag.tag_id = tag_person.id) INNER JOIN Person ON Person.id = tag_person.person_id WHERE tag.name = ?
 ~~~
 and whose execution
-~~~python
+~~~python in
 cursor = db.execute(q_math)
 results = list(cursor.fetchall())
 print(results)
 ~~~
 will return only `"Dijkstra"`
-~~~python
+~~~python out
 [("Dijkstra",)]
 ~~~
 
@@ -337,8 +337,8 @@ will return only `"Dijkstra"`
 
 The previous queries work seamlessly on PostgreSQL by simply using the PostgreSQL connector:
 
-~~~python
-from querybuilder.drivers.postgres.connector import Connector
+~~~python in
+from querybuilder.drivers.postgresql import Connector
 
 db = Connector() # Postgresql has default connection information
 ~~~
@@ -349,15 +349,15 @@ The only differences with respect to using the SQLite driver are:
 2.  We do not have warnings, since PostgreSQL has implementations
     of type `UUID`, and of `GENERATED ALWAYS AS IDENTITY`.
 
-~~~python
+~~~python in
 @table
-class person:
-    id : ColumnSpec(UUID, primary_key=True)
+class Person:
+    id : colspec(UUID, primary_key=True)
     name : str
     birth_year : int
 @table
 class tag:
-    id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
+    id: colspec(int, primary_key=True, generated_as_identity=True)
     name: str
 @table
 class tag_person:
@@ -371,7 +371,7 @@ db.execute(tag_person.create(temporary=True))
 Since PostgreSQL has no non-persistent in-memory database,
 we indicated `temporary=True` when generating the creation query of each table,
 so that `CREATE TEMPORARY TABLE` queries are produced.
-For instance, `str(person.create(temporary=True))` gives the query:
-~~~sql
-CREATE TEMPORARY TABLE person (id UUID PRIMARY KEY, name TEXT, birth_year INTEGER)
+For instance, `str(Person.create(temporary=True))` gives the query:
+~~~sql out (in: "print(str(Person.create(temporary=True)))")
+CREATE TEMPORARY TABLE Person (id UUID PRIMARY KEY, name TEXT, birth_year INTEGER)
 ~~~
diff --git a/doctest/readme_doctests.py b/doctest/readme_doctests.py
index 3f552269e34811d7a7d812240ec55c5b6c77f7f8..aae1c8e6ac1130a3295e4363f1cbd34c8a01191d 100644
--- a/doctest/readme_doctests.py
+++ b/doctest/readme_doctests.py
@@ -2,7 +2,7 @@
 >>> import querybuilder as qb
 >>> qb.settings['pretty_formatter'] = qb.formatting.formatter.StandardFormatter()
 >>> from uuid import UUID, uuid4 as uuid_gen
->>> from querybuilder.schemas.helper import table
+>>> from querybuilder.helpers import table
 >>> @table
 ... class person:
 ...     id: UUID
@@ -14,7 +14,7 @@
 >>> q2 = q.add_where(q.c.birth_year.gt(1800)).set_limit(10).set_columns(["name"])
 >>> str(q2)
 'SELECT person.name FROM person WHERE person.birth_year > 1800 FETCH FIRST 10 ROWS ONLY'
->>> from querybuilder.drivers.sqlite.connector import Connector
+>>> from querybuilder.drivers.sqlite import Connector
 >>> db = Connector(":memory:") # The ":memory:" here is SQLite-specific for in-memory non-persistent database.
 >>> str(person.create())
 'CREATE TABLE person (id UUID, name TEXT, birth_year INTEGER)'
@@ -41,10 +41,10 @@ UPDATE person SET id = ? WHERE person.name = ?
 >>> str(q_del)
 'DELETE FROM person WHERE person.id IS NULL'
 >>> _ = db.execute(q_del)
->>> from querybuilder.schemas.helper import table, ColumnSpec
+>>> from querybuilder.helpers import table, colspec
 >>> @table
 ... class tag:
-...     id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
+...     id: colspec(int, primary_key=True, generated_as_identity=True)
 ...     name: str
 >>> str(tag.create())
 'CREATE TABLE tag (id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY, name TEXT)'
@@ -84,16 +84,16 @@ SELECT person.id, tag.id FROM person, tag WHERE person.name = ? AND tag.name = ?
 >>> cursor = db.execute(q_math)
 >>> list(cursor.fetchall())
 [('Dijkstra',)]
->>> from querybuilder.drivers.postgres.connector import Connector
+>>> from querybuilder.drivers.postgres import Connector
 >>> db = Connector()
 >>> @table
 ... class person:
-...     id : ColumnSpec(UUID, primary_key=True)
+...     id : colspec(UUID, primary_key=True)
 ...     name : str
 ...     birth_year : int
 >>> @table
 ... class tag:
-...     id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
+...     id: colspec(int, primary_key=True, generated_as_identity=True)
 ...     name: str
 >>> @table
 ... class tag_person:
diff --git a/examples/networkdisk-attribute_data.py b/examples/networkdisk-attribute_data.py
index b7889a7040e33a53e8f9a78796b41deab461acb4..12ffb5dd38af1331c738d0687f89058cdd7546b9 100644
--- a/examples/networkdisk-attribute_data.py
+++ b/examples/networkdisk-attribute_data.py
@@ -1,5 +1,5 @@
 import querybuilder as qb
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.columns import (
     TableColumn,
     Placeholder,
     Named,
@@ -11,9 +11,9 @@ from querybuilder.queries.algebra.columns import (
     True_,
     False_,
 )
-from querybuilder.queries.algebra.relations import Table, View
-from querybuilder.schemas.constraints import *
-from querybuilder.schemas.schemas import Schema, DB
+from querybuilder.atoms.relations import Table, View
+from querybuilder.atoms.constraints import *
+from querybuilder.atoms.schemas import Schema, DB
 
 # nodes
 nid = TableColumn(
diff --git a/examples/networkdisk-independent_data.py b/examples/networkdisk-independent_data.py
index 827d57d6fc85a7618fdad6b724b3a18c199b19bf..d0bc1ca8cda023e9cfeb4126cd2ebd8157f84b5e 100644
--- a/examples/networkdisk-independent_data.py
+++ b/examples/networkdisk-independent_data.py
@@ -1,5 +1,5 @@
 import querybuilder as qb
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.columns import (
     TableColumn,
     Placeholder,
     Value,
@@ -11,9 +11,9 @@ from querybuilder.queries.algebra.columns import (
     False_,
     Named,
 )
-from querybuilder.queries.algebra.relations import Table, View
-from querybuilder.schemas.constraints import *
-from querybuilder.schemas.schemas import Schema, DB
+from querybuilder.atoms.relations import Table, View
+from querybuilder.atoms.constraints import *
+from querybuilder.atoms.schemas import Schema, DB
 
 # nodes
 nid = TableColumn(
diff --git a/examples/networkdisk-one_table.py b/examples/networkdisk-one_table.py
index 57435ef0c0f34b9a7d77602b8daa0df5656d781a..ac834b709761a8a2695c47c62d2fe6dacaf423e7 100644
--- a/examples/networkdisk-one_table.py
+++ b/examples/networkdisk-one_table.py
@@ -1,5 +1,5 @@
 import querybuilder as qb
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.columns import (
     TableColumn,
     Placeholder,
     Value,
@@ -11,9 +11,9 @@ from querybuilder.queries.algebra.columns import (
     False_,
     BooleanCombination,
 )
-from querybuilder.queries.algebra.relations import Table, View
-from querybuilder.schemas.constraints import *
-from querybuilder.schemas.schemas import Schema, DB
+from querybuilder.atoms.relations import Table, View
+from querybuilder.atoms.constraints import *
+from querybuilder.atoms.schemas import Schema, DB
 
 gid = TableColumn(
     int,
diff --git a/examples/networkdisk-rich-with-helper.py b/examples/networkdisk-rich-with-helper.py
index e07c29a70c7c09c65cf3d7a1d1e9d91f67e9b9d5..497e51ba11d24e9beed6d72c83390eb28557f972 100644
--- a/examples/networkdisk-rich-with-helper.py
+++ b/examples/networkdisk-rich-with-helper.py
@@ -1,29 +1,29 @@
-from querybuilder.schemas.helper import table, schema, ColumnSpec, make_column
+from querybuilder.helpers import table, schema, colspec, make_column
 
 
 @schema
 class networkdisk:
     class nodes:
-        id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
-        name: ColumnSpec(
+        id: colspec(int, primary_key=True, generated_as_identity=True)
+        name: colspec(
             str, not_null=True, unique=True, check=lambda col, rel: col.neq("")
         )
 
     class node_data:
-        id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
-        node: ColumnSpec(int, references="nodes.id", not_null=True)
-        key: ColumnSpec(str, not_null=True)
-        value: ColumnSpec(str, not_null=True)
+        id: colspec(int, primary_key=True, generated_as_identity=True)
+        node: colspec(int, references="nodes.id", not_null=True)
+        key: colspec(str, not_null=True)
+        value: colspec(str, not_null=True)
 
         @table.unique
         def _(table):
             return table.columns.node.tuple_with(table.columns.key)
 
     class edges:
-        id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
-        source: ColumnSpec(int, references="nodes.id", not_null=True)
-        target: ColumnSpec(int, references="nodes.id", not_null=True)
-        weight: ColumnSpec(float, not_null=True, default=1)
+        id: colspec(int, primary_key=True, generated_as_identity=True)
+        source: colspec(int, references="nodes.id", not_null=True)
+        target: colspec(int, references="nodes.id", not_null=True)
+        weight: colspec(float, not_null=True, default=1)
         with table.collector() as cons:
 
             @cons.unique
@@ -35,18 +35,18 @@ class networkdisk:
                 return table.columns.source.leq(table.columns.target)
 
     class edge_data:
-        id: ColumnSpec(int, primary_key=True, generated_as_identity=True)
-        edge: ColumnSpec(int, references="edges.id", not_null=True)
-        key: ColumnSpec(str, not_null=True)
-        value: ColumnSpec(str, not_null=True)
+        id: colspec(int, primary_key=True, generated_as_identity=True)
+        edge: colspec(int, references="edges.id", not_null=True)
+        key: colspec(str, not_null=True)
+        value: colspec(str, not_null=True)
 
         @table.unique
         def _(table):
             return table.columns.edge.tuple_with(table.columns.key)
 
     class graph_data:
-        key: ColumnSpec(str, primary_key=True)
-        value: ColumnSpec(str, not_null=True)
+        key: colspec(str, primary_key=True)
+        value: colspec(str, not_null=True)
 
     @schema.view
     def symedges(schema):
diff --git a/examples/networkdisk-shared_data.py b/examples/networkdisk-shared_data.py
index 5fdfd357199d1b19cab06dff501941fe77eee215..f2a12629f26672dbd5d4ed399fea92ceb5a372c3 100644
--- a/examples/networkdisk-shared_data.py
+++ b/examples/networkdisk-shared_data.py
@@ -1,5 +1,5 @@
 import querybuilder as qb
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.columns import (
     TableColumn,
     Placeholder,
     Value,
@@ -10,9 +10,9 @@ from querybuilder.queries.algebra.columns import (
     True_,
     False_,
 )
-from querybuilder.queries.algebra.relations import Table, View
-from querybuilder.schemas.constraints import *
-from querybuilder.schemas.schemas import Schema, DB
+from querybuilder.atoms.relations import Table, View
+from querybuilder.atoms.constraints import *
+from querybuilder.atoms.schemas import Schema, DB
 
 # nodes
 ndid = TableColumn(
diff --git a/examples/quickstart-tuto.py b/examples/quickstart-tuto.py
index 810c2f2b5ea00f09c49c34147321dd3ed9382b8c..6113bc734ba482a1870887fcc09fcb7d5393d145 100644
--- a/examples/quickstart-tuto.py
+++ b/examples/quickstart-tuto.py
@@ -1,5 +1,5 @@
-from querybuilder.schemas.helper import table, schema
-from querybuilder.queries.algebra.columns import (
+from querybuilder.helpers import table, schema
+from querybuilder.atoms.columns import (
     Value,
     Constant,
     Placeholder,
diff --git a/querybuilder/__init__.py b/querybuilder/__init__.py
index 07f2828ee5290c4c17c805dbf714e4bc2b1749bb..05be9961d6001ab811906977e8b2233c63b58cf2 100644
--- a/querybuilder/__init__.py
+++ b/querybuilder/__init__.py
@@ -1,10 +1,9 @@
 __version__ = "0.1"
 
 import querybuilder.queries as queries
-import querybuilder.schemas as schemas
+import querybuilder.atoms as atoms
+import querybuilder.helpers as helpers
 import querybuilder.drivers as drivers
 from querybuilder.settings import settings
 
 import querybuilder.post_init
-
-algebra = queries.algebra
diff --git a/querybuilder/atoms/__init__.py b/querybuilder/atoms/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..7acbb8b87e29c6e595aaaebded3b399566288812
--- /dev/null
+++ b/querybuilder/atoms/__init__.py
@@ -0,0 +1,6 @@
+import querybuilder.atoms.atoms
+import querybuilder.atoms.constraints
+import querybuilder.atoms.columns
+import querybuilder.atoms.relations
+import querybuilder.atoms.clauses
+import querybuilder.atoms.schemas
diff --git a/querybuilder/classes/atoms.py b/querybuilder/atoms/atoms.py
similarity index 100%
rename from querybuilder/classes/atoms.py
rename to querybuilder/atoms/atoms.py
diff --git a/querybuilder/queries/algebra/clauses.py b/querybuilder/atoms/clauses.py
similarity index 96%
rename from querybuilder/queries/algebra/clauses.py
rename to querybuilder/atoms/clauses.py
index 80c181b435030d48aa74157b22bf531ab0a8dff7..4f5f15818319e2c3db8d307c8de4ec5116a4d343 100644
--- a/querybuilder/queries/algebra/clauses.py
+++ b/querybuilder/atoms/clauses.py
@@ -1,9 +1,9 @@
 from __future__ import annotations
 from typing import Literal, Optional, Union, Tuple, Mapping
 import querybuilder.utils.constants as qbconstants
-import querybuilder.classes.atoms as atoms
-import querybuilder.queries.algebra.columns as columns
-import querybuilder
+import querybuilder.atoms.atoms as atoms
+import querybuilder.atoms.columns as columns
+import querybuilder as qb
 
 
 class ClauseWrapper(atoms.Atom):
@@ -127,7 +127,7 @@ class RelationClauseWrapper(ClauseWrapper):
     # This is not a column
     __slots__ = ("relation",)
 
-    def __init__(self, relation: querybuilder.queries.algebra.relations.Fromable):
+    def __init__(self, relation: qb.atoms.relations.Fromable):
         self.relation = relation
 
     def _get_subtokenize_kwargs(self, tokenizer):
@@ -157,7 +157,7 @@ class WithClause(ClauseWrapper):
 
     A WithClause can be obtained seamlessly from a With query:
     >>> from querybuilder.queries.dql import Select
-    >>> from querybuilder.queries.algebra.columns import Constant
+    >>> from querybuilder.atoms.columns import Constant
     >>> s = Select((Constant(int, 1),))
     >>> wc = s.as_with(name="T", materialized=True).to_definition_clause()
 
@@ -175,7 +175,7 @@ class WithClause(ClauseWrapper):
     def __init__(
         self,
         name: str,
-        query: querybuilder.queries.queries.Query,
+        query: qb.queries.queries.Query,
         materialized: Optional[bool] = None,
     ):
         self.name = name
diff --git a/querybuilder/queries/algebra/columns.py b/querybuilder/atoms/columns.py
similarity index 96%
rename from querybuilder/queries/algebra/columns.py
rename to querybuilder/atoms/columns.py
index 1d1f959afd79613b18097fe25ee9158af0ebde29..d97f8cc5274256e2a90ffa9c6049ecf5680cde1e 100644
--- a/querybuilder/queries/algebra/columns.py
+++ b/querybuilder/atoms/columns.py
@@ -16,10 +16,10 @@ from typing import (
 from querybuilder.utils.constants import MISSING, _MISSING_TYPE
 from querybuilder.utils.decorators import method_accepting_lambdas
 from querybuilder.utils.typing import NamedProto
-from querybuilder.classes.atoms import Atom
-import querybuilder.queries.algebra.relations as qbrelations
-from querybuilder.schemas.constraints import ColumnConstraint, ColumnCheck
-import querybuilder.classes.stores as qbstores
+from querybuilder.atoms.atoms import Atom
+import querybuilder.atoms.constraints as qbconstraints
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.utils.stores as qbstores
 from querybuilder.formatting.tokentree import TkTree
 import querybuilder as qb
 
@@ -173,8 +173,8 @@ class Column(Atom):
 
     def index(
         self, collation: Optional[str] = None, asc: Optional[bool] = None
-    ) -> qb.schemas.schemas.IndexedColumn:
-        return qb.schemas.schemas.IndexedColumn(self, collation=collation, asc=asc)
+    ) -> qb.atoms.schemas.IndexedColumn:
+        return qb.atoms.schemas.IndexedColumn(self, collation=collation, asc=asc)
 
     # BOOLEAN OPERATIONS
     @columnize
@@ -460,7 +460,7 @@ class Named(Column):
     --------
 
     A Named column is formatted as its full name if it has a parent:
-    >>> from querybuilder.queries.algebra.columns import Named
+    >>> from querybuilder.atoms.columns import Named
     >>> str(Named(int, "c", relation_name="T"))
     'T.c'
 
@@ -552,12 +552,12 @@ class TableColumn(Named):
     Examples
     --------
     A TableColumn is formatted as it were a Named column:
-    >>> from querybuilder.queries.algebra.columns import TableColumn
+    >>> from querybuilder.atoms.columns import TableColumn
     >>> str(TableColumn(int, "c", "T"))
     'T.c'
 
     Even if it has constraint(s):
-    >>> from querybuilder.schemas.constraints import ColumnUnique
+    >>> from querybuilder.atoms.constraints import ColumnUnique
     >>> str(TableColumn(str, "c", "T", constraints=(ColumnUnique(), )))
     'T.c'
 
@@ -571,7 +571,7 @@ class TableColumn(Named):
         name: str,
         relation_name: str,
         schema_name: Optional[str] = None,
-        constraints: Iterable[ColumnConstraint] = (),
+        constraints: Iterable[qbconstraints.ColumnConstraint] = (),
         # check constraint exposed so that its expression may involve the TableColumn to build (main use case)
         check: Union[Column, Callable[[Named], Column], None] = None,
         **kwargs,
@@ -585,10 +585,11 @@ class TableColumn(Named):
         )
         if callable(check):
             constraints = chain(
-                constraints, (ColumnCheck(check(Named(self.sqltype, self.name))),)
+                constraints,
+                (qbconstraints.ColumnCheck(check(Named(self.sqltype, self.name))),),
             )
         elif check:
-            constraints = chain(constraints, (ColumnCheck(check),))
+            constraints = chain(constraints, (qbconstraints.ColumnCheck(check),))
         cons: Iterable[NamedProto] = cast(Iterable[NamedProto], constraints)
         self.constraints = qbstores.UNamedStore(cons)
 
@@ -668,7 +669,7 @@ class Constant(Column):
     --------
 
     A Constant is formatted as its value:
-    >>> from querybuilder.queries.algebra.columns import Constant
+    >>> from querybuilder.atoms.columns import Constant
     >>> str(Constant(int, 42))
     '42'
     >>> str(Constant(str, "foo"))
@@ -733,7 +734,7 @@ class Value(Placeholder):
     --------
 
     A value is formatted as a placeholder
-    >>> from querybuilder.queries.algebra.columns import Value
+    >>> from querybuilder.atoms.columns import Value
     >>> str(Value(int, 42))
     '?'
     >>> str(Value(int, 42, key="k"))
@@ -779,7 +780,7 @@ class Default(Constant):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Default
+    >>> from querybuilder.atoms.columns import Default
     >>> str(Default())
     'DEFAULT'
     """
@@ -799,7 +800,7 @@ class True_(Constant):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import True_
+    >>> from querybuilder.atoms.columns import True_
     >>> str(True_())
     'True'
     """
@@ -862,7 +863,7 @@ class Null(Constant):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Null
+    >>> from querybuilder.atoms.columns import Null
     >>> str(Null())
     'NULL'
     """
@@ -895,7 +896,7 @@ def One(constant=True):
 
     Examples
     --------
-    >>> from querybuilder.queries.algebra.columns import Constant, One
+    >>> from querybuilder.atoms.columns import Constant, One
     >>> str(One())
     '1'
 
@@ -917,7 +918,7 @@ def Zero(constant=True):
 
     Examples
     --------
-    >>> from querybuilder.queries.algebra.columns import Constant, Zero
+    >>> from querybuilder.atoms.columns import Constant, Zero
     >>> str(Zero())
     '0'
 
@@ -992,7 +993,7 @@ class Pretuple(Expression, Generic[Col]):
     --------
 
     A Pretuple is formatted without parentheses:
-    >>> from querybuilder.queries.algebra.columns import Pretuple, Zero, One, Placeholder
+    >>> from querybuilder.atoms.columns import Pretuple, Zero, One, Placeholder
     >>> str(Pretuple(Zero(), One(), Placeholder(int)))
     '0, 1, ?'
     >>> str(Pretuple())
@@ -1069,7 +1070,7 @@ class Tuple(Pretuple):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Tuple, Zero, One, Placeholder
+    >>> from querybuilder.atoms.columns import Tuple, Zero, One, Placeholder
     >>> str(Tuple(Zero(), One(), Placeholder(int)))
     '(0, 1, ?)'
     >>> str(Tuple())
@@ -1116,7 +1117,7 @@ class Comparison(Expression):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Comparison, Placeholder, One
+    >>> from querybuilder.atoms.columns import Comparison, Placeholder, One
     >>> comp = Comparison('!=', Placeholder(int), One())
     >>> str(comp)
     '? != 1'
@@ -1203,7 +1204,7 @@ class InRelation(SubcolumnExpression):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.relations import Named as NamedRel
+    >>> from querybuilder.atoms.relations import Named as NamedRel
     >>> rel = NamedRel("foo")
     >>> inr = InRelation(One(), rel, not_in=True)
     >>> str(inr)
@@ -1272,7 +1273,7 @@ class Exists(Column):
 
     Examples
     --------
-    >>> from querybuilder.queries.algebra.relations import Named as NamedRel
+    >>> from querybuilder.atoms.relations import Named as NamedRel
     >>> str(Exists(NamedRel("foo")))
     'EXISTS (foo)'
     """
@@ -1328,7 +1329,7 @@ class BooleanCombination(Expression):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import BooleanCombination, False_, True_
+    >>> from querybuilder.atoms.columns import BooleanCombination, False_, True_
     >>> str(BooleanCombination("AND", True_(), False_()))
     'True AND False'
 
@@ -1378,7 +1379,7 @@ class Not(SubcolumnExpression):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Not, True_
+    >>> from querybuilder.atoms.columns import Not, True_
     >>> str(Not(True_()))
     'NOT True'
 
@@ -1505,7 +1506,7 @@ class Negate(SubcolumnExpression):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Negate, One
+    >>> from querybuilder.atoms.columns import Negate, One
     >>> str(Negate(One()))
     '-1'
     """
diff --git a/querybuilder/schemas/constraints.py b/querybuilder/atoms/constraints.py
similarity index 97%
rename from querybuilder/schemas/constraints.py
rename to querybuilder/atoms/constraints.py
index a1e839866a4a9fe0881fe22b227e8e3aee10f730..e343fd5ee196b3ce91e71cd4482c1a16bd15ed78 100644
--- a/querybuilder/schemas/constraints.py
+++ b/querybuilder/atoms/constraints.py
@@ -2,12 +2,12 @@ from __future__ import annotations
 from typing import Iterable, Optional, Self, Mapping
 from enum import Enum
 
-from querybuilder.queries.algebra.clauses import OnChangeWrapper
-import querybuilder.classes.atoms as qbatoms
-import querybuilder.queries.algebra.columns as qbcolumns
+from querybuilder.atoms.atoms import Atom
+from querybuilder.atoms.clauses import OnChangeWrapper
+import querybuilder.atoms.columns as qbcolumns
 
 
-class Constraint(qbatoms.Atom):
+class Constraint(Atom):
     __slots__ = ("_name", "deferrable", "initially_deferred")
 
     def __init__(
diff --git a/querybuilder/queries/algebra/relations.py b/querybuilder/atoms/relations.py
similarity index 88%
rename from querybuilder/queries/algebra/relations.py
rename to querybuilder/atoms/relations.py
index ce42013ff428ca3948ad00a8c05b4629c4e171ed..59f9cd0a720b2f851aba8433f0d49cb3ff2ab9d9 100644
--- a/querybuilder/queries/algebra/relations.py
+++ b/querybuilder/atoms/relations.py
@@ -14,29 +14,29 @@ from typing import (
 )
 from typing_extensions import ClassVar
 import abc, functools, itertools, operator
-from collections import namedtuple
-import querybuilder.utils.constants as qbconstants
+
+from querybuilder.utils.constants import JoinType
 from querybuilder.utils.decorators import method_accepting_lambdas
-import querybuilder.classes.atoms as atoms
-import querybuilder.classes.stores as qbstores
-import querybuilder.queries.algebra.columns as qbcolumns
+from querybuilder.utils.stores import Frozenmap, NamedStore, UNamedStore
 from querybuilder.utils.typing import NamedProto
+from querybuilder.atoms.atoms import Atom
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.clauses as qbclauses
 
 import querybuilder.queries as qbqueries
-import querybuilder
-import querybuilder.queries.algebra.clauses as clauses
+import querybuilder as qb
 
 
 # Base classes
-class Relation(atoms.Atom):
+class Relation(Atom):
     """Base class for relations"""
 
     __slots__ = ("columns",)
-    _column_store_factory: ClassVar[type] = qbstores.NamedStore
+    _column_store_factory: ClassVar[type] = NamedStore
     _scopable = False
 
     @property
-    def c(self) -> qbstores.NamedStore:
+    def c(self) -> NamedStore:
         return self.columns
 
     def __init__(self, columns=(), **kwargs):
@@ -94,7 +94,7 @@ class Fromable(Relation):
             Sequence[str | int | qbcolumns.Column | qbcolumns.Star]
         ] = None,
         **kwargs,
-    ) -> querybuilder.queries.dql.Select:
+    ) -> qbqueries.dql.Select:
         """
 
         Parameters
@@ -130,7 +130,7 @@ class Fromable(Relation):
                 else:
                     # assert isinstance(c, (int, str))
                     columns_to_select.append(self.columns.resolve(c))
-        return querybuilder.queries.dql.Select(
+        return qbqueries.dql.Select(
             from_=self, selected_columns=columns_to_select, **kwargs
         )
 
@@ -154,25 +154,25 @@ class Fromable(Relation):
         are exchanged.  E.g., `self.join(jointype, other, col)`
         returns the result of `other.join(jointype, self, col)`.
         """
-        jointype = qbconstants.JoinType(jointype)
+        jointype = JoinType(jointype)
         return Join(jointype, self, other, on=on)
 
-    cross_join = functools.partialmethod(join, qbconstants.JoinType.CROSS)
-    left_join = functools.partialmethod(join, qbconstants.JoinType.LEFT)
-    right_join = functools.partialmethod(join, qbconstants.JoinType.RIGHT)
-    full_join = functools.partialmethod(join, qbconstants.JoinType.FULL)
-    inner_join = functools.partialmethod(join, qbconstants.JoinType.INNER)
+    cross_join = functools.partialmethod(join, JoinType.CROSS)
+    left_join = functools.partialmethod(join, JoinType.LEFT)
+    right_join = functools.partialmethod(join, JoinType.RIGHT)
+    full_join = functools.partialmethod(join, JoinType.FULL)
+    inner_join = functools.partialmethod(join, JoinType.INNER)
 
     @functools.wraps(join)
     @method_accepting_lambdas
     def join_to(self, jointype, other, on=None):
         return other.join(jointype, self, on=on)
 
-    cross_join_to = functools.partialmethod(join_to, qbconstants.JoinType.CROSS)
-    left_join_to = functools.partialmethod(join_to, qbconstants.JoinType.LEFT)
-    right_join_to = functools.partialmethod(join_to, qbconstants.JoinType.RIGHT)
-    full_join_to = functools.partialmethod(join_to, qbconstants.JoinType.FULL)
-    inner_join_to = functools.partialmethod(join_to, qbconstants.JoinType.INNER)
+    cross_join_to = functools.partialmethod(join_to, JoinType.CROSS)
+    left_join_to = functools.partialmethod(join_to, JoinType.LEFT)
+    right_join_to = functools.partialmethod(join_to, JoinType.RIGHT)
+    full_join_to = functools.partialmethod(join_to, JoinType.FULL)
+    inner_join_to = functools.partialmethod(join_to, JoinType.INNER)
 
     @method_accepting_lambdas
     def product(self, other: Fromable, **kwargs) -> CartesianProduct:
@@ -262,7 +262,7 @@ class Aliased(Named):
         **kwargs,
     ):
         self.subrelation = subrelation
-        self.column_aliases: Mapping[int, str] = qbstores.Frozenmap(column_aliases)
+        self.column_aliases: Mapping[int, str] = Frozenmap(column_aliases)
 
         if self.column_aliases:
             for i, c in enumerate(self.subrelation.columns):
@@ -298,7 +298,7 @@ class Aliased(Named):
         kwargs = super()._get_subtokenize_kwargs(tokenizer)
         kwargs["subrelation"] = self.subrelation.subtokenize(tokenizer, scoped=True)
         if self.column_aliases:
-            CW = querybuilder.queries.algebra.clauses.AliasedColumn
+            CW = qb.atoms.clauses.AliasedColumn
             kwargs["columns"] = tuple(
                 map(
                     lambda c: CW(qbcolumns.unqualify(c)).subtokenize(tokenizer),
@@ -342,7 +342,7 @@ class With(Named):
         super().__init__(name, columns=columns)
 
     def to_definition_clause(self):
-        return clauses.WithClause(
+        return qbclauses.WithClause(
             name=self.name, query=self.subrelation, materialized=self.materialized
         )
 
@@ -529,7 +529,7 @@ class Join(CartesianProduct):
 
 class Table(Named):
     __slots__ = ("constraints",)
-    _column_store_factory = qbstores.UNamedStore
+    _column_store_factory = UNamedStore
     _preserve_table_column = True
 
     def __init__(
@@ -537,25 +537,25 @@ class Table(Named):
         name,
         columns: Iterable[qbcolumns.TableColumn],
         schema_name: Optional[str] = None,
-        constraints: Iterable[querybuilder.schemas.constraints.TableConstraint] = (),
+        constraints: Iterable[qb.atoms.constraints.TableConstraint] = (),
         **kwargs,
     ):
         cons: Iterable[NamedProto] = cast(Iterable[NamedProto], constraints)
-        self.constraints = qbstores.UNamedStore(cons)
+        self.constraints = UNamedStore(cons)
         super().__init__(name, schema_name=schema_name, columns=columns, **kwargs)
 
     def create(
         self,
         if_not_exists: bool = False,
-        as_query: Optional[querybuilder.queries.dql.DQLQuery] = None,
+        as_query: Optional[qbqueries.dql.DQLQuery] = None,
         temporary: bool = False,
-    ) -> querybuilder.queries.ddl.CreateTable:
-        return querybuilder.queries.ddl.CreateTable(
+    ) -> qbqueries.ddl.CreateTable:
+        return qbqueries.ddl.CreateTable(
             self, if_not_exists=if_not_exists, as_query=as_query, temporary=temporary
         )
 
     def drop(self, if_exists: bool = False, cascade: Optional[bool] = None):
-        return querybuilder.queries.ddl.Drop(self, if_exists=if_exists, cascade=cascade)
+        return qbqueries.ddl.Drop(self, if_exists=if_exists, cascade=cascade)
 
     @method_accepting_lambdas
     def alter(self, *args, **kwargs):
@@ -666,16 +666,12 @@ class Table(Named):
     def create_index(
         self,
         name: str,
-        columns: Tuple[
-            querybuilder.queries.algebra.columns.Column
-            | querybuilder.schemas.schemas.IndexedColumn,
-            ...,
-        ],
+        columns: tuple[qbcolumns.Column | qb.atoms.schemas.IndexedColumn, ...],
         unique: bool = False,
-        where: Optional[querybuilder.queries.algebra.columns.Expression] = None,
+        where: Optional[qbcolumns.Expression] = None,
         if_not_exists: bool = False,
-    ) -> querybuilder.queries.ddl.CreateIndex:
-        index = querybuilder.schemas.schemas.Index(name, self, columns, unique, where)
+    ) -> qbqueries.ddl.CreateIndex:
+        index = qb.atoms.schemas.Index(name, self, columns, unique, where)
         return index.create(if_not_exists=if_not_exists)
 
     def _substitute(self, substitutions: Mapping) -> Self:
@@ -695,13 +691,13 @@ class View(Named):
     def __init__(
         self,
         name: str,
-        defquery: querybuilder.queries.dql.DQLQuery,
+        defquery: qbqueries.dql.DQLQuery,
         schema_name: Optional[str] = None,
         aliases=(),
         **kwargs,
     ):
         self.defquery = defquery
-        self.aliases = aliases = qbstores.Frozenmap(aliases)
+        self.aliases = aliases = Frozenmap(aliases)
         columns = defquery.columns
         super().__init__(name, columns=columns, schema_name=schema_name, **kwargs)
 
@@ -711,13 +707,13 @@ class View(Named):
 
     def create(
         self, if_not_exists: bool = False, temporary: bool = False
-    ) -> querybuilder.queries.ddl.CreateView:
-        return querybuilder.queries.ddl.CreateView(
+    ) -> qbqueries.ddl.CreateView:
+        return qbqueries.ddl.CreateView(
             self, if_not_exists=if_not_exists, temporary=temporary
         )
 
     def drop(self, if_exists: bool = False, cascade: Optional[bool] = None):
-        return querybuilder.queries.ddl.Drop(self, if_exists=if_exists, cascade=cascade)
+        return qbqueries.ddl.Drop(self, if_exists=if_exists, cascade=cascade)
 
     @method_accepting_lambdas
     def alter(self, *args, **kwargs):
diff --git a/querybuilder/schemas/schemas.py b/querybuilder/atoms/schemas.py
similarity index 81%
rename from querybuilder/schemas/schemas.py
rename to querybuilder/atoms/schemas.py
index 23951b28654f5f83f831b3c672090cbdb0516abe..4bc80d82c3a3d14784517676bad44e9735b20fba 100644
--- a/querybuilder/schemas/schemas.py
+++ b/querybuilder/atoms/schemas.py
@@ -1,11 +1,11 @@
 from __future__ import annotations
 from typing import Iterable, Union, ClassVar, Optional, Tuple, Self, Mapping
-import querybuilder.classes.atoms as qbatoms
-import querybuilder.classes.stores as qbstores
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.ddl as qbddl
-import querybuilder.queries.algebra.clauses as qbclauses
-import querybuilder
+import querybuilder.utils.stores as qbstores
+import querybuilder.atoms.atoms as qbatoms
+import querybuilder.atoms.clauses as qbclauses
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder as qb
 
 
 class IndexedColumn(qbatoms.Atom):
@@ -13,7 +13,7 @@ class IndexedColumn(qbatoms.Atom):
 
     def __init__(
         self,
-        column: querybuilder.queries.algebra.columns.Column,
+        column: qbcolumns.Column,
         asc: Optional[bool] = None,
         collation: Optional[str] = None,
     ):
@@ -33,7 +33,7 @@ class IndexedColumn(qbatoms.Atom):
     def _get_subtokenize_kwargs(self, tokenizer):
         kwargs = super()._get_subtokenize_kwargs(tokenizer)
 
-        column = querybuilder.queries.algebra.columns.unqualify(self.column)
+        column = qb.atoms.columns.unqualify(self.column)
         kwargs["column"] = qbclauses.AliasedColumn(column).subtokenize(tokenizer)
 
         if self.collation:
@@ -58,12 +58,10 @@ class Index(qbatoms.Atom):
     def __init__(
         self,
         name: str,
-        schema_relation: querybuilder.queries.algebra.relations.Named,
-        columns: Tuple[
-            querybuilder.queries.algebra.columns.Column | IndexedColumn, ...
-        ],
+        schema_relation: qbrelations.Named,
+        columns: Tuple[qb.atoms.columns.Column | IndexedColumn, ...],
         unique: bool = False,
-        where: Optional[querybuilder.queries.algebra.columns.Expression] = None,
+        where: Optional[qb.atoms.columns.Expression] = None,
         schema_name: Optional[str] = None,
     ):
         self.schema_relation = schema_relation
@@ -73,10 +71,8 @@ class Index(qbatoms.Atom):
         self.where = where
         self.schema_name = schema_name
 
-    def create(
-        self, if_not_exists: bool = False
-    ) -> querybuilder.queries.ddl.CreateIndex:
-        return querybuilder.queries.ddl.CreateIndex(self, if_not_exists)
+    def create(self, if_not_exists: bool = False) -> qb.queries.ddl.CreateIndex:
+        return qb.queries.ddl.CreateIndex(self, if_not_exists)
 
     def _get_subtokenize_kwargs(self, tokenizer):
         return dict(
@@ -158,13 +154,13 @@ class Schema(qbatoms.Atom):
         )
         super().__setstate__(state)
 
-    def create(self, if_not_exists: bool = False) -> qbddl.CreateSchema:
-        return qbddl.CreateSchema(self, if_not_exists=if_not_exists)
+    def create(self, if_not_exists: bool = False) -> qb.queries.ddl.CreateSchema:
+        return qb.queries.ddl.CreateSchema(self, if_not_exists=if_not_exists)
 
     def drop(self, if_exists: bool = False, cascade: Optional[bool] = None):
-        return qbddl.Drop(self, if_exists=if_exists, cascade=cascade)
+        return qb.queries.ddl.Drop(self, if_exists=if_exists, cascade=cascade)
 
-    def creation_script(self) -> list[qbddl.DDLQuery]:
+    def creation_script(self) -> list[qb.queries.ddl.DDLQuery]:
         return [
             self.create(),
             *(o.create() for o in self.objects if hasattr(o, "create")),
diff --git a/querybuilder/classes/__init__.py b/querybuilder/classes/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/querybuilder/drivers/postgres/__init__.py b/querybuilder/drivers/postgres/__init__.py
index ac1a69e85f268e67e69db6edbc45335017f8010a..c85e70a9e533bed6c1e4f04717cb21613398d7d3 100644
--- a/querybuilder/drivers/postgres/__init__.py
+++ b/querybuilder/drivers/postgres/__init__.py
@@ -1,2 +1 @@
-import querybuilder.drivers.postgres.connector
-import querybuilder.drivers.postgres.tokenizer
+from querybuilder.drivers.postgres.connector import Connector
diff --git a/querybuilder/drivers/postgres/tokenizer.py b/querybuilder/drivers/postgres/tokenizer.py
index 72e5648b21cbb0e70951c0b9b3e65dbf79b4f447..0f1cd641ca02669517f76c707bdc04930e283b4b 100644
--- a/querybuilder/drivers/postgres/tokenizer.py
+++ b/querybuilder/drivers/postgres/tokenizer.py
@@ -8,10 +8,9 @@ from querybuilder.utils.decorators import TypeDispatch
 from querybuilder.formatting.token import Token
 from querybuilder.formatting.tokentree import TkInd, TkTree, TkSeq, TkStr
 from querybuilder.drivers.sql.tokenizer import Tokenizer as sqlTokenizer, name_and_defer
-from querybuilder.queries.algebra.clauses import Limit
-import querybuilder as qb
 import querybuilder.formatting.paramstyle as qbparamstyle
 import querybuilder.queries.ddl as ddl
+import querybuilder as qb
 
 
 class Tokenizer(sqlTokenizer):
diff --git a/querybuilder/drivers/sql/connector.py b/querybuilder/drivers/sql/connector.py
index 022a2eed6b981341bfea42aaf2951d04596368c7..0e0e3697d38a194e5a673f826a39b67192b87c4f 100644
--- a/querybuilder/drivers/sql/connector.py
+++ b/querybuilder/drivers/sql/connector.py
@@ -5,7 +5,7 @@ from querybuilder.utils.transaction_manager import TransactionManager
 from querybuilder.utils.typing import DBAPI_ConnectProto, DBAPI_CursorProto
 from querybuilder.drivers.sql.tokenizer import Tokenizer
 from querybuilder.formatting.formatter import Formatter
-from querybuilder.classes.atoms import Atom
+from querybuilder.atoms.atoms import Atom
 import querybuilder as qb
 
 
diff --git a/querybuilder/drivers/sql/tokenizer.py b/querybuilder/drivers/sql/tokenizer.py
index 08a08443abb2ad8b2c7019151d65944c404bb0e1..e2a7c94ee44f5c5eb784862d355b9381d2e950aa 100644
--- a/querybuilder/drivers/sql/tokenizer.py
+++ b/querybuilder/drivers/sql/tokenizer.py
@@ -24,18 +24,19 @@ import querybuilder.utils.constants as qbconstants
 from querybuilder.formatting import token as qbtoken
 import querybuilder.formatting.paramstyle as qbparamstyle
 
-import querybuilder.classes.atoms as atoms
-import querybuilder.classes.stores as stores
-import querybuilder.queries.algebra.relations as relations
-import querybuilder.queries.algebra.columns as qbcolumns
-import querybuilder.queries.algebra.clauses as clauses
+import querybuilder.utils.stores as stores
+import querybuilder.atoms.atoms as atoms
+import querybuilder.atoms.relations as relations
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.clauses as clauses
+import querybuilder.atoms.schemas as qbschemas
+import querybuilder.atoms.constraints as qbconstraints
 import querybuilder.queries.dql as dql
 import querybuilder.queries.dml as dml
 import querybuilder.queries.ddl as ddl
 import querybuilder.queries.tcl as tcl
 import querybuilder.queries.queries as queries
 import querybuilder.queries.comment as comment
-import querybuilder.schemas as qbschemas
 import querybuilder.visitors as qbvisitors
 
 P = ParamSpec("P")
@@ -694,9 +695,9 @@ class Tokenizer:
 
     @__call__.register(clauses.DBObjectNameWrapper)
     def _(self, obj: clauses.DBObjectNameWrapper, /, *, dbobj: atoms.Atom) -> TkTree:
-        if isinstance(dbobj, qbschemas.schemas.Schema):
+        if isinstance(dbobj, qbschemas.Schema):
             string = "SCHEMA"
-        elif isinstance(dbobj, qbschemas.schemas.Index):
+        elif isinstance(dbobj, qbschemas.Index):
             string = "INDEX"
         elif isinstance(dbobj, relations.View):
             string = "VIEW"
@@ -784,41 +785,41 @@ class Tokenizer:
     # CONSTRAINTS #
     ###############
 
-    @__call__.register(qbschemas.constraints.Constraint)
+    @__call__.register(qbconstraints.Constraint)
     @name_and_defer
-    def _(self, obj: qbschemas.constraints.Constraint, /, **kwargs) -> TkTree:
+    def _(self, obj: qbconstraints.Constraint, /, **kwargs) -> TkTree:
         # TODO: temporary rule during dev
         return self.tokenize_keyword(str(type(obj)))
 
-    @__call__.register(qbschemas.constraints.ColumnPrimaryKey)
+    @__call__.register(qbconstraints.ColumnPrimaryKey)
     @name_and_defer
-    def _(self, obj: qbschemas.constraints.ColumnPrimaryKey, /) -> TkTree:
+    def _(self, obj: qbconstraints.ColumnPrimaryKey, /) -> TkTree:
         return self.tokenize_keyword("PRIMARY KEY")
 
-    @__call__.register(qbschemas.constraints.ColumnNotNull)
+    @__call__.register(qbconstraints.ColumnNotNull)
     @name_and_defer
-    def _(self, obj: qbschemas.constraints.ColumnNotNull, /) -> TkTree:
+    def _(self, obj: qbconstraints.ColumnNotNull, /) -> TkTree:
         return self.tokenize_keyword("NOT NULL")
 
-    @__call__.register(qbschemas.constraints.ColumnUnique)
+    @__call__.register(qbconstraints.ColumnUnique)
     @name_and_defer
-    def _(self, obj: qbschemas.constraints.ColumnUnique, /) -> TkTree:
+    def _(self, obj: qbconstraints.ColumnUnique, /) -> TkTree:
         return self.tokenize_keyword("UNIQUE")
 
-    @__call__.register(qbschemas.constraints.ColumnGeneratedAsIdentity)
+    @__call__.register(qbconstraints.ColumnGeneratedAsIdentity)
     @name_and_defer
     def _(
-        self, obj: qbschemas.constraints.ColumnGeneratedAsIdentity, /, *, always: bool
+        self, obj: qbconstraints.ColumnGeneratedAsIdentity, /, *, always: bool
     ) -> TkTree:
         return self.tokenize_keyword(
             f"GENERATED {always and 'ALWAYS' or 'BY DEFAULT'} AS IDENTITY",
         )
 
-    @__call__.register(qbschemas.constraints.ColumnGeneratedAlwaysAs)
+    @__call__.register(qbconstraints.ColumnGeneratedAlwaysAs)
     @name_and_defer
     def _(
         self,
-        obj: qbschemas.constraints.ColumnGeneratedAlwaysAs,
+        obj: qbconstraints.ColumnGeneratedAlwaysAs,
         /,
         *,
         expression: TkTree,
@@ -829,11 +830,11 @@ class Tokenizer:
         newtree.append(self.tokenize_keyword("STORED"))
         return tuple(newtree)
 
-    @__call__.register(qbschemas.constraints.ColumnReferences)
+    @__call__.register(qbconstraints.ColumnReferences)
     @name_and_defer
     def _(
         self,
-        obj: qbschemas.constraints.ColumnReferences,
+        obj: qbconstraints.ColumnReferences,
         /,
         *,
         schema_name: Optional[str],
@@ -856,21 +857,19 @@ class Tokenizer:
 
         return (tuple(newtree), TkInd(), ondelete, onupdate)
 
-    @__call__.register(qbschemas.constraints.ColumnDefault)
+    @__call__.register(qbconstraints.ColumnDefault)
     @name_and_defer
-    def _(
-        self, obj: qbschemas.constraints.ColumnDefault, /, *, expression: TkTree
-    ) -> TkTree:
+    def _(self, obj: qbconstraints.ColumnDefault, /, *, expression: TkTree) -> TkTree:
         # TODO: fix double initial space when constraint isn't named
         kw = self.tokenize_keyword("DEFAULT")
         return (kw, expression)
 
-    @__call__.register(qbschemas.constraints.ColumnCheck)
-    @__call__.register(qbschemas.constraints.TableCheck)
+    @__call__.register(qbconstraints.ColumnCheck)
+    @__call__.register(qbconstraints.TableCheck)
     @name_and_defer
     def _(
         self,
-        obj: Union[qbschemas.constraints.ColumnCheck, qbschemas.constraints.TableCheck],
+        obj: Union[qbconstraints.ColumnCheck, qbconstraints.TableCheck],
         /,
         *,
         expression: TkTree,
@@ -882,27 +881,23 @@ class Tokenizer:
         newtree.append(TkStr(qbtoken.Punctuation, ")").to_seq())
         return tuple(newtree)
 
-    @__call__.register(qbschemas.constraints.TableUnique)
+    @__call__.register(qbconstraints.TableUnique)
     @name_and_defer
-    def _(
-        self, obj: qbschemas.constraints.TableUnique, /, *, expression: TkTree
-    ) -> TkTree:
+    def _(self, obj: qbconstraints.TableUnique, /, *, expression: TkTree) -> TkTree:
         kw = self.tokenize_keyword("UNIQUE")
         return (kw, expression)
 
-    @__call__.register(qbschemas.constraints.TablePrimaryKey)
+    @__call__.register(qbconstraints.TablePrimaryKey)
     @name_and_defer
-    def _(
-        self, obj: qbschemas.constraints.TablePrimaryKey, /, *, expression: TkTree
-    ) -> TkTree:
+    def _(self, obj: qbconstraints.TablePrimaryKey, /, *, expression: TkTree) -> TkTree:
         kw = self.tokenize_keyword("PRIMARY KEY")
         return (kw, expression)
 
-    @__call__.register(qbschemas.constraints.TableForeignKey)
+    @__call__.register(qbconstraints.TableForeignKey)
     @name_and_defer
     def _(
         self,
-        obj: qbschemas.constraints.TableForeignKey,
+        obj: qbconstraints.TableForeignKey,
         /,
         *,
         expression: TkTree,
@@ -933,7 +928,7 @@ class Tokenizer:
         /,
         *,
         change: str,
-        policy: qbschemas.constraints.OnChangePolicy,
+        policy: qbconstraints.OnChangePolicy,
     ) -> TkTree:
         return self.tokenize_keyword(f"ON {change} {policy.value}")
 
@@ -941,10 +936,10 @@ class Tokenizer:
     # SCHEMAS #
     ###########
 
-    @__call__.register(qbschemas.schemas.IndexedColumn)
+    @__call__.register(qbschemas.IndexedColumn)
     def _(
         self,
-        obj: qbschemas.schemas.IndexedColumn,
+        obj: qbschemas.IndexedColumn,
         /,
         *,
         column: TkTree,
@@ -955,12 +950,12 @@ class Tokenizer:
 
         return (column, collation, asc)
 
-    @__call__.register(qbschemas.schemas.Schema)
-    def _(self, obj: qbschemas.schemas.Schema, /, *, name: TkTree) -> TkTree:
+    @__call__.register(qbschemas.Schema)
+    def _(self, obj: qbschemas.Schema, /, *, name: TkTree) -> TkTree:
         return name
 
-    @__call__.register(qbschemas.schemas.Index)
-    def _(self, obj: qbschemas.schemas.Index, /, *, name: TkTree) -> TkTree:
+    @__call__.register(qbschemas.Index)
+    def _(self, obj: qbschemas.Index, /, *, name: TkTree) -> TkTree:
         return (name,)
 
     #############
diff --git a/querybuilder/drivers/sqlite/tokenizer.py b/querybuilder/drivers/sqlite/tokenizer.py
index b07f221708aff9102048b5d6424782c552833565..3ba229b78f4f686504d63a40f2bb5449bf5c0873 100644
--- a/querybuilder/drivers/sqlite/tokenizer.py
+++ b/querybuilder/drivers/sqlite/tokenizer.py
@@ -8,11 +8,10 @@ from querybuilder.utils.decorators import TypeDispatch
 from querybuilder.formatting.token import Token
 from querybuilder.formatting.tokentree import TkInd, TkTree, TkSeq, TkStr
 from querybuilder.drivers.sql.tokenizer import Tokenizer as sqlTokenizer, name_and_defer
-from querybuilder.queries.algebra.clauses import Limit, OrderColumn
-from querybuilder.classes.atoms import Atom
-from querybuilder.queries.dql import Select
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
+from querybuilder.atoms.clauses import Limit, OrderColumn
+from querybuilder.atoms.atoms import Atom
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
 import querybuilder as qb
 
 
@@ -56,7 +55,7 @@ class Tokenizer(sqlTokenizer):
     @__call__.register(Limit)
     def _(
         self,
-        obj: qb.queries.algebra.clauses.Limit,
+        obj: Limit,
         /,
         *,
         limit: int,
@@ -72,7 +71,7 @@ class Tokenizer(sqlTokenizer):
     @__call__.register(OrderColumn)
     def _(
         self,
-        obj: qb.queries.algebra.clauses.OrderColumn,
+        obj: OrderColumn,
         /,
         *,
         column: TkTree,
@@ -127,10 +126,10 @@ class Tokenizer(sqlTokenizer):
         return tuple(tree)
 
     # DDL
-    @__call__.register(qb.schemas.constraints.ColumnGeneratedAsIdentity)
+    @__call__.register(qb.atoms.constraints.ColumnGeneratedAsIdentity)
     @name_and_defer
     def _(
-        self, obj: qb.schemas.constraints.ColumnGeneratedAsIdentity, /, *, always: bool
+        self, obj: qb.atoms.constraints.ColumnGeneratedAsIdentity, /, *, always: bool
     ) -> TkTree:
         if always:
             warnings.warn(
@@ -139,11 +138,11 @@ class Tokenizer(sqlTokenizer):
         # TODO: works only in case of integer column
         return self.tokenize_keyword("AUTOINCREMENT")
 
-    @__call__.register(qb.schemas.constraints.ColumnReferences)
+    @__call__.register(qb.atoms.constraints.ColumnReferences)
     @name_and_defer
     def _(
         self,
-        obj: qb.schemas.constraints.ColumnReferences,
+        obj: qb.atoms.constraints.ColumnReferences,
         /,
         *,
         schema_name: Optional[str],
@@ -217,7 +216,7 @@ class Tokenizer(sqlTokenizer):
 
         left_aliases = {i: name for i, name in enumerate(obj._get_column_names())}
         left_columns = tuple(qbcolumns.Null() for i in obj.subrelation.columns)
-        naming_relation = Select(
+        naming_relation = qb.queries.dql.Select(
             left_columns, where=qbcolumns.False_(), aliases=left_aliases
         )
 
diff --git a/querybuilder/formatting/formatter.py b/querybuilder/formatting/formatter.py
index 7c2759e8407bfdab856c8c13f4e3244b2492a2a4..0b18f7374c147885572518bc2e4e54928abb505b 100644
--- a/querybuilder/formatting/formatter.py
+++ b/querybuilder/formatting/formatter.py
@@ -13,12 +13,12 @@ from typing import (
 )
 from io import StringIO
 import pygments.formatters as pygments_formatters
-from querybuilder.classes.stores import Frozenmap
+from querybuilder.utils.stores import Frozenmap
 import querybuilder.utils.typing as qbtyping
+import querybuilder.utils.constants as qbconst
 from querybuilder.formatting.tokentree import TkStr, TkSeq, TkTree
 import querybuilder.formatting.preformatter as qbpreformatter
 import querybuilder.formatting.style as qbstyle
-import querybuilder.utils.constants as qbconst
 
 
 class Formatter:
diff --git a/querybuilder/helpers/__init__.py b/querybuilder/helpers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..cc85c416205e153d7cb0518d5d72a8041dc04919
--- /dev/null
+++ b/querybuilder/helpers/__init__.py
@@ -0,0 +1,4 @@
+from .schema import table, schema, ColumnSpec, Collector
+from .columns import make_column, Placeholder
+
+colspec = ColumnSpec
diff --git a/querybuilder/helpers/columns.py b/querybuilder/helpers/columns.py
new file mode 100644
index 0000000000000000000000000000000000000000..7abbf12dca4d7d89794d5e610d7fdc5f2e50abbe
--- /dev/null
+++ b/querybuilder/helpers/columns.py
@@ -0,0 +1 @@
+from querybuilder.atoms.columns import Placeholder, make_column, Star
diff --git a/querybuilder/schemas/helper.py b/querybuilder/helpers/schema.py
similarity index 99%
rename from querybuilder/schemas/helper.py
rename to querybuilder/helpers/schema.py
index 8791046ee8270d56a489928179e14d52bfb95837..7d7311aadb855de5db1fe85854ebfdd324474cb9 100644
--- a/querybuilder/schemas/helper.py
+++ b/querybuilder/helpers/schema.py
@@ -20,7 +20,7 @@ from typing import (
 from typing_extensions import ParamSpec
 
 from querybuilder.utils.constants import MISSING, _MISSING_TYPE
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.columns import (
     Column,
     Constant as ConstantColumn,
     Named as NamedColumn,
@@ -29,15 +29,15 @@ from querybuilder.queries.algebra.columns import (
     make_column,
     name_column,
 )
-from querybuilder.queries.algebra.relations import (
+from querybuilder.atoms.relations import (
     Named as NamedRelation,
     Prenamed as PrenamedRelation,
     Table,
     View,
 )
 from querybuilder.queries.dql import DQLQuery
-from querybuilder.schemas.constraints import *
-from querybuilder.schemas.schemas import Schema, Index
+from querybuilder.atoms.constraints import *
+from querybuilder.atoms.schemas import Schema, Index
 
 if TYPE_CHECKING:
     T = TypeVar("T")
diff --git a/querybuilder/post_init.py b/querybuilder/post_init.py
index 979e5eae5678d4edfea465090a07c73d5e9ce764..6780d92eea3aa982837fc4d7628ad5df1f833514 100644
--- a/querybuilder/post_init.py
+++ b/querybuilder/post_init.py
@@ -5,25 +5,25 @@ from querybuilder.visitors.stores import WithQueryStore, PlaceholderStore
 
 
 @cast(singledispatchmethod, WithQueryStore.visit).register(
-    querybuilder.classes.atoms.Atom
+    querybuilder.atoms.atoms.Atom
 )
 @cast(singledispatchmethod, PlaceholderStore.visit).register(
-    querybuilder.classes.atoms.Atom
+    querybuilder.atoms.atoms.Atom
 )
 def _(
-    self, obj: querybuilder.classes.atoms.Atom
+    self, obj: querybuilder.atoms.atoms.Atom
 ) -> querybuilder.formatting.tokentree.TkTree:
     return self
 
 
 @cast(singledispatchmethod, WithQueryStore.visit).register(
-    querybuilder.queries.algebra.relations.With
+    querybuilder.atoms.relations.With
 )
 @cast(singledispatchmethod, PlaceholderStore.visit).register(
-    querybuilder.queries.algebra.columns.Placeholder
+    querybuilder.atoms.columns.Placeholder
 )
 def _(
-    self, obj: querybuilder.queries.algebra.columns.Placeholder
+    self, obj: querybuilder.atoms.columns.Placeholder
 ) -> querybuilder.formatting.tokentree.TkTree:
     return self | (obj,)
 
diff --git a/querybuilder/queries/algebra/__init__.py b/querybuilder/queries/algebra/__init__.py
deleted file mode 100644
index a9c3fa6b837756e9a87c1c299738dfe64f36c3e4..0000000000000000000000000000000000000000
--- a/querybuilder/queries/algebra/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-import querybuilder.queries.algebra.columns
-import querybuilder.queries.algebra.relations
-import querybuilder.queries.algebra.clauses
diff --git a/querybuilder/queries/ddl.py b/querybuilder/queries/ddl.py
index 2114538ec6e5e12c4607c7ba41edd049111c642c..164a3484693427463ed3cda443a5107c1ec0f453 100644
--- a/querybuilder/queries/ddl.py
+++ b/querybuilder/queries/ddl.py
@@ -1,9 +1,9 @@
 from __future__ import annotations
 from typing import Iterable, Optional, Self, Mapping
 from querybuilder.queries.queries import Query
-import querybuilder
-import querybuilder.queries.algebra.clauses as qbclauses
-import querybuilder.schemas.schemas as qbschemas
+import querybuilder.atoms.clauses as qbclauses
+import querybuilder.atoms.schemas as qbschemas
+import querybuilder as qb
 
 
 class DDLQuery(Query):
@@ -41,9 +41,9 @@ class CreateTable(DDLQuery):
 
     def __init__(
         self,
-        table: querybuilder.queries.algebra.relations.Table,
+        table: qb.atoms.relations.Table,
         if_not_exists: bool = False,
-        as_query: Optional[querybuilder.queries.dql.DQLQuery] = None,
+        as_query: Optional[qb.queries.dql.DQLQuery] = None,
         temporary: bool = False,
         **kwargs,
     ):
@@ -105,7 +105,7 @@ class CreateView(DDLQuery):
 
     def __init__(
         self,
-        view: querybuilder.queries.algebra.relations.View,
+        view: qb.atoms.relations.View,
         if_not_exists: bool = False,
         temporary: bool = False,
         **kwargs,
@@ -187,7 +187,7 @@ class Drop(DDLQuery):
 
     def __init__(
         self,
-        target: querybuilder.classes.atoms.Atom,
+        target: qb.atoms.atoms.Atom,
         if_exists: bool = False,
         cascade: Optional[bool] = None,
         **kwargs,
diff --git a/querybuilder/queries/dml.py b/querybuilder/queries/dml.py
index ce076d09aadad9e251441b43d09a6c85d5b4b0cc..b20c42c4f990ad5a24596d6d8140c54dafbd2084 100644
--- a/querybuilder/queries/dml.py
+++ b/querybuilder/queries/dml.py
@@ -2,9 +2,9 @@ from __future__ import annotations
 from querybuilder.queries.queries import Query
 from typing import Optional, Mapping, Self
 import querybuilder
-from querybuilder.queries.algebra.columns import Column, Named as NamedColumn
-from querybuilder.queries.algebra.columns import unqualify
-import querybuilder.queries.algebra.relations as qbrelations
+from querybuilder.atoms.columns import Column, Named as NamedColumn
+from querybuilder.atoms.columns import unqualify
+import querybuilder.atoms.relations as qbrelations
 
 
 class DMLQuery(Query):
@@ -55,7 +55,7 @@ class Insert(DMLQuery):
     schema_relation:
         the schema relation (TABLE or VIEW) in which to insert values.
 
-    in_columns: iterable of querybuilder.queries.algebra.columns.Column
+    in_columns: iterable of querybuilder.atoms.columns.Column
         a subset of the schema_relation's columns, in which to insert values.
 
     query: Optional[qbqueries.dql.DQLQuery]
@@ -67,8 +67,8 @@ class Insert(DMLQuery):
 
     Example
     -------
-    >>> from querybuilder.queries.algebra.relations import Named as NamedRel
-    >>> from querybuilder.queries.algebra.columns import Constant, Named as NamedCol
+    >>> from querybuilder.atoms.relations import Named as NamedRel
+    >>> from querybuilder.atoms.columns import Constant, Named as NamedCol
     >>> from querybuilder.queries.dql import Values
 
     An Insert query can be instantiated as follow:
@@ -88,8 +88,8 @@ class Insert(DMLQuery):
 
     def __init__(
         self,
-        schema_relation: querybuilder.queries.algebra.relations.Named,
-        in_columns: tuple[querybuilder.queries.algebra.columns.Named, ...] = (),
+        schema_relation: querybuilder.atoms.relations.Named,
+        in_columns: tuple[querybuilder.atoms.columns.Named, ...] = (),
         query: Optional[querybuilder.queries.dql.DQLQuery] = None,
         **kwargs,
     ):
@@ -113,7 +113,7 @@ class Insert(DMLQuery):
         return accumulator
 
     def _get_subtokenize_kwargs(self, tokenizer):
-        CW = querybuilder.queries.algebra.clauses.AliasedColumn
+        CW = querybuilder.atoms.clauses.AliasedColumn
         in_columns = tuple(
             map(lambda c: CW(unqualify(c)).subtokenize(tokenizer), self.in_columns)
         )
@@ -121,10 +121,8 @@ class Insert(DMLQuery):
         if self.query:
             query = self.query.subtokenize(tokenizer)
         else:
-            query = (
-                querybuilder.queries.algebra.clauses.DefaultValuesClause().subtokenize(
-                    tokenizer
-                )
+            query = querybuilder.atoms.clauses.DefaultValuesClause().subtokenize(
+                tokenizer
             )
 
         return dict(
@@ -160,8 +158,8 @@ class Delete(DMLQuery):
     Examples
     -------
 
-    >>> from querybuilder.queries.algebra.relations import Named as NamedRel
-    >>> from querybuilder.queries.algebra.columns import Constant, Named as NamedCol
+    >>> from querybuilder.atoms.relations import Named as NamedRel
+    >>> from querybuilder.atoms.columns import Constant, Named as NamedCol
 
     >>> str(Delete(NamedRel("foo"), NamedCol(int, "x").eq(3)))
     'DELETE FROM foo WHERE x = 3'
@@ -174,8 +172,8 @@ class Delete(DMLQuery):
 
     def __init__(
         self,
-        schema_relation: querybuilder.queries.algebra.relations.Relation,
-        where: Optional[querybuilder.queries.algebra.columns.Column] = None,
+        schema_relation: querybuilder.atoms.relations.Relation,
+        where: Optional[querybuilder.atoms.columns.Column] = None,
         **kwargs,
     ):
         self.where = where
@@ -208,7 +206,7 @@ class Delete(DMLQuery):
     def _get_subtokenize_kwargs(self, tokenizer):
         kwargs = super()._get_subtokenize_kwargs(tokenizer)
         kwargs["schema_relation"] = self.schema_relation.subtokenize(tokenizer)
-        WC = querybuilder.queries.algebra.clauses.WhereColumn
+        WC = querybuilder.atoms.clauses.WhereColumn
         if self.where:
             kwargs["where"] = WC(self.where).subtokenize(tokenizer)
         return kwargs
@@ -235,8 +233,8 @@ class Update(DMLQuery):
     Examples
     -------
 
-    >>> from querybuilder.queries.algebra.relations import Named as NamedRel
-    >>> from querybuilder.queries.algebra.columns import Constant, Named as NamedCol
+    >>> from querybuilder.atoms.relations import Named as NamedRel
+    >>> from querybuilder.atoms.columns import Constant, Named as NamedCol
 
     >>> set_cols = {NamedCol(int, "x"): Constant(int, 3), NamedCol(str, "y"): Constant(str, "bar")}
     >>> str(Update(NamedRel("foo"), set_cols))
@@ -247,7 +245,7 @@ class Update(DMLQuery):
 
     def __init__(
         self,
-        schema_relation: querybuilder.queries.algebra.relations.Relation,
+        schema_relation: querybuilder.atoms.relations.Relation,
         set_columns: Mapping[NamedColumn, Column],
         where: Optional[Column] = None,
         **kwargs,
@@ -306,9 +304,9 @@ class Update(DMLQuery):
         kwargs = super()._get_subtokenize_kwargs(tokenizer)
         kwargs["schema_relation"] = self.schema_relation.subtokenize(tokenizer)
         if self.where:
-            WC = querybuilder.queries.algebra.clauses.WhereColumn
+            WC = querybuilder.atoms.clauses.WhereColumn
             kwargs["where"] = WC(self.where).subtokenize(tokenizer)
-        SC = querybuilder.queries.algebra.clauses.SetColumnsClause
+        SC = querybuilder.atoms.clauses.SetColumnsClause
         kwargs["set_columns"] = SC(self.set_columns).subtokenize(tokenizer)
 
         return kwargs
diff --git a/querybuilder/queries/dql.py b/querybuilder/queries/dql.py
index 30fbab56df233b39b5e48fb1c67c8261af524116..c399bcf2d631dca9a33e6488a343cfcc8818dcd8 100644
--- a/querybuilder/queries/dql.py
+++ b/querybuilder/queries/dql.py
@@ -3,14 +3,14 @@ import functools
 import operator
 import collections
 from typing import Union, Iterable, Tuple, Optional, Mapping, Sequence, Self
-import querybuilder.classes.stores as qbstores
+import querybuilder.utils.stores as qbstores
 import querybuilder.utils.constants as qbconstants
 from querybuilder.utils.decorators import method_accepting_lambdas
 from querybuilder.queries.queries import Query
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
-import querybuilder.queries.algebra.clauses as clauses
-import querybuilder
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.clauses as clauses
+import querybuilder as qb
 
 
 class DQLQuery(Query, qbrelations.Relation):
@@ -51,7 +51,7 @@ class DQLQuery(Query, qbrelations.Relation):
 
     def create_view(
         self, name: str, if_not_exists: bool = False, temporary: bool = False
-    ) -> querybuilder.queries.ddl.CreateView:
+    ) -> qb.queries.ddl.CreateView:
         return qbrelations.View(name, self).create(
             if_not_exists=if_not_exists, temporary=temporary
         )
@@ -267,7 +267,7 @@ class Select(DQLQuery):
 
         Examples
         --------
-        >>> from querybuilder.schemas.helper import table, make_column
+        >>> from querybuilder.helpers import table, make_column
         >>> t = table(type("t", (), dict(__annotations__=dict(x=int, y=str))))
         >>> const2 = make_column(2)
         >>> sq = t.select([t.columns[0], const2, t.columns[1]], aliases={2: "bar"})
@@ -285,9 +285,9 @@ class Select(DQLQuery):
         selected column of index 2 (ie, `sq.selected_columns[2]`), and `"x"` stands for the
         selected column that is unambiguously named "x" (ie, `sq.selected_columns._["x"]`).
 
-        It is also possible to use `querybuilder.queries.algebra.columns.Star()`, or the
+        It is also possible to use `querybuilder.atoms.columns.Star()`, or the
         `"*"` shorthand, in the sequence of selected columns.
-        >>> from querybuilder.queries.algebra.columns import Star
+        >>> from querybuilder.atoms.columns import Star
         >>> str(sq.set_selected_columns(["*", 2, Star(), "x"]))
         'SELECT *, t.y, *, t.x FROM t'
 
@@ -328,7 +328,7 @@ class Select(DQLQuery):
 
         Examples
         --------
-        >>> from querybuilder.schemas.helper import table, make_column
+        >>> from querybuilder.helpers import table, make_column
         >>> t = table(type("t", (), dict(__annotations__=dict(x=int, y=str))))
         >>> const2 = make_column(2)
         >>> sq = t.select([t.columns[0], const2, t.columns[1], t.columns[1]], aliases={2: "bar"})
@@ -594,7 +594,7 @@ class WithClosure(DQLQuery):
     Examples
     --------
 
-    >>> from querybuilder.queries.algebra.columns import Constant
+    >>> from querybuilder.atoms.columns import Constant
     >>> w1 = Select((Constant(int, 1),)).as_with(name="T", materialized=True)
     >>> w2 = Select((Constant(str, "a"),)).as_with(name="T2", materialized=False)
     >>> j = w1.full_join(w2).select()
diff --git a/querybuilder/queries/queries.py b/querybuilder/queries/queries.py
index 5da2aa459f19d9550f2971bc67c307f0bdd05eb3..67834e9d155381221db29bd295f453e0f2ae4b60 100644
--- a/querybuilder/queries/queries.py
+++ b/querybuilder/queries/queries.py
@@ -1,7 +1,7 @@
 from __future__ import annotations
 from typing import ClassVar
-from querybuilder.classes.atoms import Atom
-import querybuilder
+from querybuilder.atoms.atoms import Atom
+import querybuilder as qb
 
 
 class Query(Atom):
@@ -12,11 +12,11 @@ class Query(Atom):
         return self._is_readonly
 
     def rawformat(self, tokenizer):
-        formatter = querybuilder.settings["raw_formatter"]
+        formatter = qb.settings["raw_formatter"]
         tkstream = self.tokenize(tokenizer)
         return formatter.get_formatted(tkstream)
 
     def with_closure(self, with_relations=None):
         if with_relations is None:
             with_relations = self.get_free_with()
-        return querybuilder.queries.dql.WithClosure(self, with_relations)
+        return qb.queries.dql.WithClosure(self, with_relations)
diff --git a/querybuilder/schemas/__init__.py b/querybuilder/schemas/__init__.py
deleted file mode 100644
index 1aee25450342385f86933a5bc4f96ab2484d1b14..0000000000000000000000000000000000000000
--- a/querybuilder/schemas/__init__.py
+++ /dev/null
@@ -1,2 +0,0 @@
-import querybuilder.schemas.schemas as schemas
-import querybuilder.schemas.constraints as constraints
diff --git a/querybuilder/tests/classes/test_atoms.py b/querybuilder/tests/atoms/test_atoms.py
similarity index 98%
rename from querybuilder/tests/classes/test_atoms.py
rename to querybuilder/tests/atoms/test_atoms.py
index 39251c2657c7ae83fb04f79faa618d4206342581..01373d972c1031d40e90fbb2fb468cdae23e5857 100644
--- a/querybuilder/tests/classes/test_atoms.py
+++ b/querybuilder/tests/atoms/test_atoms.py
@@ -1,6 +1,6 @@
 import pytest
 from mock import Mock
-from querybuilder.classes.atoms import Atom
+from querybuilder.atoms.atoms import Atom
 
 
 class ScopableAtom(Atom):
diff --git a/querybuilder/tests/queries/algebra/test_clauses.py b/querybuilder/tests/atoms/test_clauses.py
similarity index 88%
rename from querybuilder/tests/queries/algebra/test_clauses.py
rename to querybuilder/tests/atoms/test_clauses.py
index 6650758413287e8159e57519049095795e7d9e04..ad0dc885c234ce8b13f2511f7065c46dca038ba5 100644
--- a/querybuilder/tests/queries/algebra/test_clauses.py
+++ b/querybuilder/tests/atoms/test_clauses.py
@@ -1,7 +1,7 @@
 import pytest
-import querybuilder
-import querybuilder.queries.algebra.clauses as qbclauses
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.clauses as qbclauses
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder as qb
 
 
 class TestSetColumnsClause:
@@ -30,7 +30,7 @@ class TestSetColumnsClause:
 
 class TestDBObjectNameWrapper:
     def test_get_subtokenize_kwargs(self):
-        index = querybuilder.schemas.schemas.Schema("foo")
+        index = qb.atoms.schemas.Schema("foo")
         wrapper = qbclauses.DBObjectNameWrapper(index)
 
         result = wrapper._get_subtokenize_kwargs(None)
diff --git a/querybuilder/tests/queries/algebra/test_columns.py b/querybuilder/tests/atoms/test_columns.py
similarity index 97%
rename from querybuilder/tests/queries/algebra/test_columns.py
rename to querybuilder/tests/atoms/test_columns.py
index 7aca6843acaa9b8fefc295dec89ac8a78b9542a4..dbe90a6f001720d497a59aedcc1c4ea7a404b009 100644
--- a/querybuilder/tests/queries/algebra/test_columns.py
+++ b/querybuilder/tests/atoms/test_columns.py
@@ -1,9 +1,9 @@
+from uuid import UUID
 import pytest
 from mock import Mock
-import querybuilder
-import querybuilder.queries.algebra.columns as qbcolumns
-from querybuilder.queries.algebra.columns import make_column
-from uuid import UUID
+import querybuilder.atoms.columns as qbcolumns
+from querybuilder.atoms.columns import make_column
+import querybuilder as qb
 
 
 class TestColumns:
@@ -587,8 +587,8 @@ class TestExpression:
 
 class TestInRelation:
     def test_substitute_relation_and_column(self):
-        pre_relation = querybuilder.queries.algebra.relations.Named("foo")
-        post_relation = querybuilder.queries.algebra.relations.Named("bar")
+        pre_relation = qb.atoms.relations.Named("foo")
+        post_relation = qb.atoms.relations.Named("bar")
         pre_col = qbcolumns.Named(str, "clo")
         post_col = qbcolumns.Named(str, "col")
 
@@ -604,8 +604,8 @@ class TestInRelation:
 
 class TestExists:
     def test_substitute_query(self):
-        pre_query = querybuilder.queries.dql.Select((make_column(1),))
-        post_query = querybuilder.queries.dql.Select((make_column(2),))
+        pre_query = qb.queries.dql.Select((make_column(1),))
+        post_query = qb.queries.dql.Select((make_column(2),))
 
         exists = qbcolumns.Exists(pre_query)
 
diff --git a/querybuilder/tests/schemas/test_constraints.py b/querybuilder/tests/atoms/test_constraints.py
similarity index 89%
rename from querybuilder/tests/schemas/test_constraints.py
rename to querybuilder/tests/atoms/test_constraints.py
index 5b572cfa1e2b983ce41c2cbd1430364b866e98ef..f88c2af2867b84222147d05f1d54eaef180775ab 100644
--- a/querybuilder/tests/schemas/test_constraints.py
+++ b/querybuilder/tests/atoms/test_constraints.py
@@ -1,7 +1,6 @@
 import pytest
-import querybuilder
-import querybuilder.schemas.constraints as qbconstraints
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.constraints as qbconstraints
+import querybuilder.atoms.columns as qbcolumns
 
 
 class TestSubstitute:
diff --git a/querybuilder/tests/queries/algebra/test_relations.py b/querybuilder/tests/atoms/test_relations.py
similarity index 96%
rename from querybuilder/tests/queries/algebra/test_relations.py
rename to querybuilder/tests/atoms/test_relations.py
index 0a530c062e5d15430c21b679a6db29255d5c3f52..d3615132dd0c0a93a1111e4f190b4b16ecb14502 100644
--- a/querybuilder/tests/queries/algebra/test_relations.py
+++ b/querybuilder/tests/atoms/test_relations.py
@@ -2,13 +2,12 @@ import pytest
 from pytest_mock import MockerFixture
 from mock import Mock
 
-import querybuilder
-import querybuilder.queries.dml as qbdml
-from querybuilder.schemas.helper import table, ColumnSpec
-import querybuilder.queries.algebra.columns as qbcolumns
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.schemas.constraints as qbconstraints
+from querybuilder.helpers import table, ColumnSpec
 from querybuilder.tests.utils import create_subtokenizable_mock
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.constraints as qbconstraints
+import querybuilder as qb
 
 
 class TestRelation:
@@ -341,7 +340,7 @@ class TestAliased:
         tokenizer.tokenize_name = Mock(return_value=name_tok)
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column_tok
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column_tok
         )
 
         rel = qbrelations.Aliased(
@@ -364,7 +363,7 @@ class TestAliased:
         )
         subrelation.subtokenize.assert_called_once_with(tokenizer, scoped=True)
 
-        AC = querybuilder.queries.algebra.clauses.AliasedColumn
+        AC = qb.atoms.clauses.AliasedColumn
         for c in rel.columns:
             AC.assert_any_call(qbcolumns.unqualify(c))
 
@@ -467,8 +466,8 @@ class TestView:
         pre_col = qbcolumns.make_column(1)
         post_col = qbcolumns.make_column(2)
 
-        pre_query = querybuilder.queries.dql.Select((pre_col, pre_col))
-        post_query = querybuilder.queries.dql.Select((pre_col, post_col))
+        pre_query = qb.queries.dql.Select((pre_col, pre_col))
+        post_query = qb.queries.dql.Select((pre_col, post_col))
 
         pre_view = qbrelations.View("foo", pre_query)
         post_view = pre_view.substitute({pre_col: post_col, pre_query: post_query})
diff --git a/querybuilder/tests/schemas/test_schema.py b/querybuilder/tests/atoms/test_schema.py
similarity index 82%
rename from querybuilder/tests/schemas/test_schema.py
rename to querybuilder/tests/atoms/test_schema.py
index 5db7a2036a08151df78698be9c0f31f40592cca1..2a5e38e5fa35f38aec0651e9f4ddaee1927a615e 100644
--- a/querybuilder/tests/schemas/test_schema.py
+++ b/querybuilder/tests/atoms/test_schema.py
@@ -1,9 +1,9 @@
 import pytest
 from mock import Mock
-from querybuilder.schemas.schemas import Index, IndexedColumn, Schema
+from querybuilder.atoms.schemas import Index, IndexedColumn, Schema
 from querybuilder.tests.utils import create_subtokenizable_mock
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
 import querybuilder
 
 
@@ -12,7 +12,7 @@ class TestIndexedColumn:
         column = "column"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
 
         idxcol = IndexedColumn(
@@ -30,11 +30,9 @@ class TestIndexedColumn:
         asc = "ASC"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
-        )
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AscWrapper", asc
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.clauses.AscWrapper", asc)
 
         idxcol = IndexedColumn(qbcolumns.Named(int, "col"), asc=True)
 
@@ -49,11 +47,9 @@ class TestIndexedColumn:
         asc = "DESC"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
-        )
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AscWrapper", asc
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.clauses.AscWrapper", asc)
 
         idxcol = IndexedColumn(qbcolumns.Named(int, "col"), asc=False)
 
@@ -68,10 +64,10 @@ class TestIndexedColumn:
         collation = "'collation'"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.CollationWrapper", collation
+            mocker, "querybuilder.atoms.clauses.CollationWrapper", collation
         )
 
         idxcol = IndexedColumn(qbcolumns.Named(int, "col"), collation="foo")
@@ -88,14 +84,12 @@ class TestIndexedColumn:
         asc = "ASC"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
-        )
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.CollationWrapper", collation
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AscWrapper", asc
+            mocker, "querybuilder.atoms.clauses.CollationWrapper", collation
         )
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.clauses.AscWrapper", asc)
 
         idxcol = IndexedColumn(
             qbcolumns.Named(int, "col"), collation="collation", asc=True
@@ -149,13 +143,13 @@ class TestIndex:
         where = "where ..."
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", schema_relation
+            mocker, "querybuilder.atoms.relations.Named", schema_relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.UniqueClause", unique
+            mocker, "querybuilder.atoms.clauses.UniqueClause", unique
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", where
+            mocker, "querybuilder.atoms.clauses.WhereColumn", where
         )
 
         col = mock_column
@@ -188,10 +182,10 @@ class TestIndex:
         where = "where ..."
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", schema_relation
+            mocker, "querybuilder.atoms.relations.Named", schema_relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.UniqueClause", unique
+            mocker, "querybuilder.atoms.clauses.UniqueClause", unique
         )
 
         col = mock_column
@@ -222,10 +216,10 @@ class TestIndex:
         where = "where ..."
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", schema_relation
+            mocker, "querybuilder.atoms.relations.Named", schema_relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", where
+            mocker, "querybuilder.atoms.clauses.WhereColumn", where
         )
 
         col = mock_column
@@ -250,7 +244,7 @@ class TestIndex:
         schema_relation = "relation"
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", schema_relation
+            mocker, "querybuilder.atoms.relations.Named", schema_relation
         )
 
         col = mock_column
diff --git a/querybuilder/tests/conftest.py b/querybuilder/tests/conftest.py
index a503067cc4a6459a606b2a6f0fa9451cdc27df5d..68709395c1276a7d2b2edbfe6ee37531c5bf9a69 100644
--- a/querybuilder/tests/conftest.py
+++ b/querybuilder/tests/conftest.py
@@ -1,15 +1,15 @@
 import pytest
-from querybuilder.schemas.helper import table
+from querybuilder.helpers import table
 from typing import cast
-import querybuilder
+import querybuilder as qb
 
 
 @pytest.fixture
-def person_table() -> querybuilder.queries.algebra.relations.Table:
+def person_table() -> qb.atoms.relations.Table:
     @table
     class Person:
         id: int
         name: str
         age: int
 
-    return cast(querybuilder.queries.algebra.relations.Table, Person)
+    return cast(qb.atoms.relations.Table, Person)
diff --git a/querybuilder/tests/drivers/postgres/test_postgres_tokenizer.py b/querybuilder/tests/drivers/postgres/test_postgres_tokenizer.py
index b4e2924289a89ddc55469018a78bb1589e77c145..835565bc5587b6fa5e8bc58f7b334386b9c4160b 100644
--- a/querybuilder/tests/drivers/postgres/test_postgres_tokenizer.py
+++ b/querybuilder/tests/drivers/postgres/test_postgres_tokenizer.py
@@ -124,9 +124,7 @@ class TestPostgresTokenizer(parent_suite.TestSQLTokenizer):
 
     def test_placeholder_with_key_provided(self):  # override
         key = "42"
-        result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Placeholder), key=key
-        )
+        result = self.tk(self.get_empty_instance(qb.atoms.columns.Placeholder), key=key)
 
         expected = TkStr(qbtoken.Token.Name.Variable, f"%({key})s").to_seq()
 
@@ -134,7 +132,7 @@ class TestPostgresTokenizer(parent_suite.TestSQLTokenizer):
 
     def test_placeholder_with_no_key_provided(self):  # override
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Placeholder),
+            self.get_empty_instance(qb.atoms.columns.Placeholder),
         )
 
         expected = TkStr(qbtoken.Token.Name.Variable, "%s").to_seq()
diff --git a/querybuilder/tests/drivers/sql/test_tokenizer.py b/querybuilder/tests/drivers/sql/test_tokenizer.py
index 71c4b48a2f5f53f8b7f207514e9b0c0b15c7415a..11cc7db04ab89422c0bd778baa57f0c66a918d9c 100644
--- a/querybuilder/tests/drivers/sql/test_tokenizer.py
+++ b/querybuilder/tests/drivers/sql/test_tokenizer.py
@@ -3,8 +3,8 @@ import querybuilder as qb
 from querybuilder.formatting import token as qbtoken
 from querybuilder.formatting.tokentree import TkStr, TkSeq, TkTree, TkInd
 import querybuilder.utils.constants as qbconstants
-import querybuilder.queries.algebra.columns as qbcolumns
-import querybuilder.queries.algebra.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
 
 
 class TestSQLTokenizer:
@@ -32,7 +32,7 @@ class TestSQLTokenizer:
             self.tk(DummyClass())
 
     def test_tokenize_default(self):
-        result = self.tk(qb.queries.algebra.columns.Default())
+        result = self.tk(qb.atoms.columns.Default())
 
         expected = TkStr(qbtoken.Keyword, "DEFAULT").to_seq()
 
@@ -41,7 +41,7 @@ class TestSQLTokenizer:
     def test_tokenize_exists(self):
         query = self.get_dummy_tkseq(value="QUERY")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Exists),
+            self.get_empty_instance(qb.atoms.columns.Exists),
             query=query,
         )
         expected = (
@@ -58,7 +58,7 @@ class TestSQLTokenizer:
     def test_tokenize_aggregate_with_distinct(self):
         column = self.get_dummy_tkseq("COLUMN")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Aggregate),
+            self.get_empty_instance(qb.atoms.columns.Aggregate),
             aggregator="avg",
             column=column,
             distinct=True,
@@ -80,7 +80,7 @@ class TestSQLTokenizer:
     def test_tokenize_aggregate_without_distinct(self):
         column = self.get_dummy_tkseq("column")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Aggregate),
+            self.get_empty_instance(qb.atoms.columns.Aggregate),
             aggregator="avg",
             column=column,
             distinct=False,
@@ -97,7 +97,7 @@ class TestSQLTokenizer:
         assert expected == result
 
     def test_tokenize_case_without_else(self):
-        case_column = self.get_empty_instance(qb.queries.algebra.columns.Case)
+        case_column = self.get_empty_instance(qb.atoms.columns.Case)
         when = [
             (
                 self.get_dummy_tkseq(value=f"COND{i}"),
@@ -141,7 +141,7 @@ class TestSQLTokenizer:
         assert result == expected
 
     def test_tokenize_case_with_else(self):
-        case_column = self.get_empty_instance(qb.queries.algebra.columns.Case)
+        case_column = self.get_empty_instance(qb.atoms.columns.Case)
         when = [
             (
                 self.get_dummy_tkseq(value=f"COND{i}"),
@@ -191,7 +191,7 @@ class TestSQLTokenizer:
     def test_tokenize_cast(self):
         column = self.get_dummy_tkseq(value="COLUMN")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Cast),
+            self.get_empty_instance(qb.atoms.columns.Cast),
             column=column,
             sqltype=str,
         )
@@ -220,7 +220,7 @@ class TestSQLTokenizer:
     def test_tokenize_transform(self):
         columns = self.get_dummy_columns(3)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Transform),
+            self.get_empty_instance(qb.atoms.columns.Transform),
             columns=columns,
             transformator="f",
         )
@@ -244,7 +244,7 @@ class TestSQLTokenizer:
         tkval = "COLUMN"
         column = self.get_dummy_tkseq(value=tkval)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Negate),
+            self.get_empty_instance(qb.atoms.columns.Negate),
             operator="-",
             column=column,
         )
@@ -259,7 +259,7 @@ class TestSQLTokenizer:
     def test_arithmetic_expression(self):
         columns = self.get_dummy_columns(3)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.ArithmeticOperation),
+            self.get_empty_instance(qb.atoms.columns.ArithmeticOperation),
             operator="+",
             columns=columns,
         )
@@ -275,7 +275,7 @@ class TestSQLTokenizer:
         relation = self.get_dummy_tkseq(value="relation")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.InRelation),
+            self.get_empty_instance(qb.atoms.columns.InRelation),
             operator="IN",
             columns=columns,
             relation=relation,
@@ -292,7 +292,7 @@ class TestSQLTokenizer:
     def test_comparison(self):
         columns = self.get_dummy_columns(2)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Comparison),
+            self.get_empty_instance(qb.atoms.columns.Comparison),
             operator=">",
             columns=columns,
         )
@@ -306,7 +306,7 @@ class TestSQLTokenizer:
     def test_not(self):
         column = self.get_dummy_tkseq()
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Not),
+            self.get_empty_instance(qb.atoms.columns.Not),
             combinator="NOT",
             column=column,
         )
@@ -320,7 +320,7 @@ class TestSQLTokenizer:
     def test_boolean_combination(self):
         columns = self.get_dummy_columns(3)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.BooleanCombination),
+            self.get_empty_instance(qb.atoms.columns.BooleanCombination),
             combinator="AND",
             columns=columns,
         )
@@ -340,7 +340,7 @@ class TestSQLTokenizer:
     def test_tuple(self):
         columns = self.get_dummy_columns(3)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Tuple),
+            self.get_empty_instance(qb.atoms.columns.Tuple),
             columns=columns,
         )
 
@@ -360,7 +360,7 @@ class TestSQLTokenizer:
     def test_pretuple(self):
         columns = self.get_dummy_columns(3)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Pretuple),
+            self.get_empty_instance(qb.atoms.columns.Pretuple),
             columns=columns,
         )
 
@@ -382,7 +382,7 @@ class TestSQLTokenizer:
     )
     def test_constant(self, typ, val):  # kinda bad test
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Constant),
+            self.get_empty_instance(qb.atoms.columns.Constant),
             sqltype=typ,
             constant=val,
         )
@@ -393,9 +393,7 @@ class TestSQLTokenizer:
 
     def test_placeholder_with_key_provided(self):
         key = "42"
-        result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Placeholder), key=key
-        )
+        result = self.tk(self.get_empty_instance(qb.atoms.columns.Placeholder), key=key)
 
         expected = TkStr(qbtoken.Token.Name.Variable, ":" + key).to_seq()
 
@@ -403,7 +401,7 @@ class TestSQLTokenizer:
 
     def test_placeholder_with_no_key_provided(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.columns.Placeholder),
+            self.get_empty_instance(qb.atoms.columns.Placeholder),
         )
 
         expected = TkStr(qbtoken.Token.Name.Variable, "?").to_seq()
@@ -451,7 +449,7 @@ class TestSQLTokenizer:
 
     def test_tokenize_default_values(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.DefaultValuesClause),
+            self.get_empty_instance(qb.atoms.clauses.DefaultValuesClause),
         )
 
         expected = TkSeq(
@@ -537,7 +535,7 @@ class TestSQLTokenizer:
 
     def test_distinct_column_with_no_column(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.DistinctColumn),
+            self.get_empty_instance(qb.atoms.clauses.DistinctColumn),
             column=None,
         )
 
@@ -548,7 +546,7 @@ class TestSQLTokenizer:
     def test_distinct_column_with_column(self):
         column = self.get_dummy_tkseq(value="column")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.DistinctColumn),
+            self.get_empty_instance(qb.atoms.clauses.DistinctColumn),
             column=column,
         )
 
@@ -576,7 +574,7 @@ class TestSQLTokenizer:
         name = "foo"
         query = self.get_dummy_tkseq(value="query")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.WithClause),
+            self.get_empty_instance(qb.atoms.clauses.WithClause),
             name=name,
             query=query,
             materialized=False,
@@ -609,7 +607,7 @@ class TestSQLTokenizer:
         name = "foo"
         query = self.get_dummy_tkseq(value="query")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.WithClause),
+            self.get_empty_instance(qb.atoms.clauses.WithClause),
             name=name,
             query=query,
             materialized=True,
@@ -640,7 +638,7 @@ class TestSQLTokenizer:
         name = "foo"
         query = self.get_dummy_tkseq(value="query")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.WithClause),
+            self.get_empty_instance(qb.atoms.clauses.WithClause),
             name=name,
             query=query,
             materialized=None,
@@ -698,7 +696,7 @@ class TestSQLTokenizer:
         alias = "foo"
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.AliasedColumn),
+            self.get_empty_instance(qb.atoms.clauses.AliasedColumn),
             column=column,
             alias=alias,
         )
@@ -724,7 +722,7 @@ class TestSQLTokenizer:
         column = self.get_dummy_tkseq(value="column")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.AliasedColumn),
+            self.get_empty_instance(qb.atoms.clauses.AliasedColumn),
             column=column,
             alias=None,
         )
@@ -737,7 +735,7 @@ class TestSQLTokenizer:
         relation = self.get_dummy_tkseq(value="relation")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.RelationClauseWrapper),
+            self.get_empty_instance(qb.atoms.clauses.RelationClauseWrapper),
             relation=relation,
         )
 
@@ -753,7 +751,7 @@ class TestSQLTokenizer:
         column = self.get_dummy_tkseq(value="column")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.WhereColumn),
+            self.get_empty_instance(qb.atoms.clauses.WhereColumn),
             column=column,
         )
 
@@ -769,7 +767,7 @@ class TestSQLTokenizer:
         column = self.get_dummy_tkseq(value="column")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.GroupColumn),
+            self.get_empty_instance(qb.atoms.clauses.GroupColumn),
             column=column,
         )
 
@@ -791,7 +789,7 @@ class TestSQLTokenizer:
         column = self.get_dummy_tkseq(value="column")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.HavingColumn),
+            self.get_empty_instance(qb.atoms.clauses.HavingColumn),
             column=column,
         )
 
@@ -805,7 +803,7 @@ class TestSQLTokenizer:
 
     def test_temporary_wrapper(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.TemporaryWrapper),
+            self.get_empty_instance(qb.atoms.clauses.TemporaryWrapper),
         )
 
         expected = TkStr(qbtoken.Keyword, "TEMPORARY").to_seq()
@@ -814,7 +812,7 @@ class TestSQLTokenizer:
 
     def test_if_not_exists_wrapper(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.IfNotExistsWrapper),
+            self.get_empty_instance(qb.atoms.clauses.IfNotExistsWrapper),
         )
 
         expected = TkSeq(
@@ -831,7 +829,7 @@ class TestSQLTokenizer:
 
     def test_if_exists_wrapper(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.IfExistsWrapper),
+            self.get_empty_instance(qb.atoms.clauses.IfExistsWrapper),
         )
 
         expected = TkSeq(
@@ -848,7 +846,7 @@ class TestSQLTokenizer:
         subquery = self.get_dummy_tkseq(value="subquery")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.AsQueryWrapper),
+            self.get_empty_instance(qb.atoms.clauses.AsQueryWrapper),
             subquery=subquery,
         )
 
@@ -863,7 +861,7 @@ class TestSQLTokenizer:
         offset = 42
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Offset),
+            self.get_empty_instance(qb.atoms.clauses.Offset),
             offset=offset,
         )
 
@@ -877,7 +875,7 @@ class TestSQLTokenizer:
     def test_order_columns_with_true_how(self):
         column = self.get_dummy_tkseq(value="column")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.OrderColumn),
+            self.get_empty_instance(qb.atoms.clauses.OrderColumn),
             column=column,
             how=True,
         )
@@ -901,7 +899,7 @@ class TestSQLTokenizer:
     def test_order_columns_with_false_how(self):
         column = self.get_dummy_tkseq(value="column")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.OrderColumn),
+            self.get_empty_instance(qb.atoms.clauses.OrderColumn),
             column=column,
             how=False,
         )
@@ -925,7 +923,7 @@ class TestSQLTokenizer:
     def test_order_columns_with_none_how(self):
         column = self.get_dummy_tkseq(value="column")
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.OrderColumn),
+            self.get_empty_instance(qb.atoms.clauses.OrderColumn),
             column=column,
             how=None,
         )
@@ -948,7 +946,7 @@ class TestSQLTokenizer:
     def test_limit_one_row_only(self):
         limit = 1
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+            self.get_empty_instance(qb.atoms.clauses.Limit),
             limit=limit,
             with_ties=False,
         )
@@ -974,7 +972,7 @@ class TestSQLTokenizer:
     def test_limit_some_rows_only(self):
         limit = 42
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+            self.get_empty_instance(qb.atoms.clauses.Limit),
             limit=limit,
             with_ties=False,
         )
@@ -1000,7 +998,7 @@ class TestSQLTokenizer:
     def test_limit_some_rows_with_ties(self):
         limit = 42
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+            self.get_empty_instance(qb.atoms.clauses.Limit),
             limit=limit,
             with_ties=True,
         )
@@ -1028,7 +1026,7 @@ class TestSQLTokenizer:
     def test_set_combinator_wrapper_with_True_all(self):
         combinator = qbconstants.SetCombinator.UNION
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.SetCombinatorWrapper),
+            self.get_empty_instance(qb.atoms.clauses.SetCombinatorWrapper),
             combinator=combinator,
             all=True,
         )
@@ -1048,7 +1046,7 @@ class TestSQLTokenizer:
     def test_set_combinator_wrapper_with_False_all(self):
         combinator = qbconstants.SetCombinator.UNION
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.SetCombinatorWrapper),
+            self.get_empty_instance(qb.atoms.clauses.SetCombinatorWrapper),
             combinator=combinator,
             all=False,
         )
@@ -1069,7 +1067,7 @@ class TestSQLTokenizer:
         set_columns = self.get_dummy_columns(3)
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.SetColumnsClause),
+            self.get_empty_instance(qb.atoms.clauses.SetColumnsClause),
             set_columns=set_columns,
         )
 
@@ -1254,7 +1252,7 @@ class TestSQLTokenizer:
 
     def test_cascade_clause_True(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.DropCascadeClause),
+            self.get_empty_instance(qb.atoms.clauses.DropCascadeClause),
             cascade=True,
         )
 
@@ -1264,7 +1262,7 @@ class TestSQLTokenizer:
 
     def test_cascade_clause_False(self):
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.DropCascadeClause),
+            self.get_empty_instance(qb.atoms.clauses.DropCascadeClause),
             cascade=False,
         )
 
@@ -1468,7 +1466,7 @@ class TestSQLTokenizer:
         assert expected == result
 
     def test_tokenize_star(self):
-        result = self.tk(self.get_empty_instance(qb.queries.algebra.columns.Star))
+        result = self.tk(self.get_empty_instance(qb.atoms.columns.Star))
 
         expected = TkStr(qbtoken.Operator, "*").to_seq()
         assert expected == result
@@ -1478,7 +1476,7 @@ class TestSQLTokenizer:
         subrelation = self.get_dummy_tkseq(value="foo")
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.relations.Aliased),
+            self.get_empty_instance(qb.atoms.relations.Aliased),
             subrelation=subrelation,
             name=name,
             columns=(),
@@ -1494,7 +1492,7 @@ class TestSQLTokenizer:
         columns = self.get_dummy_columns(3)
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.relations.Aliased),
+            self.get_empty_instance(qb.atoms.relations.Aliased),
             subrelation=subrelation,
             name=name,
             columns=columns,
@@ -1528,7 +1526,7 @@ class TestSQLTokenizer:
         )
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.relations.Aliased),
+            self.get_empty_instance(qb.atoms.relations.Aliased),
             subrelation=subrelation,
             name=name,
             columns=(),
@@ -1557,7 +1555,7 @@ class TestSQLTokenizer:
         )
 
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.relations.Aliased),
+            self.get_empty_instance(qb.atoms.relations.Aliased),
             subrelation=subrelation,
             name=name,
             columns=columns,
diff --git a/querybuilder/tests/drivers/sqlite/test_sqlite_specificities.py b/querybuilder/tests/drivers/sqlite/test_sqlite_specificities.py
index fa26d70c714759f22b68919920d89266ae106bc7..35c36ba9fa2006612b481febc12885f4d0f11ced 100644
--- a/querybuilder/tests/drivers/sqlite/test_sqlite_specificities.py
+++ b/querybuilder/tests/drivers/sqlite/test_sqlite_specificities.py
@@ -1,6 +1,5 @@
 import pytest
 import querybuilder as qb
-from querybuilder.queries import algebra
 import warnings
 
 
@@ -9,30 +8,30 @@ class TestSqliteSpecificities:
     formatter = qb.formatting.formatter.StandardFormatter()
 
     def test_schema_removed_in_create(self):
-        col1 = algebra.columns.TableColumn(
+        col1 = qb.atoms.columns.TableColumn(
             int, "x", schema_name="main", relation_name="A"
         )
-        A = algebra.relations.Table("A", schema_name="main", columns=(col1,))
-        col2 = algebra.columns.TableColumn(
+        A = qb.atoms.relations.Table("A", schema_name="main", columns=(col1,))
+        col2 = qb.atoms.columns.TableColumn(
             int,
             "y",
             schema_name="main",
             relation_name="B",
-            constraints=(qb.schemas.constraints.ColumnReferences(col1),),
+            constraints=(qb.atoms.constraints.ColumnReferences(col1),),
         )
-        B = algebra.relations.Table("B", schema_name="main", columns=(col2,))
+        B = qb.atoms.relations.Table("B", schema_name="main", columns=(col2,))
         result = self.formatter.get_formatted(B.create().tokenize(self.tk))
         expected = "CREATE TABLE main.b (y INTEGER REFERENCES a(x))"
         assert expected == result
 
     def test_autoincrement_in_create(self):
-        col1 = algebra.columns.TableColumn(
+        col1 = qb.atoms.columns.TableColumn(
             int,
             "x",
             relation_name="A",
-            constraints=(qb.schemas.constraints.ColumnGeneratedAsIdentity(),),
+            constraints=(qb.atoms.constraints.ColumnGeneratedAsIdentity(),),
         )
-        A = algebra.relations.Table("A", columns=(col1,))
+        A = qb.atoms.relations.Table("A", columns=(col1,))
         with pytest.warns(UserWarning):
             result = self.formatter.get_formatted(A.create().tokenize(self.tk))
         expected = "CREATE TABLE a (x INTEGER AUTOINCREMENT)"
diff --git a/querybuilder/tests/drivers/sqlite/test_sqlite_tokenizer.py b/querybuilder/tests/drivers/sqlite/test_sqlite_tokenizer.py
index 6f1e6b25359dbc3561e547ddaa15a7b0e8541146..d5bcef937179fdfed09edb7d7c364f71c13d095d 100644
--- a/querybuilder/tests/drivers/sqlite/test_sqlite_tokenizer.py
+++ b/querybuilder/tests/drivers/sqlite/test_sqlite_tokenizer.py
@@ -4,8 +4,8 @@ from querybuilder.formatting import token as qbtoken
 from querybuilder.formatting.tokentree import TkStr, TkSeq, TkTree, TkInd
 import querybuilder.utils.constants as qbconstants
 import querybuilder.tests.drivers.sql.test_tokenizer as parent_suite
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
 import querybuilder.queries.dql as qbdql
 
 
@@ -18,7 +18,7 @@ class TestSqliteTokenizer(parent_suite.TestSQLTokenizer):
     def test_limit_one_row_only(self):  # override
         limit = 1
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+            self.get_empty_instance(qb.atoms.clauses.Limit),
             limit=limit,
             with_ties=False,
         )
@@ -36,7 +36,7 @@ class TestSqliteTokenizer(parent_suite.TestSQLTokenizer):
     def test_limit_some_rows_only(self):  # override
         limit = 42
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+            self.get_empty_instance(qb.atoms.clauses.Limit),
             limit=limit,
             with_ties=False,
         )
@@ -56,7 +56,7 @@ class TestSqliteTokenizer(parent_suite.TestSQLTokenizer):
 
         with pytest.raises(NotImplementedError):
             result = self.tk(
-                self.get_empty_instance(qb.queries.algebra.clauses.Limit),
+                self.get_empty_instance(qb.atoms.clauses.Limit),
                 limit=limit,
                 with_ties=True,
             )
@@ -65,7 +65,7 @@ class TestSqliteTokenizer(parent_suite.TestSQLTokenizer):
         column = self.get_dummy_tkseq(value="column")
         scoped_column = self.tk.scope_it(column, noindent=True)
         result = self.tk(
-            self.get_empty_instance(qb.queries.algebra.clauses.OrderColumn),
+            self.get_empty_instance(qb.atoms.clauses.OrderColumn),
             column=scoped_column,
             how=None,
         )
diff --git a/querybuilder/tests/schemas/test_schema_helper.py b/querybuilder/tests/helpers/test_schema_helpers.py
similarity index 93%
rename from querybuilder/tests/schemas/test_schema_helper.py
rename to querybuilder/tests/helpers/test_schema_helpers.py
index 2485eee6c035a03c63c533d189485f60727994ae..ab601224d728a8ef7684f499c4d53ccd122bcde9 100644
--- a/querybuilder/tests/schemas/test_schema_helper.py
+++ b/querybuilder/tests/helpers/test_schema_helpers.py
@@ -2,8 +2,8 @@
 import pytest
 
 from datetime import date
-from querybuilder.schemas.helper import Collector, table, schema, ColumnSpec
-from querybuilder.schemas.constraints import ColumnReferences
+from querybuilder.helpers import Collector, table, schema, ColumnSpec
+from querybuilder.atoms.constraints import ColumnReferences
 import querybuilder as qb
 
 
@@ -12,7 +12,7 @@ class TestHelper:
     formatter = qb.formatting.formatter.Formatter()
 
     @classmethod
-    def _check(cls, obj: qb.classes.atoms.Atom, expected: str):
+    def _check(cls, obj: qb.atoms.atoms.Atom, expected: str):
         tokens = obj.tokenize(cls.tokenizer)
         formatted = cls.formatter.get_formatted(tokens)
         assert formatted == expected
@@ -24,7 +24,7 @@ class TestColumnSpec(TestHelper):
             int, name="bar", relation_name="foo", schema_name="public", primary_key=True
         )
         col = c.to_table_column()
-        assert type(col) == qb.queries.algebra.columns.TableColumn
+        assert type(col) == qb.atoms.columns.TableColumn
         assert col.name == "bar"
         assert col.relation_name == "foo"
         assert col.schema_name == "public"
@@ -42,14 +42,11 @@ class TestTableHelper(TestHelper):
             lastname: str
             birthday: date
 
-        assert type(mytable) == qb.queries.algebra.relations.Table
+        assert type(mytable) == qb.atoms.relations.Table
         assert mytable.name == "mytable"
         assert mytable.schema_name is None
         assert len(mytable.columns) == 4
-        assert all(
-            isinstance(c, qb.queries.algebra.columns.TableColumn)
-            for c in mytable.columns
-        )
+        assert all(isinstance(c, qb.atoms.columns.TableColumn) for c in mytable.columns)
         assert all(c.relation_name == "mytable" for c in mytable.columns)
         assert all(c.schema_name is None for c in mytable.columns)
         assert not mytable.constraints
@@ -72,14 +69,11 @@ class TestTableHelper(TestHelper):
             lastname: str
             birthday: date
 
-        assert type(mytable) == qb.queries.algebra.relations.Table
+        assert type(mytable) == qb.atoms.relations.Table
         assert mytable.name == "mytable"
         assert mytable.schema_name == "main"
         assert len(mytable.columns) == 4
-        assert all(
-            isinstance(c, qb.queries.algebra.columns.TableColumn)
-            for c in mytable.columns
-        )
+        assert all(isinstance(c, qb.atoms.columns.TableColumn) for c in mytable.columns)
         assert all(c.relation_name == "mytable" for c in mytable.columns)
         assert all(c.schema_name == "main" for c in mytable.columns)
         assert not mytable.constraints
@@ -101,14 +95,11 @@ class TestTableHelper(TestHelper):
             lastname: str
             birthday: date
 
-        assert type(mytable) == qb.queries.algebra.relations.Table
+        assert type(mytable) == qb.atoms.relations.Table
         assert mytable.name == "break"
         assert mytable.schema_name is None
         assert len(mytable.columns) == 4
-        assert all(
-            isinstance(c, qb.queries.algebra.columns.TableColumn)
-            for c in mytable.columns
-        )
+        assert all(isinstance(c, qb.atoms.columns.TableColumn) for c in mytable.columns)
         assert all(c.relation_name == "break" for c in mytable.columns)
         assert all(c.schema_name is None for c in mytable.columns)
         assert not mytable.constraints
@@ -130,14 +121,11 @@ class TestTableHelper(TestHelper):
             lastname: str
             birthday: date
 
-        assert type(mytable) == qb.queries.algebra.relations.Table
+        assert type(mytable) == qb.atoms.relations.Table
         assert mytable.name == "break"
         assert mytable.schema_name == "main"
         assert len(mytable.columns) == 4
-        assert all(
-            isinstance(c, qb.queries.algebra.columns.TableColumn)
-            for c in mytable.columns
-        )
+        assert all(isinstance(c, qb.atoms.columns.TableColumn) for c in mytable.columns)
         assert all(c.relation_name == "break" for c in mytable.columns)
         assert all(c.schema_name == "main" for c in mytable.columns)
         assert not mytable.constraints
@@ -265,7 +253,7 @@ class TestSchemaHelper(TestHelper):
                 player: int
                 since: date
 
-        assert type(main) == qb.schemas.schemas.Schema
+        assert type(main) == qb.atoms.schemas.Schema
         assert len(main.objects) == 3
         self._check(main, "main")
 
@@ -388,7 +376,7 @@ class TestSchemaHelper(TestHelper):
 
             # TODO: test index
 
-        assert type(main) == qb.schemas.schemas.Schema
+        assert type(main) == qb.atoms.schemas.Schema
         assert len(main.objects) == 5
         assert len(main.relations) == 5
         self._check(main, "main")
diff --git a/querybuilder/tests/queries/test_ddl.py b/querybuilder/tests/queries/test_ddl.py
index 6e823fa360f6adbd02e8b4c7387c133d376d2765..6723c82464f64ab8ac53c52c007035d6918cc164 100644
--- a/querybuilder/tests/queries/test_ddl.py
+++ b/querybuilder/tests/queries/test_ddl.py
@@ -8,13 +8,12 @@ from querybuilder.queries.ddl import (
     CreateView,
     CreateSchema,
 )
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
 import querybuilder.queries.dql as qbdql
-import querybuilder.schemas.schemas as qbschemas
+import querybuilder.atoms.schemas as qbschemas
 from querybuilder.tests.utils import create_subtokenizable_mock
-import querybuilder
-import querybuilder.schemas.schemas as qbschemas
+import querybuilder.atoms.schemas as qbschemas
 
 
 class TestDrop:
@@ -23,18 +22,16 @@ class TestDrop:
         table = "table"
         if_exists = "if_exists"
         cascade = "cascade"
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.relations.Named", table)
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", table
+            mocker, "querybuilder.atoms.clauses.IfExistsWrapper", if_exists
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.IfExistsWrapper", if_exists
-        )
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.DropCascadeClause", cascade
+            mocker, "querybuilder.atoms.clauses.DropCascadeClause", cascade
         )
         create_subtokenizable_mock(
             mocker,
-            "querybuilder.queries.algebra.clauses.DBObjectNameWrapper",
+            "querybuilder.atoms.clauses.DBObjectNameWrapper",
             target_type,
         )
 
@@ -55,15 +52,13 @@ class TestDrop:
         target_type = "TABLE"
         table = "table"
         if_exists = "if_exists"
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.relations.Named", table)
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", table
-        )
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.IfExistsWrapper", if_exists
+            mocker, "querybuilder.atoms.clauses.IfExistsWrapper", if_exists
         )
         create_subtokenizable_mock(
             mocker,
-            "querybuilder.queries.algebra.clauses.DBObjectNameWrapper",
+            "querybuilder.atoms.clauses.DBObjectNameWrapper",
             target_type,
         )
 
@@ -79,16 +74,14 @@ class TestDrop:
         target_type = "TABLE"
         table = "table"
         cascade = "cascade"
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", table
-        )
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.relations.Named", table)
 
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.DropCascadeClause", cascade
+            mocker, "querybuilder.atoms.clauses.DropCascadeClause", cascade
         )
         create_subtokenizable_mock(
             mocker,
-            "querybuilder.queries.algebra.clauses.DBObjectNameWrapper",
+            "querybuilder.atoms.clauses.DBObjectNameWrapper",
             target_type,
         )
 
@@ -105,12 +98,10 @@ class TestDrop:
         table = "table"
         if_exists = "if_exists"
         cascade = "cascade"
-        create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", table
-        )
+        create_subtokenizable_mock(mocker, "querybuilder.atoms.relations.Named", table)
         create_subtokenizable_mock(
             mocker,
-            "querybuilder.queries.algebra.clauses.DBObjectNameWrapper",
+            "querybuilder.atoms.clauses.DBObjectNameWrapper",
             target_type,
         )
 
@@ -145,7 +136,7 @@ class TestCreateIndex:
 
     @pytest.fixture
     def mock_index(self, mocker, mock_index_subtoken, mock_index_kwargs):
-        patcher = mocker.patch("querybuilder.schemas.schemas.Index")
+        patcher = mocker.patch("querybuilder.atoms.schemas.Index")
         instance = patcher.return_value
         instance.subtokenize = Mock(return_value=mock_index_subtoken)
         instance._get_creation_kwargs = Mock(return_value=mock_index_kwargs)
@@ -156,7 +147,7 @@ class TestCreateIndex:
         if_not_exists = "if_not_exists"
         create_subtokenizable_mock(
             mocker,
-            "querybuilder.queries.algebra.clauses.IfNotExistsWrapper",
+            "querybuilder.atoms.clauses.IfNotExistsWrapper",
             if_not_exists,
         )
 
diff --git a/querybuilder/tests/queries/test_dml.py b/querybuilder/tests/queries/test_dml.py
index 7cf9aaab4dead999323b0ac8693925e0bef610e5..01a457a0906d80faaf977ff0748c262cf6339dcf 100644
--- a/querybuilder/tests/queries/test_dml.py
+++ b/querybuilder/tests/queries/test_dml.py
@@ -3,8 +3,8 @@ from pytest_mock import MockerFixture
 from mock import Mock
 from typing import Any, Dict
 from querybuilder.queries.dml import Insert, Delete, Update
-import querybuilder.queries.algebra.relations as qbrelations
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
+import querybuilder.atoms.columns as qbcolumns
 import querybuilder.queries.dql as qbdql
 from querybuilder.tests.utils import create_subtokenizable_mock
 import querybuilder
@@ -16,13 +16,13 @@ class TestInsert:
         column = "column"
         query = "default values"
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.DefaultValuesClause", query
+            mocker, "querybuilder.atoms.clauses.DefaultValuesClause", query
         )
 
         insert = Insert(
@@ -44,10 +44,10 @@ class TestInsert:
         column = "column"
         query = "select ..."
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.AliasedColumn", column
+            mocker, "querybuilder.atoms.clauses.AliasedColumn", column
         )
         create_subtokenizable_mock(mocker, "querybuilder.queries.dql.Select", query)
 
@@ -107,10 +107,10 @@ class TestDelete:
         relation = "relation"
         column = "column"
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", column
+            mocker, "querybuilder.atoms.clauses.WhereColumn", column
         )
 
         delete = Delete(qbrelations.Named("rel"), qbcolumns.Named(int, "col").eq(3))
@@ -127,7 +127,7 @@ class TestDelete:
     def test_get_subtokenize_kwargs_without_where(self, mocker):
         relation = "relation"
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
 
         delete = Delete(qbrelations.Named("rel"))
@@ -173,13 +173,13 @@ class TestUpdate:
         column = "column"
         set_columns = "SET ..."
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", column
+            mocker, "querybuilder.atoms.clauses.WhereColumn", column
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.SetColumnsClause", set_columns
+            mocker, "querybuilder.atoms.clauses.SetColumnsClause", set_columns
         )
 
         mapping = {qbcolumns.Named(int, "x"): qbcolumns.Constant(int, 3)}
@@ -201,10 +201,10 @@ class TestUpdate:
         relation = "relation"
         set_columns = "SET ..."
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.SetColumnsClause", set_columns
+            mocker, "querybuilder.atoms.clauses.SetColumnsClause", set_columns
         )
 
         mapping = {qbcolumns.Named(int, "x"): qbcolumns.Constant(int, 3)}
@@ -220,10 +220,10 @@ class TestUpdate:
         relation = "relation"
         where = "where ..."
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", where
+            mocker, "querybuilder.atoms.clauses.WhereColumn", where
         )
 
         delete = Delete(
@@ -243,7 +243,7 @@ class TestUpdate:
     def test_delete_get_subtokenize_kwargs_without_where(self, mocker):
         relation = "relation"
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
 
         delete = Delete(qbrelations.Named("rel"))
@@ -260,10 +260,10 @@ class TestUpdate:
         relation = "relation"
         where = "where ..."
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.clauses.WhereColumn", where
+            mocker, "querybuilder.atoms.clauses.WhereColumn", where
         )
 
         delete = Delete(
@@ -283,7 +283,7 @@ class TestUpdate:
     def test_delete_get_subtokenize_kwargs_without_where(self, mocker):
         relation = "relation"
         create_subtokenizable_mock(
-            mocker, "querybuilder.queries.algebra.relations.Named", relation
+            mocker, "querybuilder.atoms.relations.Named", relation
         )
 
         delete = Delete(qbrelations.Named("rel"))
diff --git a/querybuilder/tests/queries/test_dql.py b/querybuilder/tests/queries/test_dql.py
index 7b4ed1999639f55db5457b230ffc8011dc920de0..0ce3cfbe960d129d4abe1b30f0ae15ba373c50a6 100644
--- a/querybuilder/tests/queries/test_dql.py
+++ b/querybuilder/tests/queries/test_dql.py
@@ -1,8 +1,8 @@
 import pytest
-import querybuilder as qb
-import querybuilder.queries.algebra.columns as qbcolumns
+import querybuilder.atoms.columns as qbcolumns
+import querybuilder.atoms.relations as qbrelations
 import querybuilder.queries.dql as dql
-import querybuilder.queries.algebra.relations as qbrelations
+import querybuilder as qb
 
 
 class TestDQL:
diff --git a/querybuilder/tests/classes/test_stores.py b/querybuilder/tests/utils/test_stores.py
similarity index 98%
rename from querybuilder/tests/classes/test_stores.py
rename to querybuilder/tests/utils/test_stores.py
index 072732f8980419143d44955b105bcdf260b324a5..990a2f812c746bddafebc3280d20c25c182d9391 100644
--- a/querybuilder/tests/classes/test_stores.py
+++ b/querybuilder/tests/utils/test_stores.py
@@ -1,5 +1,5 @@
 import pytest
-from querybuilder.classes.stores import (
+from querybuilder.utils.stores import (
     KeyedTuple,
     NamedStore,
     UNamedStore,
diff --git a/querybuilder/tests/utils/test_transaction_manager.py b/querybuilder/tests/utils/test_transaction_manager.py
index 65328883f3b739b39464e72856d0e3d754d54af4..731eb23cd959975ce244f681ea19e1cda5f8d87b 100644
--- a/querybuilder/tests/utils/test_transaction_manager.py
+++ b/querybuilder/tests/utils/test_transaction_manager.py
@@ -6,8 +6,8 @@ import sqlite3
 
 import querybuilder
 from querybuilder.queries.dml import Insert
-from querybuilder.queries.algebra.relations import Named as NamedRel
-from querybuilder.queries.algebra.columns import (
+from querybuilder.atoms.relations import Named as NamedRel
+from querybuilder.atoms.columns import (
     Placeholder,
     Constant,
     Value,
diff --git a/querybuilder/classes/stores.py b/querybuilder/utils/stores.py
similarity index 99%
rename from querybuilder/classes/stores.py
rename to querybuilder/utils/stores.py
index 874ece2c02f9c0be03945f871f9859af153e9f07..3a14cc4ce2a35451d9510473e03b5d8a55ad69e4 100644
--- a/querybuilder/classes/stores.py
+++ b/querybuilder/utils/stores.py
@@ -19,10 +19,9 @@ from typing import (
     overload,
 )
 from typing_extensions import TypeGuard
-import querybuilder.classes.atoms as atoms
+import querybuilder.atoms.atoms as atoms
 from querybuilder.utils.constants import MISSING
 from querybuilder.utils.typing import KeyedProto, NamedProto, PrettyPrinter, E, K, V
-import querybuilder
 
 T = TypeVar("T")
 
diff --git a/querybuilder/utils/typing.py b/querybuilder/utils/typing.py
index ac6dea1a82475ff9ecb55113f05bc7e46c4d587a..1f70804baeb48e916ed8b6cd5350ad8115f0d778 100644
--- a/querybuilder/utils/typing.py
+++ b/querybuilder/utils/typing.py
@@ -20,7 +20,7 @@ from typing_extensions import (
 )  # TODO: import from typing for recent versions of python
 from querybuilder.formatting.token import _TokenType
 import querybuilder.formatting.tokentree as qbtokentree
-import querybuilder.classes.atoms as qbatoms
+import querybuilder.atoms.atoms as qbatoms
 import querybuilder as qb
 
 
diff --git a/querybuilder/visitors/stores.py b/querybuilder/visitors/stores.py
index c82feb14eded201f1f69ed514e3705f5e28ac75e..ec597a5e5bd0b7588f7f7367c8d0b5669211f759 100644
--- a/querybuilder/visitors/stores.py
+++ b/querybuilder/visitors/stores.py
@@ -1,14 +1,14 @@
 from __future__ import annotations
 from functools import singledispatchmethod
 from typing import Any, Callable, Iterable, Optional, TypeVar, cast
-import querybuilder.classes as classes
-from querybuilder.queries.algebra.columns import Placeholder
+from querybuilder.atoms.columns import Placeholder
 from querybuilder.utils.typing import KeyedProto, NamedProto
 from querybuilder.utils.constants import MISSING
+from querybuilder.utils.stores import UNamedStore, KeyedTuple
 import querybuilder
 
 
-class WithQueryStore(classes.stores.UNamedStore):
+class WithQueryStore(UNamedStore):
     __slots__ = ()
 
     @classmethod
@@ -34,7 +34,7 @@ class WithQueryStore(classes.stores.UNamedStore):
         raise TypeError(f"Unexpected type {obj.__class__}")
 
 
-class PlaceholderStore(classes.stores.KeyedTuple[Placeholder]):
+class PlaceholderStore(KeyedTuple[Placeholder]):
     """KeyedTuple gathering placeholders in order
 
     Anonymous (i.e., keyless) elements are allowed, as well as key repetitions as far as