Mentions légales du service
Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Q
Querybuilder
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pydisk
Querybuilder
Commits
845d9120
Commit
845d9120
authored
1 year ago
by
PAPERMAN Charles
Browse files
Options
Downloads
Plain Diff
Merge branch 'hotfix/readme' into 'master'
Hotfix/readme See merge request
!73
parents
33ad554b
2bb13e86
No related branches found
No related tags found
1 merge request
!73
Hotfix/readme
Pipeline
#869411
passed
1 year ago
Stage: build
Stage: test
Changes
2
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
README.md
+41
-42
41 additions, 42 deletions
README.md
readme_doctests.py
+107
-0
107 additions, 0 deletions
readme_doctests.py
with
148 additions
and
42 deletions
README.md
+
41
−
42
View file @
845d9120
...
@@ -34,23 +34,23 @@ from uuid import UUID, uuid4 as uuid_gen
...
@@ -34,23 +34,23 @@ from uuid import UUID, uuid4 as uuid_gen
from
querybuilder.schemas.helper
import
table
from
querybuilder.schemas.helper
import
table
@table
@table
class
P
erson
:
class
p
erson
:
id
:
UUID
id
:
UUID
name
:
str
name
:
str
birth_year
:
int
birth_year
:
int
~~~
~~~
This code snippet creates a (non-mutable) table
`
P
erson`
. From those object we can build
This code snippet creates a (non-mutable) table
`
p
erson`
. From those object we can build
`queries`
. Those are not tied to any database.
`queries`
. Those are not tied to any database.
~~~
python
~~~
python
q
=
P
erson
.
select
([
P
erson
.
c
.
birth_year
,
P
erson
.
c
.
name
])
#
P
erson.c is a shorthand for
P
erson.columns
q
=
p
erson
.
select
([
p
erson
.
c
.
birth_year
,
p
erson
.
c
.
name
])
#
p
erson.c is a shorthand for
p
erson.columns
~~~
~~~
We can then get the string representation of the query
`q`
by using
`str(q)`
which returns
We can then get the string representation of the query
`q`
by using
`str(q)`
which returns
~~~
sql
~~~
sql
SELECT
P
erson
.
birth_year
,
P
erson
.
name
FROM
P
erson
SELECT
p
erson
.
birth_year
,
p
erson
.
name
FROM
p
erson
~~~
~~~
We can apply simple transformation to
`q`
. As queries (and most object)
We can apply simple transformation to
`q`
. As queries (and most object)
...
@@ -63,7 +63,7 @@ q2 = q.add_where(q.c.birth_year.gt(1800)).set_limit(10).set_columns(["name"])
...
@@ -63,7 +63,7 @@ q2 = q.add_where(q.c.birth_year.gt(1800)).set_limit(10).set_columns(["name"])
Then, formatting the query with
`str(q2)`
gives:
Then, formatting the query with
`str(q2)`
gives:
~~~
sql
~~~
sql
SELECT
P
erson
.
name
FROM
P
erson
WHERE
P
erson
.
birth_year
>
1800
FETCH
FIRST
10
ROWS
ONLY
SELECT
p
erson
.
name
FROM
p
erson
WHERE
p
erson
.
birth_year
>
1800
FETCH
FIRST
10
ROWS
ONLY
~~~
~~~
## Using an actual database backend
## Using an actual database backend
...
@@ -83,10 +83,10 @@ from querybuilder.drivers.sqlite.connector import Connector
...
@@ -83,10 +83,10 @@ from querybuilder.drivers.sqlite.connector import Connector
db
=
Connector
(
"
:memory:
"
)
# The ":memory:" here is SQLite-specific for in-memory non-persistent database.
db
=
Connector
(
"
:memory:
"
)
# The ":memory:" here is SQLite-specific for in-memory non-persistent database.
~~~
~~~
We can create the table
`
P
erson`
using
`
P
erson.create()`
which produces the following query:
We can create the table
`
p
erson`
using
`
p
erson.create()`
which produces the following query:
~~~
sql
~~~
sql
CREATE
TABLE
P
erson
(
id
UUID
,
name
TEXT
,
birth_year
INTEGER
)
CREATE
TABLE
p
erson
(
id
UUID
,
name
TEXT
,
birth_year
INTEGER
)
~~~
~~~
SQLite does not support
`UUID`
.
SQLite does not support
`UUID`
.
...
@@ -101,19 +101,19 @@ UserWarning: sqlite does not support UUID, using TEXT type instead
...
@@ -101,19 +101,19 @@ UserWarning: sqlite does not support UUID, using TEXT type instead
Here is how the query is executed in the SQLite database
`db`
:
Here is how the query is executed in the SQLite database
`db`
:
~~~
python
~~~
python
db
.
execute
(
P
erson
.
create
())
db
.
execute
(
p
erson
.
create
())
~~~
~~~
We can then create a query to populate the table:
We can then create a query to populate the table:
~~~
python
~~~
python
q_insert
=
P
erson
.
insert_values
(
in_columns
=
(
P
erson
.
c
[[
"
name
"
,
"
birth_year
"
]]),
values
=
[(
"
Dijkstra
"
,
1930
),
(
"
Euler
"
,
1707
),
(
"
Steiner
"
,
1796
)])
q_insert
=
p
erson
.
insert_values
(
in_columns
=
(
p
erson
.
c
[[
"
name
"
,
"
birth_year
"
]]),
values
=
[(
"
Dijkstra
"
,
1930
),
(
"
Euler
"
,
1707
),
(
"
Steiner
"
,
1796
)])
db
.
execute
(
q_insert
)
db
.
execute
(
q_insert
)
~~~
~~~
Now, our table admit three tuples:
Now, our table admit three tuples:
~~~
python
~~~
python
cursor
=
db
.
execute
(
P
erson
.
select
(
P
erson
.
c
[
1
:],
orderby
=
P
erson
.
c
.
name
))
cursor
=
db
.
execute
(
p
erson
.
select
(
p
erson
.
c
[
1
:],
orderby
=
p
erson
.
c
.
name
))
results
=
list
(
cursor
.
fetchall
())
results
=
list
(
cursor
.
fetchall
())
print
(
results
)
print
(
results
)
~~~
~~~
...
@@ -132,22 +132,22 @@ The values are safely embedded within `q_insert` (click me to see details).
...
@@ -132,22 +132,22 @@ The values are safely embedded within `q_insert` (click me to see details).
The query
`q_insert`
above actually embedded the values within its formatting as shown by its pretty printing
`q_insert.pretty_print()`
:
The query
`q_insert`
above actually embedded the values within its formatting as shown by its pretty printing
`q_insert.pretty_print()`
:
~~~
sql
~~~
sql
INSERT
INTO
P
erson
(
name
,
age
)
VALUES
(
?
,
1930
),
(
?
,
1707
),
(
?
,
1796
)
INSERT
INTO
p
erson
(
name
,
birth_year
)
VALUES
(
?
,
1930
),
(
?
,
1707
),
(
?
,
1796
)
-- ↖{0: 'Dijkstra', 1: 'Euler', 2: 'Steiner'}
-- ↖{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:
But it is still safe against injection as the string values will be passed as placeholders to an underlying prepared query:
~~~
python
~~~
python
q_inject
=
P
erson
.
insert_values
(
in_columns
=
P
erson
.
c
[
1
:],
values
=
[(
"
\"
;DROP TABLE
P
erson;
"
,
0000
)])
q_inject
=
p
erson
.
insert_values
(
in_columns
=
p
erson
.
c
[
1
:],
values
=
[(
"
\"
;DROP TABLE
p
erson;
"
,
0000
)])
db
.
execute
(
q_inject
)
db
.
execute
(
q_inject
)
cursor
=
db
.
execute
(
P
erson
.
select
(
P
erson
.
c
[
1
:],
where
=
P
erson
.
c
.
birth_year
.
eq
(
0
)))
cursor
=
db
.
execute
(
p
erson
.
select
(
p
erson
.
c
[
1
:],
where
=
p
erson
.
c
.
birth_year
.
eq
(
0
)))
results
=
list
(
cursor
.
fetchall
())
results
=
list
(
cursor
.
fetchall
())
print
(
results
)
print
(
results
)
~~~
~~~
gives:
gives:
~~~
python
~~~
python
[(
'"
;
DROP TABLE
P
erson;
"
'
,
0
)]
[(
'"
;DROP TABLE
p
erson;
'
,
0
)]
~~~
~~~
</details>
</details>
...
@@ -155,23 +155,23 @@ gives:
...
@@ -155,23 +155,23 @@ gives:
We can also define updates easily, _e.g._, with the following query:
We can also define updates easily, _e.g._, with the following query:
~~~
python
~~~
python
q_upd
=
P
erson
.
update
(
dict
(
id
=
uuid_gen
()),
where
=
P
erson
.
c
.
name
.
eq
(
"
Dijkstra
"
))
q_upd
=
p
erson
.
update
(
dict
(
id
=
uuid_gen
()),
where
=
p
erson
.
c
.
name
.
eq
(
"
Dijkstra
"
))
db
.
execute
(
q_upd
)
db
.
execute
(
q_upd
)
~~~
~~~
which pretty prints as:
which pretty prints as:
~~~
sql
~~~
sql
UPDATE
P
erson
SET
id
=
?
WHERE
P
erson
.
name
=
?
UPDATE
p
erson
SET
id
=
?
WHERE
p
erson
.
name
=
?
-- ↖{0: UUID('33525c22-f938-4256-b673-e595ff6df828'), 1: 'Dijkstra'}
-- ↖{0: UUID('33525c22-f938-4256-b673-e595ff6df828'), 1: 'Dijkstra'}
~~~
~~~
Of course, deletions are also possible, _e.g._:
Of course, deletions are also possible, _e.g._:
~~~
python
~~~
python
q_del
=
P
erson
.
delete
(
where
=
P
erson
.
c
.
id
.
isnull
())
q_del
=
p
erson
.
delete
(
where
=
p
erson
.
c
.
id
.
isnull
())
db
.
execute
(
q_del
)
db
.
execute
(
q_del
)
~~~
~~~
is formatted as:
is formatted as:
~~~
sql
~~~
sql
DELETE
FROM
P
erson
WHERE
P
erson
.
id
IS
NULL
DELETE
FROM
p
erson
WHERE
p
erson
.
id
IS
NULL
~~~
~~~
If we throw in more complicated tables,
If we throw in more complicated tables,
...
@@ -268,41 +268,40 @@ q_delete = tag.delete(where=tag.c.name.like("value_%"))
...
@@ -268,41 +268,40 @@ q_delete = tag.delete(where=tag.c.name.like("value_%"))
db
.
execute
(
q_delete
)
db
.
execute
(
q_delete
)
~~~
~~~
Finally, we can build a last table with references to connect tag with
P
erson:
Finally, we can build a last table with references to connect tag with
p
erson:
~~~
python
~~~
python
@table
@table
class
tag_person
:
class
tag_person
:
person_id
:
P
erson
.
c
.
id
person_id
:
p
erson
.
c
.
id
tag_id
:
tag
.
c
.
id
tag_id
:
tag
.
c
.
id
db
.
execute
(
tag_person
.
create
())
db
.
execute
(
tag_person
.
create
())
~~~
~~~
The query given by
`tag_person.create()`
is:
The query given by
`
str(
tag_person.create()
)
`
is:
~~~
sql
~~~
sql
CREATE
TABLE
tag_person
(
CREATE
TABLE
tag_person
(
person_id
UUID
REFERENCES
person
(
id
),
tag_id
INTEGER
REFERENCES
tag
(
id
))
person_id
TEXT
REFERENCES
Person
(
id
),
tag_id
INTEGER
REFERENCES
tag
(
id
)
)
~~~
~~~
Again, within SQLite, the
`UUID`
type will fallback to
`TEXT`
.
Remark that it automatically infers the types and add the constraints associated with
Remark that it automatically infers the types and add the constraints associated with
the table definitions.
the table definitions.
Let us label Dijkstra as a Mathematician:
Let us label Dijkstra as a Mathematician:
~~~
python
~~~
python
condition
=
P
erson
.
c
.
name
.
eq
(
"
Dijkstra
"
)
&
tag
.
c
.
name
.
eq
(
"
mathematician
"
)
condition
=
p
erson
.
c
.
name
.
eq
(
"
Dijkstra
"
)
&
tag
.
c
.
name
.
eq
(
"
mathematician
"
)
q_prod
=
P
erson
.
product
(
tag
).
select
(
columns
=
(
P
erson
.
c
.
id
,
tag
.
c
.
id
),
where
=
condition
)
q_prod
=
p
erson
.
product
(
tag
).
select
(
columns
=
(
p
erson
.
c
.
id
,
tag
.
c
.
id
),
where
=
condition
)
~~~
~~~
The query
`q_prod`
is of the following shape:
The query
`q_prod`
is of the following shape:
~~~
sql
~~~
sql
SELECT
P
erson
.
id
,
tag
.
id
SELECT
p
erson
.
id
,
tag
.
id
FROM
P
erson
,
tag
FROM
p
erson
,
tag
WHERE
P
erson
.
name
=
?
AND
tag
.
name
=
?
WHERE
p
erson
.
name
=
?
AND
tag
.
name
=
?
-- ↖{0: 'Dijkstra', 1: 'mathematician'}
-- ↖{0: 'Dijkstra', 1: 'mathematician'}
~~~
~~~
...
@@ -316,12 +315,12 @@ Let us check by getting the list of mathematicians using the following complex q
...
@@ -316,12 +315,12 @@ Let us check by getting the list of mathematicians using the following complex q
~~~
python
~~~
python
q_math
=
tag_person
\
q_math
=
tag_person
\
.
inner_join
(
tag
,
on
=
tag
.
c
.
id
.
eq
(
tag_person
.
c
.
tag_id
))
\
.
inner_join
(
tag
,
on
=
tag
.
c
.
id
.
eq
(
tag_person
.
c
.
tag_id
))
\
.
inner_join
(
P
erson
,
on
=
P
erson
.
c
.
id
.
eq
(
tag_person
.
c
.
person_id
))
\
.
inner_join
(
p
erson
,
on
=
p
erson
.
c
.
id
.
eq
(
tag_person
.
c
.
person_id
))
\
.
select
([
P
erson
.
c
.
name
],
where
=
tag
.
c
.
name
.
eq
(
"
mathematician
"
))
.
select
([
p
erson
.
c
.
name
],
where
=
tag
.
c
.
name
.
eq
(
"
mathematician
"
))
~~~
~~~
which is formatted as
which is formatted as
~~~
sql
~~~
sql
SELECT
P
erson
.
name
FROM
(
tag_person
INNER
JOIN
tag
ON
tag
.
tag_
id
=
tag_person
.
id
)
INNER
JOIN
P
erson
ON
P
erson
.
id
=
tag_person
.
person_id
WHERE
tag
.
name
=
?
SELECT
p
erson
.
name
FROM
(
tag_person
INNER
JOIN
tag
ON
tag
.
id
=
tag_person
.
tag_
id
)
INNER
JOIN
p
erson
ON
p
erson
.
id
=
tag_person
.
person_id
WHERE
tag
.
name
=
?
~~~
~~~
and whose execution
and whose execution
~~~
python
~~~
python
...
@@ -339,20 +338,20 @@ will return only `"Dijkstra"`
...
@@ -339,20 +338,20 @@ will return only `"Dijkstra"`
The previous queries work seamlessly on PostgreSQL by simply using the PostgreSQL connector:
The previous queries work seamlessly on PostgreSQL by simply using the PostgreSQL connector:
~~~
python
~~~
python
from
querybuilder.drivers.postgres
ql
.connector
import
Connector
from
querybuilder.drivers.postgres.connector
import
Connector
db
=
Connector
()
db
=
Connector
()
# Postgresql has default connection information
~~~
~~~
The only differences are
The only differences
with respect to using the SQLite driver
are
:
1.
We need to specify that
`
P
erson.id`
is the primary key of
`
P
erson`
1.
We need to specify that
`
p
erson.id`
is the primary key of
`
p
erson`
to allow us to use it as a foreign key in
`tag_person`
;
to allow us to use it as a foreign key in
`tag_person`
;
2.
We do not have warnings, since PostgreSQL has implementations
2.
We do not have warnings, since PostgreSQL has implementations
of type
`UUID`
, and of
`GENERATED ALWAYS AS IDENTITY`
.
of type
`UUID`
, and of
`GENERATED ALWAYS AS IDENTITY`
.
~~~
python
~~~
python
@table
@table
class
P
erson
:
class
p
erson
:
id
:
ColumnSpec
(
UUID
,
primary_key
=
True
)
id
:
ColumnSpec
(
UUID
,
primary_key
=
True
)
name
:
str
name
:
str
birth_year
:
int
birth_year
:
int
...
@@ -363,8 +362,8 @@ class tag:
...
@@ -363,8 +362,8 @@ class tag:
@table
@table
class
tag_person
:
class
tag_person
:
tag_id
:
tag
.
c
.
id
tag_id
:
tag
.
c
.
id
person_id
:
P
erson
.
c
.
id
person_id
:
p
erson
.
c
.
id
db
.
execute
(
P
erson
.
create
(
temporary
=
True
))
db
.
execute
(
p
erson
.
create
(
temporary
=
True
))
db
.
execute
(
tag
.
create
(
temporary
=
True
))
db
.
execute
(
tag
.
create
(
temporary
=
True
))
db
.
execute
(
tag_person
.
create
(
temporary
=
True
))
db
.
execute
(
tag_person
.
create
(
temporary
=
True
))
~~~
~~~
...
@@ -372,7 +371,7 @@ db.execute(tag_person.create(temporary=True))
...
@@ -372,7 +371,7 @@ db.execute(tag_person.create(temporary=True))
Since PostgreSQL has no non-persistent in-memory database,
Since PostgreSQL has no non-persistent in-memory database,
we indicated
`temporary=True`
when generating the creation query of each table,
we indicated
`temporary=True`
when generating the creation query of each table,
so that
`CREATE TEMPORARY TABLE`
queries are produced.
so that
`CREATE TEMPORARY TABLE`
queries are produced.
For instance,
`str(
P
erson.create(temporary=True))`
gives the query:
For instance,
`str(
p
erson.create(temporary=True))`
gives the query:
~~~
sql
~~~
sql
CREATE
TEMPORARY
TABLE
P
erson
(
id
UUID
PRIMARY
KEY
,
name
TEXT
,
birth_year
INTEGER
)
CREATE
TEMPORARY
TABLE
p
erson
(
id
UUID
PRIMARY
KEY
,
name
TEXT
,
birth_year
INTEGER
)
~~~
~~~
This diff is collapsed.
Click to expand it.
readme_doctests.py
0 → 100644
+
107
−
0
View file @
845d9120
"""
>>>
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
>>>
@table
...
class
person
:
...
id
:
UUID
...
name
:
str
...
birth_year
:
int
>>>
q
=
person
.
select
([
person
.
c
.
birth_year
,
person
.
c
.
name
])
# person.c is a shorthand for person.columns
>>>
str
(
q
)
'
SELECT person.birth_year, person.name FROM person
'
>>>
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
>>>
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)
'
>>>
_
=
db
.
execute
(
person
.
create
())
>>>
q_insert
=
person
.
insert_values
(
in_columns
=
(
person
.
c
[[
"
name
"
,
"
birth_year
"
]]),
values
=
[(
"
Dijkstra
"
,
1930
),
(
"
Euler
"
,
1707
),
(
"
Steiner
"
,
1796
)])
>>>
q_insert
.
pretty_print
()
INSERT
INTO
person
(
name
,
birth_year
)
VALUES
(
?
,
1930
),
(
?
,
1707
),
(
?
,
1796
)
--
↖
{
0
:
'
Dijkstra
'
,
1
:
'
Euler
'
,
2
:
'
Steiner
'
}
>>>
_
=
db
.
execute
(
q_insert
)
>>>
cursor
=
db
.
execute
(
person
.
select
(
person
.
c
[
1
:],
orderby
=
person
.
c
.
name
))
>>>
list
(
cursor
.
fetchall
())
[(
'
Dijkstra
'
,
1930
),
(
'
Euler
'
,
1707
),
(
'
Steiner
'
,
1796
)]
>>>
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
)))
>>>
list
(
cursor
.
fetchall
())
[(
'"
;DROP TABLE person;
'
,
0
)]
>>>
q_upd
=
person
.
update
(
dict
(
id
=
uuid_gen
()),
where
=
person
.
c
.
name
.
eq
(
"
Dijkstra
"
))
>>>
q_upd
.
pretty_print
()
# doctest: +ELLIPSIS
UPDATE
person
SET
id
=
?
WHERE
person
.
name
=
?
--
↖
{
0
:
UUID
(
'
...
'
),
1
:
'
Dijkstra
'
}
>>>
_
=
db
.
execute
(
q_upd
)
>>>
q_del
=
person
.
delete
(
where
=
person
.
c
.
id
.
isnull
())
>>>
str
(
q_del
)
'
DELETE FROM person WHERE person.id IS NULL
'
>>>
_
=
db
.
execute
(
q_del
)
>>>
from
querybuilder.schemas.helper
import
table
,
ColumnSpec
>>>
@table
...
class
tag
:
...
id
:
ColumnSpec
(
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)
'
>>>
db
.
stringify
(
tag
.
create
())
'
CREATE TABLE tag (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)
'
>>>
_
=
db
.
execute
(
tag
.
create
())
>>>
q_tag
=
tag
.
insert_values
(
in_columns
=
(
tag
.
c
.
name
,),
values
=
[(
"
mathematician
"
,)])
>>>
q_tag
.
pretty_print
()
INSERT
INTO
tag
(
name
)
VALUES
(
?
)
--
↖
{
0
:
'
mathematician
'
}
>>>
_
=
db
.
execute
(
q_tag
)
>>>
q_tag_bulk
=
tag
.
insert_many
(
in_columns
=
(
tag
.
c
.
name
,))
>>>
q_tag_bulk
.
pretty_print
()
INSERT
INTO
tag
(
name
)
VALUES
(:
name
)
--
↖
{
name
:
ø
}
>>>
_
=
db
.
executemany
(
q_tag_bulk
,
[
dict
(
name
=
f
"
value_
{
i
}
"
)
for
i
in
range
(
1000
)])
>>>
q_delete
=
tag
.
delete
(
where
=
tag
.
c
.
name
.
like
(
"
value_%
"
))
>>>
_
=
db
.
execute
(
q_delete
)
>>>
@table
...
class
tag_person
:
...
person_id
:
person
.
c
.
id
...
tag_id
:
tag
.
c
.
id
>>>
str
(
tag_person
.
create
())
'
CREATE TABLE tag_person (person_id UUID REFERENCES person(id), tag_id INTEGER REFERENCES tag(id))
'
>>>
db
.
stringify
(
tag_person
.
create
())
'
CREATE TABLE tag_person (person_id TEXT REFERENCES person(id), tag_id INTEGER REFERENCES tag(id))
'
>>>
_
=
db
.
execute
(
tag_person
.
create
())
>>>
condition
=
person
.
c
.
name
.
eq
(
"
Dijkstra
"
)
&
tag
.
c
.
name
.
eq
(
"
mathematician
"
)
>>>
str
(
condition
)
'
person.name = ? AND tag.name = ?
'
>>>
q_prod
=
person
.
product
(
tag
).
select
(
columns
=
(
person
.
c
.
id
,
tag
.
c
.
id
),
where
=
condition
)
>>>
q_prod
.
pretty_print
()
SELECT
person
.
id
,
tag
.
id
FROM
person
,
tag
WHERE
person
.
name
=
?
AND
tag
.
name
=
?
--
↖
{
0
:
'
Dijkstra
'
,
1
:
'
mathematician
'
}
>>>
_
=
db
.
execute
(
tag_person
.
insert
(
query
=
q_prod
))
>>>
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
"
))
>>>
str
(
q_math
)
'
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 = ?
'
>>>
cursor
=
db
.
execute
(
q_math
)
>>>
list
(
cursor
.
fetchall
())
[(
'
Dijkstra
'
,)]
>>>
from
querybuilder.drivers.postgres.connector
import
Connector
>>>
db
=
Connector
()
>>>
@table
...
class
person
:
...
id
:
ColumnSpec
(
UUID
,
primary_key
=
True
)
...
name
:
str
...
birth_year
:
int
>>>
@table
...
class
tag
:
...
id
:
ColumnSpec
(
int
,
primary_key
=
True
,
generated_as_identity
=
True
)
...
name
:
str
>>>
@table
...
class
tag_person
:
...
tag_id
:
tag
.
c
.
id
...
person_id
:
person
.
c
.
id
>>>
_
=
db
.
execute
(
person
.
create
(
temporary
=
True
))
>>>
_
=
db
.
execute
(
tag
.
create
(
temporary
=
True
))
>>>
_
=
db
.
execute
(
tag_person
.
create
(
temporary
=
True
))
>>>
str
(
person
.
create
(
temporary
=
True
))
'
CREATE TEMPORARY TABLE person (id UUID PRIMARY KEY, name TEXT, birth_year INTEGER)
'
"""
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment