背景
CloudSpannerではENUMを使うことができるので使い方を調べてみました〜
ENUM作り方・使い方
CloudSpannerは、基本的にgRPCで構成されているので対応する型を作って登録することができます。
そして、その型をCloudSpanner上でENUMとして使うことができます。下記が手順です。
- protoファイル定義
- protocコマンド実行
- pbファイル生成
- DDLファイル作成
- gcloudコマンド実行
- 引数
- DDLファイル or DDL
- pbファイル
- 引数
- SQL実行時にENUMと紐づける
protoファイル定義
product.proto
syntax = "proto3";
package product;
enum ProductType {
HOGE = 0;
HUGU = 1;
}
protocコマンド実行
protoc --descriptor_set_out=product.pb product.proto
pbファイル爆誕
このファイルを使ってCloudSpannerに適用させていく。
product.pb
K
product.proto product*%
ProductType
HOGE
HUGUbproto3
DDLファイル作成
ENUMを使いたくば CREATE PTORO BUNDLE
をCloudSpannerに適用しないといけないらしい。ソースは下記。
そのためDDLファイルを作成した。
product.ddl
CREATE PROTO BUNDLE (
product.ProductType
);
gcloudコマンド実行
「ddlの適用」と「DDLが登録されているかを確認」をしている。
gcloud spanner databases ddl update hoge-db --instance=hoge-local --ddl-file=/app/cloudspanner/sql/product.ddl --proto-descriptors-file=/app/cloudspanner/product.pb
gcloud spanner databases ddl describe hoge-db --instance=hoge-local
実行結果
Schema updating...
.....done.
CREATE PROTO BUNDLE (
product.ProductType,
);
CREATE TABLE SchemaMigrations (
Version INT64 NOT NULL,
Dirty BOOL NOT NULL,
) PRIMARY KEY(Version);
SQL実行時にENUMとひもづける
cloudspannerを使っているのでwrenchを使いこなそうと思っている。
DB操作クライアント(dbeaver)をつかったDDLの実行は問題なくできたが、ENUMを使っているテーブルはマイグレーション管理ができなくなってしまうという課題感がでてきた。
wrenchでマイグレーションできない
wrenchからマイグレーションファイルを生成して下記のように記述した。
wrenchのマイグレーション実行結果
CREATE TABLE products (
id INT64 NOT NULL,
product_type product.ProductType NOT NULL -- product.ProductTypeでエラー
) PRIMARY KEY(id);
-- ↓ 実行時エラー
-- 登録したenumが使えない...
-- Error command: up, version: 1.10.1
-- failed to parse DDL/DML statements: 000001.sql:3: got "product", want scalar type, 000001.sql:1.0: unknown DML statement
failed to parse DDL/DML statements
wrench/pkg/spanner/migration.go
の ddlToStatements
でこけていることがわかった。
ddlToStatements
内部的にspansqlというものを使っているらしい。
処理の流れ
- ParseDDL
- parseStatements
- parseDDLStmt
- parseCreateTable
- parseColumnDef
- parseType
- parseBaseOrParameterizedType
余談
ちなみにSpanSQLにENUM自体は次のリリースで対応されるらしい。
ENUMに対応したPR
リリースタグ
ENUM使わないなら、どう制約かける?
- アプリケーション内でチェックをする
- SQL文にCHECK制約を使う
CREATE TABLE products (
id STRING(36) NOT NULL,
product_type STRING(10) NOT NULL,
CHECK (product_type IN ('HOGE', 'HUGU'))
) PRIMARY KEY(id);