JSONフィールドを含む特定の構造体をデータベースに保存したいと思います。
type Comp struct {
CompId int64 `db:"comp_id" json:"comp_id"`
StartDate time.Time `db:"start_date" json:"start_date"`
EndDate time.Time `db:"end_date" json:"end_date"`
WeeklySchedule json.RawMessage `db:"weekly_schedule" json:"weekly_schedule"`
}
テーブルのスキーマは次のとおりです。
CREATE TABLE IF NOT EXISTS Tr.Comp(
comp_id SERIAL,
start_date timestamp NOT NULL,
end_date timestamp NOT NULL,
weekly_schedule json NOT NULL,
PRIMARY KEY (comp_id)
);
プロジェクトでsqlxおよびlib/pqドライバーを使用していますが、以下は実行されません。代わりに、nilポインタがあると言ってパニックになります。 DBはグローバルな*sqlx.DB
構造体です
tx := DB.MustBegin()
compFixture := Comp{
StartDate: time.Now(),
EndDate: time.Now().AddDate(1, 0, 0),
WeeklySchedule: json.RawMessage([]byte("{}")),
}
_, err = tx.NamedExec(
`INSERT INTO
Tr.Comp(comp_id,
start_date, end_date, weekly_schedule)
VALUES (DEFAULT,
:start_date, :end_date, :weekly_schedule)
RETURNING comp_id;`, compFixture)
if err != nil {
t.Fatal("Error creating fixture.", err)
}
スキーマとフィクスチャからweekly_schedule
を削除すると、問題なく動作します。しかし、何らかの理由で、このフィールドが含まれていると、プログラムはパニックになります。 DBスキーマとGo構造体の両方でweekly_schedule
フィールドをどのように定義する必要があるかについてのアイデアはありますか?
sqlxのタイプはgithub.com/jmoiron/sqlx/types
にJSONText
で、必要な処理を実行します
doc JSONTextの場合
これがどれほどクリーンなソリューションであるかはわかりませんが、最終的に独自のデータ型JSONRaw
を作成しました。 DBドライバーはそれを[]btye
と見なしますが、Goコードではjson.RawMessageのように扱うことができます。
type JSONRaw json.RawMessage
func (j JSONRaw) Value() (driver.Value, error) {
byteArr := []byte(j)
return driver.Value(byteArr), nil
}
func (j *JSONRaw) Scan(src interface{}) error {
asBytes, ok := src.([]byte)
if !ok {
return error(errors.New("Scan source was not []bytes"))
}
err := json.Unmarshal(asBytes, &j)
if err != nil {
return error(errors.New("Scan could not unmarshal to []string"))
}
return nil
}
func (m *JSONRaw) MarshalJSON() ([]byte, error) {
return *m, nil
}
func (m *JSONRaw) UnmarshalJSON(data []byte) error {
if m == nil {
return errors.New("json.RawMessage: UnmarshalJSON on nil pointer")
}
*m = append((*m)[0:0], data...)
return nil
}
これは、encoding/json
ライブラリからのMarshalJSON
とUnmarshalJSON
のコピーアンドペーストの再実装です。
外出先のドキュメントから:
json.RawMessage is a raw encoded JSON object. It implements Marshaler and Unmarshaler and can be used to delay JSON decoding or precompute a JSON encoding.
パッケージjsonjson.RawMessageで提供されている例でlog.Printf( "%#"、colors)を実行すると、jsonオブジェクト 'Point'-メンバーをアンマーシャリングした後、アンマーシャリングされないが、[]バイト形式のままになることがわかります。カラーフォーマットは固定されており、「ポイント」は明示的にマーシャリングされていません。
DBに入れる前に、WeeklyScheduleのマーシャリングを解除するようなことを試しましたか?