dieselでchronoの日付型を扱う。
成果物
コード
前回の続き。マイグレーションで日付を入れるpublished
列を追加した。
マイグレーション実行によってschema.rs
ファイルなどが変更されたはず。だが、そのままでは動かない。以下のように修正する。
shema.rs
table! { posts (id) { id -> Integer, title -> Text, body -> Text, is_published -> Bool, published -> Nullable<Timestamp>, } }
models.rs
use super::schema::posts; #[derive(Queryable)] pub struct Post { pub id: i32, pub title: String, pub body: String, pub is_published: bool, pub published: Option<chrono::NaiveDateTime>, } #[derive(Insertable)] #[table_name = "posts"] pub struct NewPost<'a> { pub title: &'a str, pub body: &'a str, }
ちなみに、SQLテーブル定義は以下。
$ sqlite3 ./db.sqlite3 ... sqlite> select * from sqlite_master; ... table|posts|posts|5|CREATE TABLE posts ( id integer primary key, title text not null, body text not null, is_published text not null default 'f' , published text)
実行
できた!
Displaying 1 posts 記事のタイトル ---------- 記事の本文。 複数行を書く。 Ctrl+dキーで終了。 最終行。
失敗ログ
失敗ログ
schema.rs
見てみるとNullable<Text>
になっていた。is_published
もText
に戻ってしまっている。
before
table! { posts (id) { id -> Nullable<Integer>, title -> Text, body -> Text, is_published -> Text, published -> Nullable<Text>, } }
日付型に変えてみた。
after
table! { posts (id) { id -> Integer, title -> Text, body -> Text, is_published -> Bool, published -> chrono::DateTime<chrono::Local>, } }
実行。エラー。
$ cargo run --bin show_posts ... error[E0277]: the trait bound `bool: diesel::Expression` is not satisfied --> src/bin/show_posts.rs:13:30 | 13 | .filter(is_published.eq(true)) | ^^ the trait `diesel::Expression` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::expression::AsExpression<diesel::sql_types::Text>` for `bool` error[E0277]: the trait bound `bool: diesel::Expression` is not satisfied --> src/bin/show_posts.rs:13:10 | 13 | .filter(is_published.eq(true)) | ^^^^^^ the trait `diesel::Expression` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::Expression` for `diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>` = note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table>` error[E0277]: the trait bound `bool: diesel::expression::NonAggregate` is not satisfied --> src/bin/show_posts.rs:13:10 | 13 | .filter(is_published.eq(true)) | ^^^^^^ the trait `diesel::expression::NonAggregate` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::expression::NonAggregate` for `diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>` = note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table>` error[E0277]: the trait bound `(i32, std::string::String, std::string::String, bool): diesel::Queryable<(diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Nullable<diesel::sql_types::Text>), _>` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::Queryable<(diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Nullable<diesel::sql_types::Text>), _>` is not implemented for `(i32, std::string::String, std::string::String, bool)` | = help: the following implementations were found: <(A, B, C, D) as diesel::Queryable<(SA, SB, SC, SD), __DB>> = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Nullable<diesel::sql_types::Integer>, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Nullable<diesel::sql_types::Text>), _>` for `diesel_hello::models::Post` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error[E0277]: the trait bound `bool: diesel::AppearsOnTable<diesel_hello::schema::posts::table>` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::AppearsOnTable<diesel_hello::schema::posts::table>` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::AppearsOnTable<diesel_hello::schema::posts::table>` for `diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>` = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<diesel_hello::schema::posts::table>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>` = note: required because of the requirements on the impl of `diesel::query_builder::Query` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error[E0277]: the trait bound `bool: diesel::query_builder::QueryFragment<_>` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::query_builder::QueryFragment<_>` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>` = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>` = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error[E0277]: the trait bound `bool: diesel::query_builder::QueryId` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::query_builder::QueryId` is not implemented for `bool` | = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>` = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>` = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, bool>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error: aborting due to 7 previous errors
これを以下のように編集する。
schema.rs
table! { posts (id) { id -> Integer, title -> Text, body -> Text, is_published -> Bool, published -> chrono::DateTime<chrono::Local>, } }
models.rs
// ... pub struct Post { pub id: i32, pub title: String, pub body: String, pub is_published: bool, pub published: chrono::DateTime<chrono::Local>, } // ...
エラー。
error[E0277]: the trait bound `chrono::datetime::DateTime<chrono::offset::local::Local>: diesel::deserialize::FromSql<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::deserialize::FromSql<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` is not implemented for `chrono::datetime::DateTime<chrono::offset::local::Local>` | = note: required because of the requirements on the impl of `diesel::Queryable<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` for `chrono::datetime::DateTime<chrono::offset::local::Local>` = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>), diesel::sqlite::Sqlite>` for `(i32, std::string::String, std::string::String, bool, chrono::datetime::DateTime<chrono::offset::local::Local>)` = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>), diesel::sqlite::Sqlite>` for `diesel_hello::models::Post` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, diesel::expression::bound::Bound<diesel::sql_types::Bool, bool>>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error[E0277]: the trait bound `diesel::sqlite::Sqlite: diesel::sql_types::HasSqlType<chrono::datetime::DateTime<chrono::offset::local::Local>>` is not satisfied --> src/bin/show_posts.rs:15:10 | 15 | .load::<Post>(&connection) | ^^^^ the trait `diesel::sql_types::HasSqlType<chrono::datetime::DateTime<chrono::offset::local::Local>>` is not implemented for `diesel::sqlite::Sqlite` | = help: the following implementations were found: <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::BigInt>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Binary>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Bool>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Date>> and 8 others = note: required because of the requirements on the impl of `diesel::sql_types::HasSqlType<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>)>` for `diesel::sqlite::Sqlite` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<diesel::SqliteConnection, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::is_published, diesel::expression::bound::Bound<diesel::sql_types::Bool, bool>>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. error: Could not compile `diesel_hello`. warning: build failed, waiting for other jobs to finish... error[E0277]: the trait bound `diesel::sqlite::Sqlite: diesel::sql_types::HasSqlType<chrono::datetime::DateTime<chrono::offset::local::Local>>` is not satisfied --> src/bin/publish_post.rs:25:10 | 25 | .first(&connection) | ^^^^^ the trait `diesel::sql_types::HasSqlType<chrono::datetime::DateTime<chrono::offset::local::Local>>` is not implemented for `diesel::sqlite::Sqlite` | = help: the following implementations were found: <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::BigInt>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Binary>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Bool>> <diesel::sqlite::Sqlite as diesel::sql_types::HasSqlType<diesel::sql_types::Date>> and 8 others = note: required because of the requirements on the impl of `diesel::sql_types::HasSqlType<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>)>` for `diesel::sqlite::Sqlite` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<diesel::SqliteConnection, _>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>` error[E0277]: the trait bound `chrono::datetime::DateTime<chrono::offset::local::Local>: diesel::deserialize::FromSql<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` is not satisfied --> src/bin/publish_post.rs:25:10 | 25 | .first(&connection) | ^^^^^ the trait `diesel::deserialize::FromSql<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` is not implemented for `chrono::datetime::DateTime<chrono::offset::local::Local>` | = note: required because of the requirements on the impl of `diesel::Queryable<chrono::datetime::DateTime<chrono::offset::local::Local>, diesel::sqlite::Sqlite>` for `chrono::datetime::DateTime<chrono::offset::local::Local>` = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>), diesel::sqlite::Sqlite>` for `(i32, std::string::String, std::string::String, bool, chrono::datetime::DateTime<chrono::offset::local::Local>)` = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Integer, diesel::sql_types::Text, diesel::sql_types::Text, diesel::sql_types::Bool, chrono::datetime::DateTime<chrono::offset::local::Local>), diesel::sqlite::Sqlite>` for `diesel_hello::models::Post` = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<diesel::SqliteConnection, diesel_hello::models::Post>` for `diesel::query_builder::SelectStatement<diesel_hello::schema::posts::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::operators::Eq<diesel_hello::schema::posts::id, diesel::expression::bound::Bound<diesel::sql_types::Integer, i32>>>, diesel::query_builder::order_clause::NoOrderClause, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>`
調査
ググってみる。
とうやら以下2つの型と互換性があるらしい。
[std::time::SystemTime](https://doc.rust-lang.org/nightly/std/time/struct.SystemTime.html)
[chrono::NaiveDateTime](https://erickt.github.io/chrono/naive/datetime/struct.NaiveDateTime.html)
with feature = "chrono"
UTC時刻が使えないだと……。
まあいいや。以下のように修正する。
schema.rs
table! { posts (id) { id -> Integer, title -> Text, body -> Text, is_published -> Bool, published -> Timestamp, } }
models.rs
// ... pub struct Post { pub id: i32, pub title: String, pub body: String, pub is_published: bool, pub published: chrono::NaiveDateTime, } // ...
実行。cargo build
はできたが、以下はパニックした。
$ cargo run --bin show_posts ... thread 'main' panicked at 'Error loading posts: DeserializationError(UnexpectedNullError)', src/libcore/result.rs:999:5 note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
「UnexpectedNullError
」とある。published
列はNULLを許容する。それをコードに反映させねばならないのだと思う。たぶんNullable<T>
だろう。rust側はOption<T>
かな?
shema.rs
table! { posts (id) { // ... published -> Nullable<Timestamp>, } }
models.rs
pub struct Post { // ... pub published: Option<chrono::NaiveDateTime>, }
実行。できた!
Displaying 1 posts 記事のタイトル ---------- 記事の本文。 複数行を書く。 Ctrl+dキーで終了。 最終行。
対象環境
- Raspbierry pi 3 Model B+
- Raspbian stretch 9.0 2018-11-13
- bash 4.4.12(1)-release
- rustc 1.36.0 (a53f9df32 2019-07-03)
- cargo 1.36.0 (c4fcfb725 2019-05-15)
$ uname -a Linux raspberrypi 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux
前回まで
- Rust学習まとめ(ドキュメント)
- Rust自習(じゃんけんゲーム1)
- Rust自習(双方向リスト1)
- Rust自習(単方向リスト1)
- Rust自習(単方向リスト2)
- Rust自習(単方向リスト3)
- Rust自習(単方向リスト4)
- Rust自習(単方向リスト5)
- Rust自習(単方向リスト6)
- Rust自習(単方向リスト7)
- Rust自習(リストのインタフェースを考える)
- Rust自習(連結リスト1)
- Rust自習(連結リスト2)
- Rust自習(連結リスト3)
- Rust自習(連結リスト4)
- Rust自習(連結リストの取得系インタフェース考察)
- Rust自習(連結リスト5)
- Rust自習(連結リストの取得系インタフェース考察2)
- Rust自習(連結リスト6)
- Rust自習(連結リスト7)
- Rust自習(連結リスト8)
- Rust自習(連結リスト9)
- Rust自習(変数名でイテレートする方法)
- Rust自習(iter、iter_mut実装方法)
- Rust自習(連結リスト10)
- Rust自習(rev()実装できず)
- Rust自習(cycle()実装できず)
- Rust自習(じゃんけんゲーム2)
- Rust自習(じゃんけんゲーム3)
- Rust自習(じゃんけんゲーム4)
- Rust自習(じゃんけんゲーム5)
- Rust自習(じゃんけんゲーム6)
- Rust自習(じゃんけんゲーム7)
- Rust自習(じゃんけんゲーム8)
- Rustのアップデート(rustup update)
- Rust自習(SQLite3 1)
- Rust自習(SQLite3 2)
- Rust自習(SQLite3 3)
- Rust自習(日時 1 chrono)
- Rust自習(日時 2 chrono)
- Rust自習(日時 3 chrono)
- Rust自習(日時 4 chrono)
- Rust自習(日時 5 chrono)
- Rust自習(日時 6 chrono)
- Rust自習(日時 7 chrono)
- Rust自習(std::time::SystemTime)
- Rust自習(std::time::Instant)
- Rust自習(std::time::Duration)
- Rust自習(シリアライズ serde 1)
- JSON5とは?
- Rust自習(シリアライズ serde 2 JSON5)
- Rust自習(シリアライズ serde 3 chrono日時型変換)
- Rust自習(diesel 1 SQLite3 ORM)
- Rust自習(diesel 2 SQLite3 ORM)
- Rust自習(diesel 3 SQLite3 ORM)
- Rust自習(diesel 4 SQLite3 ORM)
- Rust自習(diesel 5 SQLite3 ORM)
- Rust自習(diesel 6 SQLite3 ORM)