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