🧩

Serverpod でPostgreSQLのLASTVAL()を取得する

2023/03/27に公開

Serverpod 1.0.1を使う 2

この記事に関しては、大きな後日譚があります。

結論だけ言うと、「LASTVAL」要注意、です。
詳しくは こちらを参照してください。
https://zenn.dev/flutteruniv_dev/articles/dbcc6d868000d8

試行錯誤

mysql_clientでMySQLを使っていたときは、定型文の()の中にSQL文を書き込むだけだったから、MySQLのdocumentさえしっかり読めばなんとかなっていた。
でも今回は、まだ、serverpodが用意してくれるCRUD関数以外のraw SQLの理解がイマイチだし、endpoint側に書いたraw SQLで取得したdataのFlutter側からの呼び出しがうまくいかないので、五里霧中、という感じ。それでも、できることから、一つずつ。

endpointを新設する

  • tableを新設すると、そのtable専用のCRUD関数が新設される
  • それを既存のendpointで一々書いていると、endpointが爆発する。
  • 用途別にendpointを分けることは可能か実験
  • 結論から言えば、可能。・・・当然か。
  • 新しいendpointは newpod_client/lib/src/protocol/client.dartに自動で追加される。
  • Flutter側で使うときには
    • client.newEndpoint.addItem(item) とか
    • client.oldEndpoint.deleteItem(id) とか区別して書く。

LASTVAL()を取得する

  • 中間tableを設定するのに必須のIdを取得するためにRaw SQLを書いてみる。
newpod_server/lib/src/endpoints/new_endpoint.dart
  Future<int> addPrincipal(Session session, Principal historical) async {
    await Principal.insert(session, historical);
    var principalLastVal = await session.db.query('SELECT LASTVAL()');
    return principalLastVal[0][0] as int;
  }

書く途中でも爺様やら愛ちゃんやらにいろいろ質問したが、できあがったcodeについてコメントを求めると、例えばWarpAIはこんなふうに評する。

This function can be used to insert a Principal object into the database and retrieve the last inserted value, which can be useful for generating unique IDs or linking the Principal object to other objects in the database.

いかにもうまくいってそうな雰囲気。
で、同時にこれをFlutter側から呼んで、二つのIDをつかって中間tableを作りたいのだけれど、これが難題で、Flutter側ではNull扱いになってしまう。爺様、愛ちゃん、ほぼ同じコードを書いてくれるが、私のfileの中では動かないのだ。それはこんなcode。

newpod_flutter/lib/addEvent.dart
case 'HistoricalYears':
  int principalLastVal = await addPrincipal();
  print(principalLastVal);
  break;

だれか助けて できた!

LASTVALがうまく使えるようになったら、一気に中間table問題が解決するんだけどなあ。
初心者過ぎて、自分で自分を笑うしかないミスを、夢のお告げで解決。天才数学者でなくても、ときどき神様が下りてくることはあるのでした\(^O^)/。

何がまちがっていたか

fileの中でaddPrincipal()を呼んでいるところが2カ所ある。
1, clientからaddPrincipal()を呼んで、Flutterの関数として設定しているところ。
2, widgetの中で、1の関数を呼んでいるところ。
なーんと私はずっと、2のほうにくっつけようとしていた。1でclientから呼んでない以上、いくら2で叫んでも聞こえない。

ということで書き直したcodeがこちら。

  addPrincipal() async {
    var principal = Principal(year: year, event: event, country: country);
    int principalLastVal = await client.addAffair.addPrincipal(principal);
    print(principalLastVal);
    debugPrint("add principal");
  }
  
  中略
  
              Padding(
              padding: const EdgeInsets.only(bottom: 16.0),
              child: ElevatedButton(
                onPressed: () async {
                  debugPrint('button pressed');
                  switch (isSelectedCalender) {
                    case 'BillionYears':
                      addBillion();
                      break;
                    case 'HistoricalYears':
                      addPrincipal(); //ここに書いていた愚か者
                      break;
                  }
                },
                child: const Text('Send to Server'),
              ),
            ),
  
  

さあ、前進しよう!

Flutter大学

Discussion