sqlite-utils 4.0rc1 がマイグレーションとネストトランザクションを追加
本文の状態
日本語全文を表示中
詳細モードで約6分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Simon Willison Blog
Simon Willison氏が開発するPythonライブラリ・CLIツール「sqlite-utils」のバージョン4.0rc1が、データベースマイグレーション機能とネストされたトランザクション機能を新たに追加してリリースされました。
Continue in AI NEW LAB
このニュースを、実務の判断につなげる
AI NEW LABで、試したことや先に確認したい条件を共有できます。まずはログインなしで読めます。
AI NEW LABで論点を見るSource Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
sqlite-utils は、SQLite データベースを扱うための Python ライブラリと CLI ツールを組み合わせたものです。Python のデフォルトの sqlite3 パッケージ 上に、高度な操作セットを提供しており、複雑なテーブル変換 のサポートや、JSON データからの自動テーブル作成、その他多数の機能を備えています。
私は sqlite-utils 4.0rc1 をリリースしました。これは sqlite-utils v4 の最初のリリース候補版です。メジャーバージョンのアップグレードには、いくつか(小規模な)後方互換性を損なう変更が含まれているため、安定版リリースを確定する前に、多くの人々にこのバージョンを試してもらいたいと考えています。
新機能:マイグレーション
今回の RC では、以前の 4.0 アルファ版と比較して、2 つの重要な新機能が追加されました。
1 つ目はデータベースマイグレーションのサポートです。これは完全に新しい実装ではなく、数年前に私がリリースした sqlite-migrate パッケージをわずかに修正して移植したものです。このパッケージは時間の経過とともにその価値を実証してきたため、現在は sqlite-utils に直接バンドルする準備が整いました。
migrations.py ファイル内のマイグレーションセットの例は以下の通りです:
from sqlite_utils import Database, Migrations
migrations = Migrations("creatures")
@migrations()
def create_table(db):
db["creatures"].create(
{"id": int, "name": str, "species": str},
pk="id",
)
@migrations()
def add_weight(db):
db["creatures"].add_column("weight", float)
これは、creatures テーブルを作成する移行と、そのテーブルに列を追加する移行という 2 つの移行セットを定義するものです。
その後、これらの移行は Python を使用して実行できます:
db = Database("creatures.db")
migrations.apply(db)
または、コマンドラインの migrate コマンドを使用して実行することもできます:
sqlite-utils migrate creatures.db migrations.py
このシステムは意図的に小さく設計されており、ロールバック(逆移行)機能は提供していません。そのため、発生したミスタイクは、それを無効化するための新しい移行をデプロイすることで修正する必要があります。
その前身となる機能は、LLM やその他のさまざまなプロジェクトで数年間使用されており、設計が安定しており良好に動作していることに自信を持っています。
新しい移行機能の詳細は こちら でドキュメント化されています。
新機能:db.atomic() トランザクション
この機能は移行機能ほど頻繁には使用されないため、テスターからのより多くの注目を集める必要があります。
以前は、sqlite_utils は主にユーザーにトランザクション管理を任せており、sqlite3 のメカニズムを直接再利用する with db.conn: 構文を通じて行われていました。
SQLite はセーブポイントの形式でネストされたトランザクションをサポートしているため、それらをできるだけ使いやすくする抽象化機能が必要でした。
「アトミック」という用語は Django や Peewee から借用しました。新しい API の外観は以下の通りです:
with db.atomic():
db.table("dogs").insert({"id": 1, "name": "Cleo"}, pk="id")
try:
with db.atomic():
db.table("dogs").insert({"id": 2, "name": "Pancakes"})
raise ValueError("skip this one")
except ValueError:
pass
db.table("dogs").insert({"id": 3, "name": "Marnie"})
詳細は ドキュメント をご覧ください。
後方互換性を破る変更点
v4 における後方互換性を破る変更点は、アルファ版のリリースノートで説明されています。4.0a0 を参照してください。
- Upsert 操作は、SQLite バージョン 3.23.1 より後のすべてのバージョンにおいて、SQLite の
INSERT ... ON CONFLICT SET構文を使用するようになりました。これは、以前のINSERT OR IGNOREに続くUPDATEという動作に依存していたアプリケーションにとっては非常にわずかな破壊的変更です。(#652)
- Python ライブラリのユーザーは、Database() コンストラクタに use_old_upsert=True を渡すことで、以前の実装をオプトインできます。詳細は「INSERT OR IGNORE を使用した代替の Upsert」をご覧ください。
- Python 3.8 のサポートを終了し、Python 3.13 のサポートを追加しました。(#646)
- sqlite-utils tui は now、sqlite-utils-tui プラグインによって提供されるようになりました。(#648)
- テストスイートは、新しい
INSERT ... ON CONFLICT SET構文が追加される前の最後のバージョンである SQLite 3.23.1(2018-04-10 版)でも実行されるようになりました。(#654)
そして 4.0a1 では:
- ブレイキングチェンジ:db.table(table_name) メソッドは現在、テーブルのみに対して動作します。SQL ビューにアクセスするには代わりに db.view(view_name) を使用してください。(#657)
- table.insert_all() および table.upsert_all() メソッドは、辞書の代わりにリストまたはタプルのイテレータを受け付けるようになりました。最初の項目には列名を格納したリスト/タプルを指定する必要があります。詳細については「リストまたはタプルのイテレータからのデータ挿入」をご覧ください。(#672)
- ブレイキングチェンジ:デフォルトの浮動小数点型カラムが、浮動小数点値に対する正しい SQLite 型である REAL に変更されました(以前は FLOAT)。これはデータの挿入時に自動検出されるカラムに影響を及ぼします。(#645)
- パッケージングに setup.py の代わりに pyproject.toml を使用するように変更されました。(#675)
- Python API におけるテーブルは、作成された際に保持していた主キーやその他のスキーマ詳細をより確実に記憶するようになりました。(#655)
- ブレイキングチェンジ:table.convert() および sqlite-utils convert メカニズムは、False と評価される値をスキップしなくなりました。以前は --skip-false オプションが必要でしたが、これは削除されました。(#542)
- ブレイキングチェンジ:このライブラリによって作成されたテーブルは、スキーマにおいてテーブル名と列名を「二重引用符」で囲むようになりました(以前は [角括弧] を使用していました)。(#677)
- --functions CLI 引数は、Python コードの文字列を受け付けるだけでなく、Python ファイルへのパスも受け付けられるようになりました。また、この引数を複数回指定することも可能になりました。(#659)
- ブレイキングチェンジ:CSV または TSV データをインポートする際の insert および upsert CLI コマンドにおいて、型検出がデフォルト動作となりました(以前は --detect-types フラグを渡さない限りすべての列が TEXT として扱われていました)。古い動作に戻すには新しい --no-detect-types フラグを使用してください。SQLITE_UTILS_DETECT_TYPES 環境変数は削除されました。(#679)
実際に試してみましょう
新しい RC バージンは以下のようにインストールできます:
pip install sqlite-utils==4.0rc1
または、uvx を使って CLI バージンを直接試すことも可能です:
uvx --with sqlite-utils==4.0rc1 sqlite-utils --help
sqlite-utils Discord チャンネルで私たちとチャットしたり、GitHub Issues でバグを報告してください。
Tags: migrations, projects, sqlite, sqlite-utils, annotated-release-notes
原文を表示
sqlite-utils is my combined Python library and CLI tool for working with SQLite databases. It provides an extensive set of higher-level operations on top of Python's default sqlite3 package, including support for complex table transformations, automatic table creation from JSON data and a whole lot more.
I released sqlite-utils 4.0rc1, the first release candidate for sqlite-utils v4. The major version bump indicates some (minor) backwards incompatible changes, so I'm interested in having people try this out before I commit to a stable release.
New feature: migrations
There are two significant new features in this RC compared to the previous 4.0 alphas.
The first is support for database migrations. This isn't a completely new implementation - it's a slightly modified port of the sqlite-migrate package I released a few years ago. I think that package has proved itself over time, so I'm now ready to bundle it with sqlite-utils directly.
Here's what a set of migrations in a migrations.py file looks like:
from sqlite_utils import Database, Migrations
migrations = Migrations("creatures")
@migrations()
def create_table(db):
db["creatures"].create(
{"id": int, "name": str, "species": str},
pk="id",
)
@migrations()
def add_weight(db):
db["creatures"].add_column("weight", float)This defines a set of two migrations, one creating the creatures table and another adding a column to it.
You can then run those migrations either using Python:
db = Database("creatures.db")
migrations.apply(db)Or with the command-line migrate command:
sqlite-utils migrate creatures.db migrations.pyThe system is deliberately small: it doesn't provide reverse migrations, so any mistakes you make should be fixed by deploying a fresh migration to undo them.
Its predecessor has been used by LLM and various other projects for several years, so I'm confident that the design is stable and works well.
The new migrations feature is documented here.
New feature: db.atomic() transactions
This feature is a lot less exercised than migrations, so it deserves more attention from testers.
Previously, sqlite-utils mostly left transaction management up to its users, via a with db.conn: construct that reused the sqlite3 mechanism directly.
SQLite supports nested transactions in the form of savepoints, so I wanted an abstraction that could make those as easy to use as possible.
I borrowed the terminology "atomic" from Django and Peewee. Here's what the new API looks like:
with db.atomic():
db.table("dogs").insert({"id": 1, "name": "Cleo"}, pk="id")
try:
with db.atomic():
db.table("dogs").insert({"id": 2, "name": "Pancakes"})
raise ValueError("skip this one")
except ValueError:
pass
db.table("dogs").insert({"id": 3, "name": "Marnie"})More details in the documentation.
Backwards incompatible changes
The backwards incompatible changes in v4 were described in the alpha release notes. For 4.0a0:
Upsert operations now use SQLite's INSERT ... ON CONFLICT SET syntax on all SQLite versions later than 3.23.1. This is a very slight breaking change for apps that depend on the previous INSERT OR IGNORE followed by UPDATE behavior. (#652)
Python library users can opt-in to the previous implementation by passing use_old_upsert=True to the Database() constructor, see Alternative upserts using INSERT OR IGNORE.
Dropped support for Python 3.8, added support for Python 3.13. (#646)
sqlite-utils tui is now provided by the sqlite-utils-tui plugin. (#648)
Test suite now also runs against SQLite 3.23.1, the last version (from 2018-04-10) before the new INSERT ... ON CONFLICT SET syntax was added. (#654)
And for 4.0a1:
Breaking change: The db.table(table_name) method now only works with tables. To access a SQL view use db.view(view_name) instead. (#657)
The table.insert_all() and table.upsert_all() methods can now accept an iterator of lists or tuples as an alternative to dictionaries. The first item should be a list/tuple of column names. See Inserting data from a list or tuple iterator for details. (#672)
Breaking change: The default floating point column type has been changed from FLOAT to REAL, which is the correct SQLite type for floating point values. This affects auto-detected columns when inserting data. (#645)
Now uses pyproject.toml in place of setup.py for packaging. (#675)
Tables in the Python API now do a much better job of remembering the primary key and other schema details from when they were first created. (#655)
Breaking change: The table.convert() and sqlite-utils convert mechanisms no longer skip values that evaluate to False. Previously the --skip-false option was needed, this has been removed. (#542)
Breaking change: Tables created by this library now wrap table and column names in "double-quotes" in the schema. Previously they would use [square-braces]. (#677)
The --functions CLI argument now accepts a path to a Python file in addition to accepting a string full of Python code. It can also now be specified multiple times. (#659)
Breaking change: Type detection is now the default behavior for the insert and upsert CLI commands when importing CSV or TSV data. Previously all columns were treated as TEXT unless the --detect-types flag was passed. Use the new --no-detect-types flag to restore the old behavior. The SQLITE_UTILS_DETECT_TYPES environment variable has been removed. (#679)
Try it out
You can install the new RC like this:
pip install sqlite-utils==4.0rc1Or try the CLI version directly with uvx like this:
uvx --with sqlite-utils==4.0rc1 sqlite-utils --helpCome chat with us about it in the sqlite-utils Discord channel, or file any bugs in GitHub Issues.
Tags: migrations, projects, sqlite, sqlite-utils, annotated-release-notes
関連記事
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み