Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
03ff51a
add mysql engine, initial columns types changes, changes to alter method
sinisaos Nov 15, 2025
9418c53
fix create and drop indexes
sinisaos Nov 15, 2025
f0bdac4
continue with changes when trying to pass unittest
sinisaos Nov 16, 2025
cf1bdb3
fix some serial pk m2m columns and continue trying to pass unittest
sinisaos Nov 16, 2025
e5e3c1f
some clean up
sinisaos Nov 16, 2025
2b21878
more changes
sinisaos Nov 18, 2025
80175cd
timestamp, interval and m2m changes
sinisaos Nov 19, 2025
15dedaa
additional changes for unittest passing
sinisaos Nov 20, 2025
7e56178
update_with_joins - same goes for delete_with_joins
sinisaos Nov 20, 2025
0739bb6
enable some refresh tests
sinisaos Nov 20, 2025
40535fa
resolve merge conflicts
sinisaos Nov 20, 2025
2151851
add and change more tests
sinisaos Nov 21, 2025
c496a9c
add wrap_in_transaction=False to some migrations test
sinisaos Nov 21, 2025
e622c78
some globals for safer MySQL behavior
sinisaos Nov 23, 2025
52d69ba
fix small typos
sinisaos Nov 25, 2025
4fd5859
on_conflict work with MySQL (with MySQL limitation)
sinisaos Nov 27, 2025
f77f417
more tests fixed
sinisaos Nov 27, 2025
ef3ea83
adds documentation
sinisaos Dec 1, 2025
bfb3d94
use aiomysql instead of asyncmy because it is better maintained
sinisaos Dec 1, 2025
5d91cc9
fix docs and some tests
sinisaos Dec 2, 2025
b71a4e2
fix integration test for litestar and try to pass action for MySQL
sinisaos Dec 2, 2025
b89823b
another try to pass action for MySQL
sinisaos Dec 2, 2025
ccc4aec
another try
sinisaos Dec 2, 2025
f30b70b
last try
sinisaos Dec 2, 2025
99c4f52
simplified the action using root user and try again
sinisaos Dec 2, 2025
4f58382
try again with actions for mysql
sinisaos Dec 2, 2025
536a654
list hosts
sinisaos Dec 2, 2025
a2dc8f3
final try
sinisaos Dec 2, 2025
6e951db
revert github actions
sinisaos Dec 2, 2025
bdfc623
add Playground for MySQL
sinisaos Dec 2, 2025
7a23387
adds basic Array functions using JSON
sinisaos Dec 2, 2025
5c297b4
adds JSON arrow and from_path functions for MySQL
sinisaos Dec 3, 2025
0f1237d
small clean up
sinisaos Dec 3, 2025
fbd9fa5
adds more tests
sinisaos Dec 3, 2025
765c08c
fix timestamptz and more tests
sinisaos Dec 3, 2025
fe97cb8
try to fix mysql workflow
sinisaos Dec 3, 2025
fab6407
Merge branch 'piccolo-orm:master' into mysql_engine
sinisaos Dec 3, 2025
22404f0
another try with MySQL actions
sinisaos Dec 3, 2025
f75c3dc
another try
sinisaos Dec 3, 2025
8aa1174
MySQL is working now, but needs to be match versions. If 8.4 doesn't …
sinisaos Dec 3, 2025
d0a4c8e
add password to connection
sinisaos Dec 4, 2025
6bc32b6
correct env vars names
sinisaos Dec 4, 2025
993c225
port as int not str
sinisaos Dec 4, 2025
acae191
localhost -> 127.1.0.0
sinisaos Dec 4, 2025
d15c14e
fix typo
sinisaos Dec 4, 2025
cb942da
fix linters error by moving imports inside method
sinisaos Dec 4, 2025
2a418a1
uuid and boolean converter
sinisaos Dec 4, 2025
fd63947
adds PyMySQL as dependency and try to pass CI
sinisaos Dec 5, 2025
208be6c
adds PyMySQL as main dependency in requirements.txt
sinisaos Dec 5, 2025
acdeb62
adds timestamp and timestamptz converter
sinisaos Dec 5, 2025
c5e6d0b
fix subtle bug with sql generation for foreign keys
sinisaos Dec 5, 2025
7a0090e
Merge branch 'master' into mysql_engine
sinisaos Dec 6, 2025
3fdc9ab
update connection pool docs
sinisaos Dec 6, 2025
aa206c8
start with auto migrations
sinisaos Dec 6, 2025
8de3124
more tests
sinisaos Dec 7, 2025
3a14cdc
handle default values for text,json and blob columns
sinisaos Dec 9, 2025
f1dd6bf
remove wrap_in_transaction from auto migrations tests
sinisaos Dec 9, 2025
baa1f97
fix defaults and add set_null
sinisaos Dec 9, 2025
eefa670
reduce Postgres coverage to 80 due to a lot of MySQL related code
sinisaos Dec 9, 2025
fedf946
update docs
sinisaos Dec 9, 2025
0965d14
more tests
sinisaos Dec 10, 2025
4e84b28
Mysql -> MySQL change
sinisaos Dec 11, 2025
d400eba
remove duplicate code
sinisaos Dec 12, 2025
61fc755
lazy import pymysql
sinisaos Dec 16, 2025
f7ffe84
Merge branch 'piccolo-orm:master' into mysql_engine
sinisaos Dec 16, 2025
6ce311b
add @dantownsend suggestions
sinisaos Dec 16, 2025
4058e49
revert changes in CI
sinisaos Dec 16, 2025
a6b9277
change uuid default value
sinisaos Dec 17, 2025
986a679
Merge branch 'master' into mysql_engine
sinisaos Jan 14, 2026
6d64452
fix linters and adjust conflict target
sinisaos Jan 14, 2026
c4dffe8
fix linter error
sinisaos Jan 14, 2026
91bfdb2
Merge branch 'master' into mysql_engine
sinisaos Feb 7, 2026
1dc89bd
Merge branch 'master' into mysql_engine
sinisaos Feb 11, 2026
3bb26d3
fix linters and merge conflicts
sinisaos Feb 11, 2026
1e9a627
Merge branch 'master' into mysql_engine
sinisaos Mar 11, 2026
711b468
added mysql property to UUID7 class
sinisaos Mar 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,77 @@ jobs:
- name: Upload coverage
uses: codecov/codecov-action@v1
if: matrix.python-version == '3.13'

mysql:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

services:
mysql:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: piccolo
MYSQL_ROOT_HOST: '%'
options: >-
--health-cmd="mysqladmin ping -uroot -prootpassword"
--health-interval=5s
--health-timeout=2s
--health-retries=10
ports:
- 3306:3306

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements/requirements.txt
pip install -r requirements/test-requirements.txt
pip install -r requirements/extras/mysql.txt

- name: Install MySQL Client
run: sudo apt-get update && sudo apt-get install -y mysql-client

- name: Wait for MySQL
run: |
set -e
for i in {1..60}; do
if mysqladmin ping -h127.0.0.1 -P3306 -uroot -prootpassword > /dev/null 2>&1; then
echo "MySQL is up"
break
fi
echo "Waiting for MySQL… ($i/60)"
sleep 2
if [ "$i" -eq 60 ]; then
echo "MySQL did not become ready in time!" >&2
mysqladmin ping -h127.0.0.1 -P3306 -uroot -prootpassword || true
exit 1
fi
done

- name: Setup MySQL (create database)
run: |
mysql -h127.0.0.1 -P3306 -uroot -prootpassword -e "CREATE DATABASE IF NOT EXISTS piccolo;"

- name: Test with pytest, MySQL
run: ./scripts/test-mysql.sh
env:
MY_HOST: 127.0.0.1
MY_PORT: 3306
MY_USER: root
MY_PASSWORD: rootpassword
MY_DATABASE: piccolo

- name: Upload coverage
uses: codecov/codecov-action@v1
if: matrix.python-version == '3.13'
2 changes: 1 addition & 1 deletion docs/src/piccolo/engines/connection_pool.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Connection Pool
===============

.. hint:: Connection pools can be used with Postgres and CockroachDB.
.. hint:: Connection pools can be used with Postgres, CockroachDB and MySQL.

Setup
~~~~~
Expand Down
1 change: 1 addition & 0 deletions docs/src/piccolo/engines/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,5 @@ Engine types
./sqlite_engine
./postgres_engine
./cockroach_engine
./mysql_engine
./connection_pool
44 changes: 44 additions & 0 deletions docs/src/piccolo/engines/mysql_engine.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
MySQLEngine
===========

Configuration
-------------

.. code-block:: python

# piccolo_conf.py
from piccolo.engine.mysql import MySQLEngine


DB = MySQLEngine(
config={
"host": "localhost",
"port": 3306,
"user": "root",
"password": "",
"db": "piccolo",
}
)

config
~~~~~~

The config dictionary is passed directly to the underlying database adapter,
aiomysql. See the `aiomysql docs <https://aiomysql.readthedocs.io/en/stable/connection.html#connection>`_
to learn more.

-------------------------------------------------------------------------------

Connection Pool
---------------

See :ref:`ConnectionPool`.

-------------------------------------------------------------------------------

Source
------

.. currentmodule:: piccolo.engine.mysql

.. autoclass:: MySQLEngine
6 changes: 6 additions & 0 deletions docs/src/piccolo/getting_started/database_support.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ together in production. The main missing feature is support for
:ref:`automatic database migrations <AutoMigrations>` due to SQLite's limited
support for ``ALTER TABLE`` ``DDL`` statements.

`MySQL <https://www.mysql.com/>`_ is also supported. There may be some features
not supported, but it's OK to use. :ref:`Automatic database migrations <AutoMigrations>`
is supported but we must be careful because MySQL ``DDL`` statements
`are not transactional <https://dev.mysql.com/doc/refman/8.4/en/atomic-ddl.html>`_
and MySQL will commit the changes in transaction.

What about other databases?
---------------------------

Expand Down
1 change: 1 addition & 0 deletions docs/src/piccolo/getting_started/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ Getting Started
./setup_postgres
./setup_cockroach
./setup_sqlite
./setup_mysql
./example_schema
./sync_and_async
28 changes: 28 additions & 0 deletions docs/src/piccolo/getting_started/setup_mysql.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.. _setting_up_mysql:

###########
Setup MySQL
###########

Installation
************

Follow the `instructions for your OS <https://dev.mysql.com/doc/refman/8.4/en/installing.html>`_.


Creating a database
*******************

Using ``mysql``:

.. code-block:: bash

mysql -u root -p

Enter your password and create the database:

.. code-block:: bash

CREATE DATABASE "my_database_name";

Alternatively, use a GUI tool.
7 changes: 4 additions & 3 deletions docs/src/piccolo/migrations/create.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,9 +256,10 @@ Creating an auto migration:
aren't supported by auto migrations, or to modify the data held in tables, as
opposed to changing the tables themselves.

.. warning:: Auto migrations aren't supported in SQLite, because of SQLite's
extremely limited support for SQL Alter statements. This might change in
the future.
.. warning:: Auto migrations for SQLite and MySQL are supported, with limitations.
SQLite has extremely limited support for SQL ALTER statements and MySQL DDL triggers
an implicit commit in transaction and we cannot roll back a DDL using ROLLBACK
(non-transactional DDL). This might change in the future.

Troubleshooting
~~~~~~~~~~~~~~~
Expand Down
35 changes: 35 additions & 0 deletions docs/src/piccolo/playground/advanced.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,41 @@ When you have the database setup, you can connect to it as follows:

piccolo playground run --engine=cockroach


MySQL
-----

Install MySQL
~~~~~~~~~~~~~

See :ref:`the docs on settings up MySQL <setting_up_mysql>`.

Create database
~~~~~~~~~~~~~~~

By default the playground expects a local database to exist with the following
credentials:

.. code-block:: bash

user: "root"
password: ""
host: "localhost"
db: "piccolo_playground"
port: 3306

If you want to use different credentials, you can pass them into the playground
command (use ``piccolo playground run --help`` for details).

Connecting
~~~~~~~~~~

When you have the database setup, you can connect to it as follows:

.. code-block:: bash

piccolo playground run --engine=mysql

iPython
-------

Expand Down
11 changes: 9 additions & 2 deletions docs/src/piccolo/query_clauses/on_conflict.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ You can also specify the name of a constraint using a string:
... target='some_constraint'
... )

.. warning:: Not supported for MySQL.

``values``
----------

Expand Down Expand Up @@ -194,11 +196,15 @@ update should be made:
... where=Band.popularity < 1000
... )

.. warning:: Not supported for MySQL. A workaround is possible by using an
``IF`` or ``CASE`` condition in the ``UPDATE`` clause or by first
performing a separate ``UPDATE``, but this is not currently supported in Piccolo.

Multiple ``on_conflict`` clauses
--------------------------------

SQLite allows you to specify multiple ``ON CONFLICT`` clauses, but Postgres and
Cockroach don't.
SQLite allows you to specify multiple ``ON CONFLICT`` clauses, but Postgres,
Cockroach and MySQL don't.

.. code-block:: python

Expand All @@ -218,6 +224,7 @@ Learn more
* `Postgres docs <https://www.postgresql.org/docs/current/sql-insert.html#SQL-ON-CONFLICT>`_
* `Cockroach docs <https://www.cockroachlabs.com/docs/v2.0/insert.html#on-conflict-clause>`_
* `SQLite docs <https://www.sqlite.org/lang_UPSERT.html>`_
* `MySQL docs <https://dev.mysql.com/doc/refman/8.4/en/insert.html>`_

Source
------
Expand Down
4 changes: 3 additions & 1 deletion docs/src/piccolo/query_clauses/returning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ how many rows were affected or processed by the operation.
.. warning:: This works for all versions of Postgres, but only
`SQLite 3.35.0 <https://www.sqlite.org/lang_returning.html>`_ and above
support the returning clause. See the :ref:`docs <check_sqlite_version>` on
how to check your SQLite version.
how to check your SQLite version.

Not supported for MySQL because there is no ``RETURNING`` clause in MySQL.
29 changes: 24 additions & 5 deletions piccolo/apps/migrations/auto/migration_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@
)
from piccolo.apps.migrations.auto.serialisation import deserialise_params
from piccolo.columns import Column, column_types
from piccolo.columns.column_types import ForeignKey, Serial
from piccolo.columns.column_types import JSON, Blob, ForeignKey, Serial, Text
from piccolo.engine import engine_finder
from piccolo.engine.cockroach import CockroachTransaction
from piccolo.query import Query
from piccolo.query.base import DDL
from piccolo.query.constraints import get_fk_constraint_name
from piccolo.query.constraints import (
get_fk_constraint_name,
get_fk_constraint_name_mysql,
)
from piccolo.schema import SchemaDDLBase
from piccolo.table import Table, create_table_class, sort_table_classes
from piccolo.utils.warnings import colored_warning
Expand Down Expand Up @@ -543,10 +546,16 @@ async def _run_alter_columns(self, backwards: bool = False):

assert isinstance(fk_column, ForeignKey)

if existing_table._meta.db.engine_type == "mysql":
constraint_name = await get_fk_constraint_name_mysql(
column=fk_column
)
else:
constraint_name = await get_fk_constraint_name(
column=fk_column
)

# First drop the existing foreign key constraint
constraint_name = await get_fk_constraint_name(
column=fk_column
)
if constraint_name:
await self._run_query(
_Table.alter().drop_constraint(
Expand Down Expand Up @@ -642,6 +651,16 @@ async def _run_alter_columns(self, backwards: bool = False):
column._meta._name = alter_column.column_name
column._meta.db_column_name = alter_column.db_column_name

if _Table._meta.db.engine_type == "mysql" and (
column_class == Text
or column_class == JSON
or column_class == Blob
):
raise ValueError(
"MySQL does not support default value in alter "
"statement for TEXT, JSON and BLOB columns"
)

if default is None:
await self._run_query(
_Table.alter().drop_default(column=column)
Expand Down
17 changes: 16 additions & 1 deletion piccolo/apps/playground/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
Varchar,
)
from piccolo.columns.readable import Readable
from piccolo.engine import CockroachEngine, PostgresEngine, SQLiteEngine
from piccolo.engine import (
CockroachEngine,
MySQLEngine,
PostgresEngine,
SQLiteEngine,
)
from piccolo.engine.base import Engine
from piccolo.table import Table
from piccolo.utils.warnings import colored_string
Expand Down Expand Up @@ -424,6 +429,16 @@ def run(
"port": port or 26257,
}
)
elif engine.upper() == "MYSQL":
db = MySQLEngine(
{
"host": host,
"db": database,
"user": user or "root",
"password": password or "",
"port": port or 3306,
}
)
else:
db = SQLiteEngine()
for _table in TABLES:
Expand Down
Loading