Share
Embed
Transcript
221 slides
-
情報も増えつつある © 2024 Cloudbase Inc. A 入門記3 A 採用事例記3 A
エラー対処記3 A 解説記事 (いつもお世話になっています!) -
アジェンダ É 自己紹介 É Prisma ORMの基本 CÉ ノウハウ紹介 ~ilitiesを添えて~ HÉ
まとめ © 2024 Cloudbase Inc. -
アジェンダ É 自己紹介 É Prisma ORMの基本 CÉ ノウハウ紹介 ~ilitiesを添えて~ HÉ
まとめ © 2024 Cloudbase Inc. -
Cloudbaseの技術スタック © 2024 Cloudbase Inc. RDB API Server GraphDB Data
Loader Storage スキャナー お客様のクラウド環境 Web Frontend お客様 -
Cloudbaseの技術スタック © 2024 Cloudbase Inc. RDB API Server GraphDB Data
Loader Storage スキャナー お客様のクラウド環境 Web Frontend お客様 -
アジェンダ É 自己紹介 É Prisma ORMの基本 CÉ ノウハウ紹介 ~ilitiesを添えて~ HÉ
まとめ © 2024 Cloudbase Inc. -
Prisma ORMとは E TypeScript向けORMライブラ3 E RDBだけでなくドキュメント指向DBも サポー E PostgreSQL, MySQL,
MongoDB, etc... © 2024 Cloudbase Inc. -
Prisma ORMの思想 $ アプリケーション開発者がDBを操作す る際の生産性を向上させるこ( $ 直感的なAPb $ 強力な型定! $
純粋なObjectを返す © 2024 Cloudbase Inc. -
操作例: SELECT const = . . ({ { } })
users await prisma user where: name: findMany "tockn" /* [ { id: 2, email: '[email protected]', name: 'tockn' }, { id: 3, email: '[email protected]', name: 'tockn' } ] */ © 2024 Cloudbase Inc. -
操作例: SELECT const = . . ({ { } })
users await prisma user where: name: findMany "tockn" /* [ { id: 2, email: '[email protected]', name: 'tockn' }, { id: 3, email: '[email protected]', name: 'tockn' } ] */ © 2024 Cloudbase Inc. 純粋なObjectを返す -
操作例: INSERT , UPDATE, DELETE... // INSERT // UPDATE //
DELETE // UPSERT await await await await await await . . ({ { , } }) . . ({ { }, { } }) . . ({ { }, { } }) . . ({ { } }) . . ({ { } }) . . ({ { }, { , }, { } }) prisma user data: name: email: prisma user where: email: data: name: prisma user where: name: data: name: prisma user where: email: prisma user where: name: prisma user where: email: create: name: email: update: name: create update updateMany delete deleteMany upsert "tockn" "[email protected]" "[email protected]" "tockn" "sato" "tockn" "[email protected]" "tockn" "[email protected]" "tockn" "[email protected]" "sato" © 2024 Cloudbase Inc. -
アジェンダ É 自己紹介 É Prisma ORMの基本 CÉ ノウハウ紹介 ~ilitiesを添えて~ HÉ
まとめ © 2024 Cloudbase Inc. -
ilitiesに沿ってお話します © 2024 Cloudbase Inc. F パフォーマンス、スケーラビリティ F セキュリティ F
テスタビリティ F オブザーバビリティ -
find系のincludeについて await . . ({ { , }, }); prisma
user include: post: findFirst true © 2024 Cloudbase Inc. -
find系のincludeについて await . . ({ { , }, }); prisma
user include: post: findFirst true © 2024 Cloudbase Inc. リレーションを持つテーブルを指定 -
includeして得られる結果 { , , , [ { , , ,
, , }, ], }; id: email: name: posts: id: title: content: published: authorId: 1 1 11 '[email protected]' 'tockn' 'Cloudbase' 'Cloudbase is a cloud security platform.' false © 2024 Cloudbase Inc. -
includeして得られる結果 { , , , [ { , , ,
, , }, ], }; id: email: name: posts: id: title: content: published: authorId: 1 1 11 '[email protected]' 'tockn' 'Cloudbase' 'Cloudbase is a cloud security platform.' false © 2024 Cloudbase Inc. リレーション先のデータも取得 -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. -- 1. Userの取得 SELECT FROM
WHERE LIMIT . . , . . , . . . . . = ? ? OFFSET ?; `main` `User` `id` `main` `User` `email` `main` `User` `name` `main` `User` `main` `User` `name` -- 2. 取得したUserが持つPost取得 SELECT FROM WHERE IN LIMIT . . , . . , . . , . . , . . . . . (?, ?, ?) ? OFFSET ?; `main` `Post` `id` `main` `Post` `title` `main` `Post` `content` `main` `Post` `published` `main` `Post` `authorId` `main` `Post` `main` `Post` `authorId` -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. -- 1. Userの取得 SELECT FROM
WHERE LIMIT . . , . . , . . . . . = ? ? OFFSET ?; `main` `User` `id` `main` `User` `email` `main` `User` `name` `main` `User` `main` `User` `name` -- 2. 取得したUserが持つPost取得 SELECT FROM WHERE IN LIMIT . . , . . , . . , . . , . . . . . (?, ?, ?) ? OFFSET ?; `main` `Post` `id` `main` `Post` `title` `main` `Post` `content` `main` `Post` `published` `main` `Post` `authorId` `main` `Post` `main` `Post` `authorId` 最初にuserを取得 -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. -- 1. Userの取得 SELECT FROM
WHERE LIMIT . . , . . , . . . . . = ? ? OFFSET ?; `main` `User` `id` `main` `User` `email` `main` `User` `name` `main` `User` `main` `User` `name` -- 2. 取得したUserが持つPost取得 SELECT FROM WHERE IN LIMIT . . , . . , . . , . . , . . . . . (?, ?, ?) ? OFFSET ?; `main` `Post` `id` `main` `Post` `title` `main` `Post` `content` `main` `Post` `published` `main` `Post` `authorId` `main` `Post` `main` `Post` `authorId` 取得したuser_idで Postを取得 -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. -- 1. Userの取得 SELECT FROM
WHERE LIMIT . . , . . , . . . . . = ? ? OFFSET ?; `main` `User` `id` `main` `User` `email` `main` `User` `name` `main` `User` `main` `User` `name` -- 2. 取得したUserが持つPost取得 SELECT FROM WHERE IN LIMIT . . , . . , . . , . . , . . . . . (?, ?, ?) ? OFFSET ?; `main` `Post` `id` `main` `Post` `title` `main` `Post` `content` `main` `Post` `published` `main` `Post` `authorId` `main` `Post` `main` `Post` `authorId` 取得したuser_idで Postを取得 WHERE IN -
© 2024 Cloudbase Inc. Cloudbaseではど う し ているか g 対象データ量が多い場合はqueryRawを使C
g 少ない場合はincludeを使う await . <{ : ; : }> ; prisma id name $queryRaw number string ` SELECT u.id, u.name FROM user as u INNER JOIN post as p ON u.id = p."authorId" WHERE u.name = 'tockn'` -
© 2024 Cloudbase Inc. Cloudbaseではど う し ているか f 原則updateMany,
deleteManyを使用すa f xxxManyなら余分なクエリが走らない UPDATE DELETE // ️ 原則使わない // 余分なクエリが走らないmanyを使う await await . . ({ { }, { }, }); . . ({ { }, { }, }); prisma user where: email: data: name: prisma user where: name: data: name: update updateMany '[email protected]' 'tockn' 'sato' 'tockn' // 原則使わない // ️ 余分なクエリが走らないmanyを使う await await . . ({ { }, }); . . ({ { }, }); prisma user where: email: prisma user where: name: delete deleteMany '[email protected]' 'tockn' -
previewFeature: relationJoins await . . ({ { }, { },
}); prisma user include: posts: where: name: findMany true 'tockn' © 2024 Cloudbase Inc. -
previewFeature: relationJoins await . . ({ , { }, {
}, }); prisma user relationLoadStrategy: include: posts: where: name: findMany 'join' 'tockn' true © 2024 Cloudbase Inc. joinかqueryか選べるように! -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. await . . ({ ,
{ }, { }, }); prisma user relationLoadStrategy: include: posts: where: name: findMany 'join' 'tockn' true SELECT AS FROM AS LEFT JOIN SELECT AS FROM SELECT FROM SELECT AS FROM SELECT FROM AS WHERE AS AS AS AS ON WHERE . , . , . . LATERAL ( (JSONB_AGG( ), ) ( . ( JSONB_BUILD_OBJECT ( , . , , . , , . ) ( .* . . = . ) ) ) ) TRUE . = $ ; "t1" "id" "t1" "name" "User_posts" "__prisma_data__" "posts" "public" "User" "t1" "__prisma_data__" '[]' "__prisma_data__" "t4" "__prisma_data__" 'id' "t3" "id" 'content' "t3" "content" 'authorId' "t3" "authorId" "__prisma_data__" "t2" "public" "Post" "t2" "t1" "id" "t2" "authorId" "t3" "t4" "t5" "User_posts" "t1" "name" COALESCE /* root select */ /* inner select */ /* middle select */ /* outer select */ 1 発行されるSQL -
find系のincludeで発行されるSQL © 2024 Cloudbase Inc. await . . ({ ,
{ }, { }, }); prisma user relationLoadStrategy: include: posts: where: name: findMany 'join' 'tockn' true SELECT AS FROM AS LEFT JOIN SELECT AS FROM SELECT FROM SELECT AS FROM SELECT FROM AS WHERE AS AS AS AS ON WHERE . , . , . . LATERAL ( (JSONB_AGG( ), ) ( . ( JSONB_BUILD_OBJECT ( , . , , . , , . ) ( .* . . = . ) ) ) ) TRUE . = $ ; "t1" "id" "t1" "name" "User_posts" "__prisma_data__" "posts" "public" "User" "t1" "__prisma_data__" '[]' "__prisma_data__" "t4" "__prisma_data__" 'id' "t3" "id" 'content' "t3" "content" 'authorId' "t3" "authorId" "__prisma_data__" "t2" "public" "Post" "t2" "t1" "id" "t2" "authorId" "t3" "t4" "t5" "User_posts" "t1" "name" COALESCE /* root select */ /* inner select */ /* middle select */ /* outer select */ 1 発行されるSQL JOINが使われている (少し複雑なSQLだが...) -
© 2024 Cloudbase Inc. Read Replica V Read専用のノーD V Primaryの内容をほぼリアルタイムにコピー
Primary レプリケーション Read Replica -
PrismaClientIssuerについて const new async => async => = ( )
. (..., ( ) { . . ({ ... }) }) . (..., ( ) { . . ({ ... }) }) issuer PrismaClientIssuser primary create readReplica findMany args issuer tx tx user issuer tx tx user // primaryへのアクセス // read replicaへのアクセス await await await return © 2024 Cloudbase Inc. -
PrismaClientIssuerについて const new async => async => = ( )
. (..., ( ) { . . ({ ... }) }) . (..., ( ) { . . ({ ... }) }) issuer PrismaClientIssuser primary create readReplica findMany args issuer tx tx user issuer tx tx user // primaryへのアクセス // read replicaへのアクセス await await await return © 2024 Cloudbase Inc. primaryを指定 -
PrismaClientIssuerについて const new async => async => = ( )
. (..., ( ) { . . ({ ... }) }) . (..., ( ) { . . ({ ... }) }) issuer PrismaClientIssuser primary create readReplica findMany args issuer tx tx user issuer tx tx user // primaryへのアクセス // read replicaへのアクセス await await await return © 2024 Cloudbase Inc. callbackの引数に primaryへ張ったTranasctionClientが来る -
PrismaClientIssuerについて const new async => async => = ( )
. (..., ( ) { . . ({ ... }) }) . (..., ( ) { . . ({ ... }) }) issuer PrismaClientIssuser primary create readReplica findMany args issuer tx tx user issuer tx tx user // primaryへのアクセス // read replicaへのアクセス await await await return © 2024 Cloudbase Inc. primaryへクエリを発行 -
PrismaClientIssuerについて const new async => async => = ( )
. (..., ( ) { . . ({ ... }) }) . (..., ( ) { . . ({ ... }) }) issuer PrismaClientIssuser primary create readReplica findMany args issuer tx tx user issuer tx tx user // primaryへのアクセス // read replicaへのアクセス await await await return © 2024 Cloudbase Inc. read replicaも同じ -
PrismaClientIssuerについて const async => = ( : . , :
) { ... }; handleUser tx user Prisma TransactionClient User © 2024 Cloudbase Inc. -
PrismaClientIssuerについて const async => = ( : . , :
) { ... }; handleUser tx user Prisma TransactionClient User © 2024 Cloudbase Inc. primaryを渡すべき? readReplicaを渡すべき? -
PrismaClientIssuerについて const async => = ( : . , :
) { . . ({ }); }; handleUser create tx user tx user data: user Prisma TransactionClient User await © 2024 Cloudbase Inc. 実装を見ないとわからない (この例はcreateしてるのでprimaryが必要) -
© 2024 Cloudbase Inc. 2つのTransaction型 ・PrismaのTransactionClientの交差型 ・ ・issuerのprimaryメソッドで渡る型
・ に対しても ・ ・issuerのreadReplicaメソッドで渡る型 ・ に対して CBWritableTransaction CBWritableTransaction CBReadableTransaction CBReadableTransaction 渡せる 渡せない -
独自Transaction型を使う const async => const async => = ( :
, : ) { . . ({ }); }; = ( : ) { . . (); }; registerUser create listUsers findMany tx user tx user data: user tx tx user CBWritableTransaction User CBReadableTransaction await return © 2024 Cloudbase Inc. -
独自Transaction型を使う const async => const async => = ( :
, : ) { . . ({ }); }; = ( : ) { . . (); }; registerUser create listUsers findMany tx user tx user data: user tx tx user CBWritableTransaction User CBReadableTransaction await return © 2024 Cloudbase Inc. Write系クエリがある場合は CBWritableTranasction -
独自Transaction型を使う const async => const async => = ( :
, : ) { . . ({ }); }; = ( : ) { . . (); }; registerUser create listUsers findMany tx user tx user data: user tx tx user CBWritableTransaction User CBReadableTransaction await return © 2024 Cloudbase Inc. Read系のみの場合は CBReadableTransaction -
PrismaClientIssuerと独自Transaction型(OKパターン) // primary // CBWritableTransaction // CBReadableTransaction // read replica
// CBReadableTransaction await await return await return . (..., ( ) { ( ) ( ) }) . (..., ( ) { ( ) }) issuer tx tx tx issuer tx tx primary registerUser listUsers readReplica listUsers async => async => © 2024 Cloudbase Inc. -
PrismaClientIssuerと独自Transaction型(OKパターン) // primary // CBWritableTransaction // CBReadableTransaction // read replica
// CBReadableTransaction await await return await return . (..., ( ) { ( ) ( ) }) . (..., ( ) { ( ) }) issuer tx tx tx issuer tx tx primary registerUser listUsers readReplica listUsers async => async => © 2024 Cloudbase Inc. Writable, Readableどちらも呼べる primaryでは CBWritableTransactionが貰える -
PrismaClientIssuerと独自Transaction型(OKパターン) // primary // CBWritableTransaction // CBReadableTransaction // read replica
// CBReadableTransaction await await return await return . (..., ( ) { ( ) ( ) }) . (..., ( ) { ( ) }) issuer tx tx tx issuer tx tx primary registerUser listUsers readReplica listUsers async => async => © 2024 Cloudbase Inc. readReplicaでは CBReadableTransactionが貰える Readableのみ呼べる -
PrismaClientIssuerと独自Transaction型(NGパターン) // NG // 型エラー // NG // 型エラー await
return return . (..., ( ) { ( ) }) = ( : ) { ( ) . . () } issuer tx tx tx tx tx user readReplica registerUser listUsers registerUser findMany async => const async => CBReadableTransaction © 2024 Cloudbase Inc. -
PrismaClientIssuerと独自Transaction型(NGパターン) // NG // 型エラー // NG // 型エラー await
return return . (..., ( ) { ( ) }) = ( : ) { ( ) . . () } issuer tx tx tx tx tx user readReplica registerUser listUsers registerUser findMany async => const async => CBReadableTransaction © 2024 Cloudbase Inc. CBWritableTransactionが必要なメソッドを readReplicaで呼ぶと型エラー -
PrismaClientIssuerと独自Transaction型(NGパターン) // NG // 型エラー // NG // 型エラー await
return return . (..., ( ) { ( ) }) = ( : ) { ( ) . . () } issuer tx tx tx tx tx user readReplica registerUser listUsers registerUser findMany async => const async => CBReadableTransaction © 2024 Cloudbase Inc. メソッド内で渡してしまうことも防止 -
© 2024 Cloudbase Inc. パフ ォーマンス、 スケーラビリテ ィ ノ ウハウまとめ
・発行されるクエリに注意 ・結局queryRawが必要になることも ・とはいえ、Prismaはクエリ最適化を頑張ってる ・Read Replicaによるスケールアウト ・PrismaClientをwrapするクラスを作ると便利 ・独自のTransaction型を定義すると便利 -
whereとundefined const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. -
whereとundefined const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. これがundefinedを返した場合 -
whereとundefined const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. tenant関係なく 全件取得 -
© 2024 Cloudbase Inc. Row Level Security ・通称RLS ・PostgreSQLにある機能 ・DBユーザ、セッション、トランザクションにおいて
アクセス可能なレコードを行レベルで制御する仕組み -
RLSざっくり解説 © 2024 Cloudbase Inc. どうぞ (SELECT * FROM messagesの結果)
id 1 こんにちは〜 どうも〜 さようなら〜 1 1 1 6 29 body tenant_id -
RLSざっくり解説 © 2024 Cloudbase Inc. どうぞ (SELECT * FROM messagesの結果)
id 1 こんにちは〜 どうも〜 さようなら〜 1 1 1 6 29 body tenant_id Whereが無くても tenantIdで絞られる -
PrismaClientIssuerとRLS await . ( , ( ) { ... })
issuer accessToken tx primary async => © 2024 Cloudbase Inc. -
PrismaClientIssuerとRLS await . ( , ( ) { ... })
issuer accessToken tx primary async => © 2024 Cloudbase Inc. 認可情報を渡す -
PrismaClientIssuerとRLS await . ( , ( ) { ... })
issuer accessToken tx primary async => © 2024 Cloudbase Inc. RLSが適用された Transaction -
© 2024 Cloudbase Inc. このaccessTokenって何者? await . ( , (
) { ... }) issuer accessToken tx primary async => -
© 2024 Cloudbase Inc. そのユーザがアクセス可能な テナントIDが入ったObject const = { ;
} accessToken tenantId: 1 (厳密にはもっと工夫がある) -
© 2024 Cloudbase Inc. express middlewareが発行する 権限を持つtenantId取得 Request Objectとして渡す express
application auth middleware handler -
handlerの実装 async => async => ( , ) { .
( . , ( ) { ... }) } req: res: issuer req accessToken tx express.Request express.Response await readReplica © 2024 Cloudbase Inc. reqから取得して 渡すだけ -
© 2024 Cloudbase Inc. どうやってRLSを適用した Transactionを生成している? await . ( ,
( ) { ... }) issuer accessToken tx primary async => -
PrismaClientIssuerの実装 async accessToken callback prisma tx tx accessToken tenantId tx
( , ) { ... . ( ( ) { . . ; ( ); }) } readReplica $transaction $executeRaw callback return await return async => ${ } ` SELECT set_config( 'app.rls_config.tenant', , TRUE )` © 2024 Cloudbase Inc. -
PrismaClientIssuerの実装 async accessToken callback prisma tx tx accessToken tenantId tx
( , ) { ... . ( ( ) { . . ; ( ); }) } readReplica $transaction $executeRaw callback return await return async => ${ } ` SELECT set_config( 'app.rls_config.tenant', , TRUE )` © 2024 Cloudbase Inc. set_configを呼んで callbackに渡してるだけ -
© 2024 Cloudbase Inc. 例えば 以下のテーブルがあるとする model User id Int
name String address String password String { } -
© 2024 Cloudbase Inc. 例えば 以下のテーブルがあるとする model User id Int
name String address String password String { } 個人情報 -
© 2024 Cloudbase Inc. このテーブルを使った ユーザ一覧取得APIを考える model User id Int
name String address String password String { } -
© 2024 Cloudbase Inc. Responseの型を以下とする type = { : ;
: ; }[]; ListUsersResponse number string id name -
こうなる const async => const = ( , ) {
: = . . (); . ( ); }; listUsers findMany json req res prisma user res resp resp ListUsersResponse await -
こうなる const async => const = ( , ) {
: = . . (); . ( ); }; listUsers findMany json req res prisma user res resp resp ListUsersResponse await 型的には問題ないが…? -
こうなる [ { : , : , : , :
} ] "id" "name" "address" "password" 1 "tockn" "〒108-0073 東京都港区三田3-2-8" "sugoi-secure-password" -
こうなる [ { : , : , : , :
} ] "id" "name" "address" "password" 1 "tockn" "〒108-0073 東京都港区三田3-2-8" "sugoi-secure-password" 個人情報が丸見えに -
© 2024 Cloudbase Inc. zod ・スキーマ定義とバリデーションを行うライブラリ ・z.object() 等を使用してスキーマを定義 ・Schema.parse(obj) で渡したobjのバリデーション
const type typeof = . ({ . (), . (), }); = . < >; . ( ); User z id: z name: z User User obj object number string parse User z infer // バリデーション -
Response型をzodで書き換える const type typeof = . ( . ({ .
(), . (), }), ); = . < >; ListUsersResponse z z id: z name: z ListUsersResponse array object number string ListUsersResponse z infer -
zodのparseを行う const async => const = ( , ) {
= . ( . . () ); . ( ); }; listUsers parse findMany json req res ListUsersResponse prisma user res resp resp await -
zodのparseを行う const async => const = ( , ) {
= . ( . . () ); . ( ); }; listUsers parse findMany json req res ListUsersResponse prisma user res resp resp await parseメソッドを実行 -
こうなる [ { : , : } ] "id" "name"
1 "tockn" -
こうなる [ { : , : } ] "id" "name"
1 "tockn" 個人情報が切り落とされた! parseは未定義フィールドを切り落とす -
© 2024 Cloudbase Inc. セキ ュ リテ ィ ノ ウハウまとめ
・マルチテナントにおける行レベルのセキュリティ ・PrismaでRLSを使う ・またしてもPrismaClientをwrapするクラスが便利 ・列レベルのセキュリティも忘れてはいけない ・PrismaはPOJO返し、TypeScriptは構造的型付け ・ナイーブな実装は情報漏洩になることも ・zodを使うことで回避 -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => シードレコードを 宣言的に定義 -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => シードレコードを 宣言的に定義 DELETEしてから INSERT -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => シードレコードを 宣言的に定義 外部キー制約も考慮して INSERT DELETEしてから INSERT -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => テスト対象の メソッドを書く -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => テスト対象メソッドの 戻り値を定義 -
内製Test Runner全体像 it run method _TEST_ONLY_primaryDBWithRLS registerUserInGroup ( , (
, { { [{ , }], [{ , , }], }, () ( ( ) ( , )), { }, { [{ , , }] ... '指定したgroupId配下にuserが作成される' 'テナント1' 'グループ1' 'tockn' db recordSet: tenant: id: name: group: id: name: tenantId: : tx tx returns: id: mutates: user: id: name: groupId: 1 1 1 1 1 1 1 => => テスト対象メソッド実行後の レコードの状態を定義 -
© 2024 Cloudbase Inc. 今から使えます! schema.prisma shell npm @cloudbase-inc/ install
prisma-generator-integration-test-runner -D generator integration test runner provider - - { = } "prisma-generator-integration-test-runner" -
© 2024 Cloudbase Inc. テスタビリテ ィ まとめ ・開発生産性に課題 ・テストレコードの用意、検証など ・内製Test
Runnerが便利 ・宣言的な状態定義 ・OSSとして公開しました ・ぜひ使ってみてください -
© 2024 Cloudbase Inc. OpenTelemetry tracing ・PrismaにあるPreview Feature ・OpenTelemetryの計装 ・PrismaClientの様々な処理をトレースできる
・環境構築は公式ドキュメントを参照 ・expressなどの計装と合わせて見れる -
トレースをJaegerで可視化 const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. -
トレースをJaegerで可視化 const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. どのAPIで -
トレースをJaegerで可視化 const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. どのような処理が どのくらい実行されたか -
トレースをJaegerで可視化 const = (); . . ({ { } });
tenantId await await getMyTenantId findMany prisma message where: tenantId © 2024 Cloudbase Inc. どのようなSQLが発行されたか -
アジェンダ É 自己紹介 É Prisma ORMの基本 CÉ ノウハウ紹介 ~ilitiesを添えて~ HÉ
まとめ © 2024 Cloudbase Inc.