teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

typo

2020/06/06 04:02

投稿

d_tutuz
d_tutuz

スコア730

answer CHANGED
@@ -1,6 +1,6 @@
1
1
  追記いただいたコード(InsertHoge メソッド)をベースに全体的に書き換えました。ローカルで試す際は Docker などを用いて PostgreSQL に接続できる環境でお試しください。
2
2
 
3
- `LastInsertId` は Postgres のドライバーでは使えない (参照: [no LastInsertId available in Postgresql](https://github.com/jmoiron/sqlx/issues/245)) ため [`RETURNING`](https://www.postgresql.jp/document/11/html/dml-returning.html) 句を用いるのはどうでしょうか?`RETURNING` は `squirrel` のクエリビルダで付与するイメージです。
3
+ `LastInsertId` は PostgreSQL のドライバーでは使えない (参照: [no LastInsertId available in Postgresql](https://github.com/jmoiron/sqlx/issues/245)) ため [`RETURNING`](https://www.postgresql.jp/document/11/html/dml-returning.html) 句を用いるのはどうでしょうか?`RETURNING` は `squirrel` のクエリビルダで付与するイメージです。
4
4
 
5
5
  ### コード
6
6
 

1

追記いただいたコードをベースに全体的に書き換え

2020/06/06 04:02

投稿

d_tutuz
d_tutuz

スコア730

answer CHANGED
@@ -1,20 +1,98 @@
1
- squirrel のどのメソッドを用いるかよって多少異なると思いすが、とえば [InsertBuilder.ExecContext](https://godoc.org/github.com/Masterminds/squirrel#InsertBuilder.ExecContext) を用いた場合の例を考えみます
1
+ 追記いただいたコード(InsertHoge メソッド)ベース全体的に書き換え。ローカルで試す際は Docker などを用いて PostgreSQL に接続できる環境でお試しください
2
2
 
3
- ```go
4
- func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, error)
5
- ```
3
+ `LastInsertId` は Postgres のドライバーでは使えない (参照: [no LastInsertId available in Postgresql](https://github.com/jmoiron/sqlx/issues/245)) ため [`RETURNING`](https://www.postgresql.jp/document/11/html/dml-returning.html) 句を用いるのはどうでしょうか?`RETURNING` は `squirrel` のクエリビルダで付与するイメージです。
6
4
 
7
- その場合、以下のようにして database/sql の sql.Result を取得できます。なので LastInsertId() で id も取得できると思いますが、どうでしょうか。
5
+ ### コード
8
6
 
9
7
  ```go
10
- b := Insert("test").Values(1)
8
+ package main
11
9
 
10
+ import (
11
+ "database/sql"
12
+ "fmt"
13
+
14
+ "github.com/jmoiron/sqlx"
15
+ _ "github.com/lib/pq"
16
+
17
+ sq "github.com/Masterminds/squirrel"
18
+ )
19
+
20
+ func (p *Postgres) InsertHoge(hoge *Hoge) (*Hoge, error) {
12
- ret, err := b.ExecContext(context.TODO())
21
+ query, args, err := sq.StatementBuilder.PlaceholderFormat(sq.Dollar).
22
+ Insert("hoge").Columns("title").Values(hoge.Title).Suffix("RETURNING *").ToSql()
23
+
13
24
  if err != nil {
14
- // handle error
25
+ return nil, err
15
26
  }
27
+
16
- id, err = ret.LastInsertId()
28
+ tx, err := p.Beginx()
17
29
  if err != nil {
18
- // handle error
30
+ return nil, err
19
31
  }
32
+
33
+ var h Hoge
34
+ if err := tx.QueryRowx(query, args[0]).StructScan(&h); err != nil {
35
+ return nil, err
36
+ }
37
+
38
+ tx.Commit()
39
+
40
+ // エラーのときのロールバックの処理は割愛
41
+ return &h, nil
42
+ }
43
+
44
+ // ------------------------------------------------------------------------------------------------
45
+ // ローカルの Docker の起動
46
+ // $ docker run --name tmp-postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -d -p 5432:5432 postgres
47
+ // ------------------------------------------------------------------------------------------------
48
+
49
+ func main() {
50
+ // Docker上のデータベースへの接続
51
+ db, err := sql.Open("postgres", fmt.Sprintf(
52
+ "user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
53
+ "postgres", "postgres", "localhost", "5432", "postgres", "disable",
54
+ ))
55
+ if err != nil {
56
+ panic(err)
57
+ }
58
+
59
+ // sqlxライブラリの使用
60
+ x := sqlx.NewDb(db, "postgres")
61
+
62
+ // Postgres構造体の値生成
63
+ p := &Postgres{x}
64
+
65
+ // クエリの実行
66
+ m, err := p.InsertHoge(&Hoge{Title: "gopher"})
67
+ if err != nil {
68
+ panic(err)
69
+ }
70
+
71
+ // 結果の表示
72
+ fmt.Printf("%+v\n", m)
73
+ }
74
+
75
+ /*
76
+ -- DDLは以下のようなものを想定
77
+
78
+ CREATE TABLE hoge (
79
+ id SERIAL NOT NULL,
80
+ title VARCHAR(255) NOT NULL,
81
+ PRIMARY KEY (id)
82
+ );
83
+ */
84
+ type Hoge struct {
85
+ Id int `db:"id"`
86
+ Title string `db:"title"`
87
+ }
88
+
89
+ type Postgres struct{ *sqlx.DB }
90
+ ```
91
+
92
+ ### 取得できる結果例
93
+
94
+ 以下のように ID と Title の組み合わせでオートインクリメントされた ID の値も取得できます。
95
+
96
+ ```
97
+ &{Id:3 Title:gopher}
20
98
  ```