99% of base complete

This commit is contained in:
Nicolai Van der Storm 2025-02-11 19:59:00 +01:00
parent 6d08c39a6d
commit 4451a3cf3d
36 changed files with 867 additions and 5685 deletions

2
.env
View File

@ -1 +1 @@
DATABASE_URL=sqlite://./db.sqlite?mode=rwc DATABASE_URL=postgres://postgres:password@localhost/olh

7
.gitignore vendored
View File

@ -8,6 +8,13 @@
#/target #/target
# Added by cargo
#
# already existing elements were commented out
#/target
# Added by cargo # Added by cargo
# #
# already existing elements were commented out # already existing elements were commented out

2981
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -7,12 +7,11 @@ edition = "2021"
anyhow = "1.0.95" anyhow = "1.0.95"
async-trait = "0.1.86" async-trait = "0.1.86"
axum = { version = "0.8.1", features = ["json"] } axum = { version = "0.8.1", features = ["json"] }
diesel = { version = "2.2.7", features = ["postgres", "r2d2"] }
dotenvy = "0.15.7" dotenvy = "0.15.7"
sea-orm = { version = "1.1.4", features = ["runtime-tokio-native-tls", "sqlx-postgres", "sqlx-sqlite"] } r2d2 = "0.8.10"
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.138" serde_json = "1.0.138"
tokio = { version = "1.43.0", features = ["full"] } tokio = { version = "1.43.0", features = ["full"] }
tower-http = { version = "0.6.2", features = ["cors"] } tower = "0.5.2"
tower-http = { version = "0.6.2", features = ["trace"] }
[dev-dependencies]
sea-orm-cli = "1.1.4"

BIN
db.sqlite

Binary file not shown.

9
diesel.toml Normal file
View File

@ -0,0 +1,9 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
[migrations_directory]
dir = "/home/nicolaivds/GIT/OpenLayerHub/migrations"

516
log Normal file
View File

@ -0,0 +1,516 @@
Compiling openlayerhub v0.1.0 (/home/nicolaivds/GIT/OpenLayerHub)
error[E0277]: the trait bound `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>: LoadQuery<'_, _, _>` is not satisfied
--> src/base/service.rs:60:25
|
60 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `AsQuery` is not implemented for `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>`, which is required by `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>` to implement `LoadQuery<'_, _, _>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
|
54 | i32: diesel::deserialize::FromSql<diesel::sql_types::Integer, Conn::Backend>, InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>: AsQuery
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error[E0277]: the trait bound `Conn: LoadConnection` is not satisfied
--> src/base/service.rs:60:25
|
60 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `LoadConnection` is not implemented for `Conn`, which is required by `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `PooledConnection<ConnectionManager<Conn>>` to implement `LoadConnection`
= note: required for `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, _>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
help: consider further restricting this bound
|
50 | Conn: diesel::Connection + R2D2Connection + 'static + diesel::connection::LoadConnection,
| ++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<T as HasTable>::Table: SingleValue` is not satisfied
--> src/base/service.rs:60:25
|
60 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `SingleValue` is not implemented for `<T as HasTable>::Table`, which is required by `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `<T as HasTable>::Table` to implement `SqlTypeOrSelectable`
= note: required for `T` to implement `FromSqlRow<<T as HasTable>::Table, <Conn as Connection>::Backend>`
= note: required for `InsertStatement<<T as HasTable>::Table, <T as diesel::Insertable<<T as HasTable>::Table>>::Values>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, T>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
error[E0275]: overflow evaluating the requirement `_: Sized`
--> src/base/service.rs:67:14
|
67 | .filter(T::primary_key().eq(id))
| ^^^^^^
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "512"]` attribute to your crate (`openlayerhub`)
= note: required for `<<T as HasTable>::Table as AsQuery>::Query` to implement `FilterDsl<_>`
error[E0277]: `<<T as HasTable>::Table as AsQuery>::Query` is no valid SQL fragment for the `_` backend
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `QueryFragment<_>` is not implemented for `<<T as HasTable>::Table as AsQuery>::Query`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= note: this usually means that the `_` database system does not support
this SQL syntax
= help: the following other types implement trait `QueryFragment<DB, SP>`:
`&T` implements `QueryFragment<DB>`
`()` implements `QueryFragment<DB>`
`(T0, T1)` implements `QueryFragment<__DB>`
`(T0, T1, T2)` implements `QueryFragment<__DB>`
`(T0, T1, T2, T3)` implements `QueryFragment<__DB>`
`(T0, T1, T2, T3, T4)` implements `QueryFragment<__DB>`
`(T0, T1, T2, T3, T4, T5)` implements `QueryFragment<__DB>`
`(T0, T1, T2, T3, T4, T5, T6)` implements `QueryFragment<__DB>`
and 278 others
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, _, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
error[E0277]: the trait bound `<<T as HasTable>::Table as AsQuery>::Query: QueryId` is not satisfied
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `QueryId` is not implemented for `<<T as HasTable>::Table as AsQuery>::Query`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, _, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
error[E0277]: the trait bound `<<T as HasTable>::Table as AsQuery>::SqlType: SingleValue` is not satisfied
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `SingleValue` is not implemented for `<<T as HasTable>::Table as AsQuery>::SqlType`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= note: required for `<<T as HasTable>::Table as AsQuery>::SqlType` to implement `load_dsl::private::CompatibleType<T, _>`
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, _, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
error[E0277]: the trait bound `T: diesel::Queryable<<<T as HasTable>::Table as AsQuery>::SqlType, _>` is not satisfied
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `diesel::Queryable<<<T as HasTable>::Table as AsQuery>::SqlType, _>` is not implemented for `T`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `diesel::Queryable<ST, DB>`:
`(T0, T1)` implements `diesel::Queryable<(ST0, ST1), __DB>`
`(T0, T1)` implements `diesel::Queryable<Record<(ST0, ST1)>, Pg>`
`(T0, T1, T2)` implements `diesel::Queryable<(ST0, ST1, ST2), __DB>`
`(T0, T1, T2)` implements `diesel::Queryable<Record<(ST0, ST1, ST2)>, Pg>`
`(T0, T1, T2, T3)` implements `diesel::Queryable<(ST0, ST1, ST2, ST3), __DB>`
`(T0, T1, T2, T3)` implements `diesel::Queryable<Record<(ST0, ST1, ST2, ST3)>, Pg>`
`(T0, T1, T2, T3, T4)` implements `diesel::Queryable<(ST0, ST1, ST2, ST3, ST4), __DB>`
`(T0, T1, T2, T3, T4)` implements `diesel::Queryable<Record<(ST0, ST1, ST2, ST3, ST4)>, Pg>`
and 116 others
= note: required for `T` to implement `FromSqlRow<<<T as HasTable>::Table as AsQuery>::SqlType, _>`
= note: required for `<<T as HasTable>::Table as AsQuery>::SqlType` to implement `load_dsl::private::CompatibleType<T, _>`
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, _, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
error[E0277]: the trait bound `Conn: LoadConnection` is not satisfied
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `LoadConnection` is not implemented for `Conn`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= note: required for `PooledConnection<ConnectionManager<Conn>>` to implement `LoadConnection`
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
help: consider further restricting this bound
|
50 | Conn: diesel::Connection + R2D2Connection + 'static + diesel::connection::LoadConnection,
| ++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<Conn as Connection>::Backend: QueryMetadata<<<T as HasTable>::Table as AsQuery>::SqlType>` is not satisfied
--> src/base/service.rs:77:24
|
77 | .load::<T>(&mut conn)
| ---- ^^^^^^^^^ the trait `HasSqlType<<<T as HasTable>::Table as AsQuery>::SqlType>` is not implemented for `<Conn as Connection>::Backend`, which is required by `<T as HasTable>::Table: LoadQuery<'_, _, T>`
| |
| required by a bound introduced by this call
|
= note: required for `<Conn as Connection>::Backend` to implement `QueryMetadata<<<T as HasTable>::Table as AsQuery>::SqlType>`
= note: required for `<T as HasTable>::Table` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, T>`
note: required by a bound in `diesel::RunQueryDsl::load`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1542:15
|
1540 | fn load<'query, U>(self, conn: &mut Conn) -> QueryResult<Vec<U>>
| ---- required by a bound in this associated function
1541 | where
1542 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::load`
error[E0277]: the trait bound `<T as HasTable>::Table: IntoUpdateTarget` is not satisfied
--> src/base/service.rs:83:24
|
83 | diesel::update(<T as HasTable>::table())
| -------------- ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Identifiable` is not implemented for `<T as HasTable>::Table`, which is required by `<T as HasTable>::Table: IntoUpdateTarget`
| |
| required by a bound introduced by this call
|
= note: required for `<T as HasTable>::Table` to implement `IntoUpdateTarget`
note: required by a bound in `update`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_builder/functions.rs:80:18
|
80 | pub fn update<T: IntoUpdateTarget>(source: T) -> UpdateStatement<T::Table, T::WhereClause> {
| ^^^^^^^^^^^^^^^^ required by this bound in `update`
error[E0277]: the trait bound `<T as HasTable>::Table: HasTable` is not satisfied
--> src/base/service.rs:83:9
|
83 | diesel::update(<T as HasTable>::table())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasTable` is not implemented for `<T as HasTable>::Table`
error[E0277]: the trait bound `<T as Model>::PrimaryKey: AppearsOnTable<_>` is not satisfied
--> src/base/service.rs:84:14
|
84 | .filter(T::primary_key().eq(id))
| ^^^^^^ the trait `AppearsOnTable<_>` is not implemented for `<T as Model>::PrimaryKey`, which is required by `UpdateStatement<_, _>: FilterDsl<_>`
|
= help: the following other types implement trait `AppearsOnTable<QS>`:
`&'a T` implements `AppearsOnTable<QS>`
`(T0, T1)` implements `AppearsOnTable<QS>`
`(T0, T1, T2)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6, T7)` implements `AppearsOnTable<QS>`
and 131 others
= note: required for `diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>` to implement `AppearsOnTable<_>`
= note: 1 redundant requirement hidden
= note: required for `Grouped<Eq<<T as Model>::PrimaryKey, Bound<Integer, i32>>>` to implement `AppearsOnTable<_>`
= note: required for `UpdateStatement<_, _>` to implement `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>>>`
= note: the full name for the type has been written to '/home/nicolaivds/GIT/OpenLayerHub/target/debug/deps/openlayerhub-1f7d339452a03941.long-type-9065444121950834043.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0277]: the trait bound `<T as Model>::PrimaryKey: AppearsOnTable<_>` is not satisfied
--> src/base/service.rs:84:21
|
84 | .filter(T::primary_key().eq(id))
| ------ ^^^^^^^^^^^^^^^^^^^^^^^ the trait `AppearsOnTable<_>` is not implemented for `<T as Model>::PrimaryKey`, which is required by `UpdateStatement<_, _>: FilterDsl<_>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `AppearsOnTable<QS>`:
`&'a T` implements `AppearsOnTable<QS>`
`(T0, T1)` implements `AppearsOnTable<QS>`
`(T0, T1, T2)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6, T7)` implements `AppearsOnTable<QS>`
and 131 others
= note: required for `diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>` to implement `AppearsOnTable<_>`
= note: 1 redundant requirement hidden
= note: required for `Grouped<Eq<<T as Model>::PrimaryKey, Bound<Integer, i32>>>` to implement `AppearsOnTable<_>`
= note: required for `UpdateStatement<_, _>` to implement `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>>>`
note: required by a bound in `UpdateStatement::<T, U, V, Ret>::filter`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_builder/update_statement/mod.rs:98:15
|
96 | pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
| ------ required by a bound in this associated function
97 | where
98 | Self: FilterDsl<Predicate>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `UpdateStatement::<T, U, V, Ret>::filter`
= note: the full name for the type has been written to '/home/nicolaivds/GIT/OpenLayerHub/target/debug/deps/openlayerhub-1f7d339452a03941.long-type-9065444121950834043.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0277]: the trait bound `&T: diesel::AsChangeset` is not satisfied
--> src/base/service.rs:85:18
|
85 | .set(&entity)
| --- ^^^^^^^ the trait `diesel::AsChangeset` is not implemented for `&T`
| |
| required by a bound introduced by this call
|
note: required by a bound in `UpdateStatement::<T, U>::set`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_builder/update_statement/mod.rs:38:12
|
35 | pub fn set<V>(self, values: V) -> UpdateStatement<T, U, V::Changeset>
| --- required by a bound in this associated function
...
38 | V: changeset::AsChangeset<Target = T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `UpdateStatement::<T, U>::set`
help: consider removing the leading `&`-reference
|
85 - .set(&entity)
85 + .set(entity)
|
error[E0277]: the trait bound `<Conn as Connection>::Backend: DieselReserveSpecialization` is not satisfied
--> src/base/service.rs:86:25
|
86 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `DieselReserveSpecialization` is not implemented for `<Conn as Connection>::Backend`, which is required by `UpdateStatement<_, _, _>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `UpdateStatement<_, _, _, ReturningClause<_>>` to implement `QueryFragment<<Conn as Connection>::Backend>`
= note: required for `UpdateStatement<_, _, _>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, _>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
error[E0277]: `ReturningClause<_>` is no valid SQL fragment for the `<Conn as Connection>::Backend` backend
--> src/base/service.rs:86:25
|
86 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `QueryFragment<<Conn as Connection>::Backend, <<Conn as Connection>::Backend as SqlDialect>::ReturningClause>` is not implemented for `ReturningClause<_>`, which is required by `UpdateStatement<_, _, _>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: this usually means that the `<Conn as Connection>::Backend` database system does not support
this SQL syntax
= help: the following other types implement trait `QueryFragment<DB, SP>`:
`ReturningClause<Expr>` implements `QueryFragment<DB, PgLikeReturningClause>`
`ReturningClause<Expr>` implements `QueryFragment<DB>`
= note: required for `ReturningClause<_>` to implement `QueryFragment<<Conn as Connection>::Backend>`
= note: 1 redundant requirement hidden
= note: required for `UpdateStatement<_, _, _, ReturningClause<_>>` to implement `QueryFragment<<Conn as Connection>::Backend>`
= note: required for `UpdateStatement<_, _, _>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, _>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
error[E0277]: the trait bound `Conn: LoadConnection` is not satisfied
--> src/base/service.rs:86:25
|
86 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `LoadConnection` is not implemented for `Conn`, which is required by `UpdateStatement<_, _, _>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `PooledConnection<ConnectionManager<Conn>>` to implement `LoadConnection`
= note: required for `UpdateStatement<_, _, _>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, _>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
help: consider further restricting this bound
|
50 | Conn: diesel::Connection + R2D2Connection + 'static + diesel::connection::LoadConnection,
| ++++++++++++++++++++++++++++++++++++
error[E0277]: the trait bound `<T as HasTable>::Table: SingleValue` is not satisfied
--> src/base/service.rs:86:25
|
86 | .get_result(&mut conn)
| ---------- ^^^^^^^^^ the trait `SingleValue` is not implemented for `<T as HasTable>::Table`, which is required by `UpdateStatement<_, _, _>: LoadQuery<'_, _, _>`
| |
| required by a bound introduced by this call
|
= note: required for `<T as HasTable>::Table` to implement `SqlTypeOrSelectable`
= note: required for `T` to implement `FromSqlRow<<T as HasTable>::Table, <Conn as Connection>::Backend>`
= note: required for `UpdateStatement<_, _, _>` to implement `LoadQuery<'_, PooledConnection<ConnectionManager<Conn>>, T>`
note: required by a bound in `get_result`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1722:15
|
1720 | fn get_result<'query, U>(self, conn: &mut Conn) -> QueryResult<U>
| ---------- required by a bound in this associated function
1721 | where
1722 | Self: LoadQuery<'query, Conn, U>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_result`
error[E0277]: the trait bound `<T as HasTable>::Table: diesel::Identifiable` is not satisfied
--> src/base/service.rs:83:9
|
83 | diesel::update(<T as HasTable>::table())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Identifiable` is not implemented for `<T as HasTable>::Table`, which is required by `<T as HasTable>::Table: IntoUpdateTarget`
|
= note: required for `<T as HasTable>::Table` to implement `IntoUpdateTarget`
error[E0277]: the trait bound `<T as HasTable>::Table: IntoUpdateTarget` is not satisfied
--> src/base/service.rs:92:24
|
92 | diesel::delete(<T as HasTable>::table())
| -------------- ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Identifiable` is not implemented for `<T as HasTable>::Table`, which is required by `<T as HasTable>::Table: IntoUpdateTarget`
| |
| required by a bound introduced by this call
|
= note: required for `<T as HasTable>::Table` to implement `IntoUpdateTarget`
note: required by a bound in `delete`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_builder/functions.rs:132:18
|
132 | pub fn delete<T: IntoUpdateTarget>(source: T) -> DeleteStatement<T::Table, T::WhereClause> {
| ^^^^^^^^^^^^^^^^ required by this bound in `delete`
error[E0277]: the trait bound `<T as HasTable>::Table: HasTable` is not satisfied
--> src/base/service.rs:92:9
|
92 | diesel::delete(<T as HasTable>::table())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasTable` is not implemented for `<T as HasTable>::Table`
error[E0277]: the trait bound `<T as Model>::PrimaryKey: AppearsOnTable<_>` is not satisfied
--> src/base/service.rs:93:14
|
93 | .filter(T::primary_key().eq(id))
| ^^^^^^ the trait `AppearsOnTable<_>` is not implemented for `<T as Model>::PrimaryKey`, which is required by `DeleteStatement<_, _>: FilterDsl<_>`
|
= help: the following other types implement trait `AppearsOnTable<QS>`:
`&'a T` implements `AppearsOnTable<QS>`
`(T0, T1)` implements `AppearsOnTable<QS>`
`(T0, T1, T2)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6, T7)` implements `AppearsOnTable<QS>`
and 131 others
= note: required for `diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>` to implement `AppearsOnTable<_>`
= note: 1 redundant requirement hidden
= note: required for `Grouped<Eq<<T as Model>::PrimaryKey, Bound<Integer, i32>>>` to implement `AppearsOnTable<_>`
= note: required for `DeleteStatement<_, _>` to implement `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>>>`
= note: the full name for the type has been written to '/home/nicolaivds/GIT/OpenLayerHub/target/debug/deps/openlayerhub-1f7d339452a03941.long-type-9065444121950834043.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0277]: the trait bound `<T as Model>::PrimaryKey: AppearsOnTable<_>` is not satisfied
--> src/base/service.rs:93:21
|
93 | .filter(T::primary_key().eq(id))
| ------ ^^^^^^^^^^^^^^^^^^^^^^^ the trait `AppearsOnTable<_>` is not implemented for `<T as Model>::PrimaryKey`, which is required by `DeleteStatement<_, _>: FilterDsl<_>`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `AppearsOnTable<QS>`:
`&'a T` implements `AppearsOnTable<QS>`
`(T0, T1)` implements `AppearsOnTable<QS>`
`(T0, T1, T2)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6)` implements `AppearsOnTable<QS>`
`(T0, T1, T2, T3, T4, T5, T6, T7)` implements `AppearsOnTable<QS>`
and 131 others
= note: required for `diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>` to implement `AppearsOnTable<_>`
= note: 1 redundant requirement hidden
= note: required for `Grouped<Eq<<T as Model>::PrimaryKey, Bound<Integer, i32>>>` to implement `AppearsOnTable<_>`
= note: required for `DeleteStatement<_, _>` to implement `FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Eq<<T as Model>::PrimaryKey, diesel::expression::bound::Bound<Integer, i32>>>>`
note: required by a bound in `DeleteStatement::<T, U>::filter`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_builder/delete_statement/mod.rs:113:15
|
111 | pub fn filter<Predicate>(self, predicate: Predicate) -> Filter<Self, Predicate>
| ------ required by a bound in this associated function
112 | where
113 | Self: FilterDsl<Predicate>,
| ^^^^^^^^^^^^^^^^^^^^ required by this bound in `DeleteStatement::<T, U>::filter`
= note: the full name for the type has been written to '/home/nicolaivds/GIT/OpenLayerHub/target/debug/deps/openlayerhub-1f7d339452a03941.long-type-9065444121950834043.txt'
= note: consider using `--verbose` to print the full type name to the console
error[E0277]: the trait bound `<Conn as Connection>::Backend: DieselReserveSpecialization` is not satisfied
--> src/base/service.rs:94:22
|
94 | .execute(&mut conn)
| ------- ^^^^^^^^^ the trait `DieselReserveSpecialization` is not implemented for `<Conn as Connection>::Backend`, which is required by `DeleteStatement<_, _>: ExecuteDsl<_, _>`
| |
| required by a bound introduced by this call
|
= note: required for `DeleteStatement<_, _>` to implement `QueryFragment<<Conn as Connection>::Backend>`
= note: required for `DeleteStatement<_, _>` to implement `ExecuteDsl<PooledConnection<ConnectionManager<Conn>>, <Conn as Connection>::Backend>`
note: required by a bound in `diesel::RunQueryDsl::execute`
--> /home/nicolaivds/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-2.2.7/src/query_dsl/mod.rs:1431:15
|
1428 | fn execute(self, conn: &mut Conn) -> QueryResult<usize>
| ------- required by a bound in this associated function
...
1431 | Self: methods::ExecuteDsl<Conn>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::execute`
error[E0277]: the trait bound `<T as HasTable>::Table: diesel::Identifiable` is not satisfied
--> src/base/service.rs:92:9
|
92 | diesel::delete(<T as HasTable>::table())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `diesel::Identifiable` is not implemented for `<T as HasTable>::Table`, which is required by `<T as HasTable>::Table: IntoUpdateTarget`
|
= note: required for `<T as HasTable>::Table` to implement `IntoUpdateTarget`
Some errors have detailed explanations: E0275, E0277.
For more information about an error, try `rustc --explain E0275`.
error: could not compile `openlayerhub` (bin "openlayerhub") due to 26 previous errors

2400
migration/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +0,0 @@
[package]
name = "migration"
version = "0.1.0"
edition = "2021"
publish = false
[lib]
name = "migration"
path = "src/lib.rs"
[dependencies]
async-std = { version = "1", features = ["attributes", "tokio1"] }
[dependencies.sea-orm-migration]
version = "1.1.0"
features = [
# Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI.
# View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime.
# e.g.
"runtime-tokio-rustls", # `ASYNC_RUNTIME` feature
"sqlx-sqlite", # `DATABASE_DRIVER` feature
]

View File

@ -1,41 +0,0 @@
# Running Migrator CLI
- Generate a new migration file
```sh
cargo run -- generate MIGRATION_NAME
```
- Apply all pending migrations
```sh
cargo run
```
```sh
cargo run -- up
```
- Apply first 10 pending migrations
```sh
cargo run -- up -n 10
```
- Rollback last applied migrations
```sh
cargo run -- down
```
- Rollback last 10 applied migrations
```sh
cargo run -- down -n 10
```
- Drop all tables from the database, then reapply all migrations
```sh
cargo run -- fresh
```
- Rollback all applied migrations, then reapply all migrations
```sh
cargo run -- refresh
```
- Rollback all applied migrations
```sh
cargo run -- reset
```
- Check the status of all migrations
```sh
cargo run -- status
```

View File

@ -1,14 +0,0 @@
pub use sea_orm_migration::prelude::*;
mod m20220101_000001_create_table;
pub struct Migrator;
#[async_trait::async_trait]
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(m20220101_000001_create_table::Migration),
]
}
}

View File

@ -1,41 +0,0 @@
use sea_orm_migration::{prelude::*, schema::*};
#[derive(DeriveMigrationName)]
pub struct Migration;
#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Replace the sample below with your own migration scripts
todo!();
manager
.create_table(
Table::create()
.table(Post::Table)
.if_not_exists()
.col(pk_auto(Post::Id))
.col(string(Post::Title))
.col(string(Post::Text))
.to_owned(),
)
.await
}
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// Replace the sample below with your own migration scripts
todo!();
manager
.drop_table(Table::drop().table(Post::Table).to_owned())
.await
}
}
#[derive(DeriveIden)]
enum Post {
Table,
Id,
Title,
Text,
}

View File

@ -1,6 +0,0 @@
use sea_orm_migration::prelude::*;
#[async_std::main]
async fn main() {
cli::run_cli(migration::Migrator).await;
}

0
migrations/.keep Normal file
View File

View File

@ -0,0 +1,6 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
DROP FUNCTION IF EXISTS diesel_set_updated_at();

View File

@ -0,0 +1,36 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.
-- Sets up a trigger for the given table to automatically set a column called
-- `updated_at` whenever the row is modified (unless `updated_at` was included
-- in the modified columns)
--
-- # Example
--
-- ```sql
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
--
-- SELECT diesel_manage_updated_at('users');
-- ```
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
BEGIN
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
END;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
BEGIN
IF (
NEW IS DISTINCT FROM OLD AND
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
) THEN
NEW.updated_at := current_timestamp;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;

View File

@ -0,0 +1 @@
DROP TABLE users;

View File

@ -0,0 +1,5 @@
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL,
email VARCHAR NOT NULL UNIQUE
);

View File

@ -1,34 +1,33 @@
use crate::{base::service::BaseService, utils::errors::AppError}; use anyhow::Result;
use axum::{http::StatusCode, response::IntoResponse, Json}; use axum::{http::StatusCode, response::IntoResponse, Json};
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, ModelTrait}; use diesel::Identifiable;
use serde::Serialize;
use std::marker::PhantomData;
use crate::base::{entity::BaseEntity, i_service::IBaseService};
pub struct BaseController<Entity, Model, ActiveModel> pub struct BaseController<T, S>
where where
Entity: EntityTrait, T: BaseEntity + Identifiable<Id = i32> + Serialize + Send + Sync + 'static,
Model: ModelTrait + Send + Sync + 'static, S: IBaseService<T> + Send + Sync + 'static,
ActiveModel: ActiveModelTrait + Send + Sync + 'static,
{ {
service: BaseService<Entity, Model, ActiveModel>, service: S,
_marker: PhantomData<T>,
} }
impl<Entity, Model, ActiveModel> BaseController<Entity, Model, ActiveModel> impl<T, S> BaseController<T, S>
where where
Entity: EntityTrait, T: BaseEntity + Identifiable<Id = i32> + Serialize + Send + Sync + 'static,
Model: ModelTrait + Send + Sync + 'static, S: IBaseService<T> + Send + Sync + 'static,
ActiveModel: ActiveModelTrait + Send + Sync + 'static,
{ {
pub fn new() -> Self { pub fn new(service: S) -> Self {
Self { Self {
service: BaseService::new(), service,
_marker: PhantomData,
} }
} }
pub async fn create( pub async fn get_all(&self) -> Result<impl IntoResponse> {
&self, let entities = self.service.get_all().await?;
state: State<DatabaseConnection>, Ok((StatusCode::OK, Json(entities)))
Json(data): Json<ActiveModel>,
) -> Result<IntoResponse, AppError> {
let model = self.service.create(&state, data).await?;
Ok((StatusCode::CREATED, Json(model)))
} }
} }

View File

@ -1,10 +1,17 @@
use sea_orm::entity::prelude::*; use diesel::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel, Serialize, Deserialize)] pub trait BaseEntity {
pub struct BaseEntity { fn id(&self) -> i32;
#[sea_orm(primary_key)] }
pub id: i32,
pub created_at: DateTime, #[derive(Serialize, Deserialize, Clone, Debug)]
pub updated_at: DateTime, pub struct Entity {
pub id: i32,
}
impl BaseEntity for Entity {
fn id(&self) -> i32 {
self.id
}
} }

View File

@ -1,22 +1,11 @@
use crate::utils::errors::AppError; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use sea_orm::{ActiveModelTrait, DatabaseConnection, EntityTrait, ModelTrait}; use diesel::Identifiable;
#[async_trait] #[async_trait]
pub trait IService<Entity, Model, ActiveModel> pub trait IBaseService<T>: Send + Sync
where where
Entity: EntityTrait, T: Identifiable<Id = i32> + Send + Sync + 'static
Model: ModelTrait + Send + Sync,
ActiveModel: ActiveModelTrait + Send + Sync,
{ {
async fn create(&self, db: &DatabaseConnection, data: ActiveModel) -> Result<Model, AppError>; async fn get_all(&self) -> Result<Vec<T>>;
async fn get_by_id(&self, db: &DatabaseConnection, id: i32) -> Result<Option<Model>, AppError>;
async fn get_all(&self, db: &DatabaseConnection) -> Result<Vec<Model>, AppError>;
async fn update(
&self,
db: &DatabaseConnection,
id: i32,
data: ActiveModel,
) -> Result<Model, AppError>;
async fn delete(&self, db: &DatabaseConnection, id: i32) -> Result<(), AppError>;
} }

View File

@ -1,4 +1,4 @@
pub mod controller;
pub mod entity;
pub mod i_service; pub mod i_service;
pub mod service; pub mod service;
pub mod controller;
pub mod entity;

View File

@ -1,84 +1,61 @@
use crate::base::i_service::IService; use std::marker::PhantomData;
use crate::utils::errors::AppError;
use async_trait::async_trait;
use sea_orm::{
ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, Order, QueryFilter,
QueryOrder, Set,
};
pub struct BaseService<Entity, Model, ActiveModel> use anyhow::Error;
use async_trait::async_trait;
use diesel::prelude::*;
use diesel::associations::HasTable;
use diesel::query_dsl::methods::LoadQuery;
use crate::config::db::DbPool;
use super::i_service::IBaseService;
pub struct BaseService<T, U>
where where
Entity: EntityTrait, T: Identifiable<Id = i32> + Queryable<U::SqlType, diesel::pg::Pg> + Send + Sync + 'static,
Model: ModelTrait + Send + Sync + 'static, U: Table + HasTable<Table = U> + LoadQuery<'static, PgConnection, T> + Send + Sync + 'static,
ActiveModel: ActiveModelTrait + Send + Sync + 'static,
{ {
entity: std::marker::PhantomData<Entity>, pool: DbPool,
_marker: PhantomData<(T, U)>,
} }
impl<Entity, Model, ActiveModel> BaseService<Entity, Model, ActiveModel> impl<T, U> BaseService<T, U>
where where
Entity: EntityTrait, T: Identifiable<Id = i32> + Queryable<U::SqlType, diesel::pg::Pg> + Send + Sync + 'static,
Model: ModelTrait + Send + Sync + 'static, U: Table
ActiveModel: ActiveModelTrait + Send + Sync + 'static, + HasTable<Table = U>
+ LoadQuery<'static, PgConnection, T>
+ Send
+ Sync
+ 'static,
{ {
pub fn new() -> Self { pub fn new(pool: DbPool) -> Self {
Self { Self {
entity: std::marker::PhantomData, pool,
_marker: PhantomData,
} }
} }
} }
#[async_trait] #[async_trait]
impl<Entity, Model, ActiveModel> IService<Entity, Model, ActiveModel> impl<T, U> IBaseService<T> for BaseService<T, U>
for BaseService<Entity, Model, ActiveModel>
where where
Entity: EntityTrait, T: Identifiable<Id = i32> + Queryable<U::SqlType, diesel::pg::Pg> + Send + Sync + 'static,
Model: ModelTrait + Send + Sync + 'static, U: Table
ActiveModel: ActiveModelTrait + Send + Sync + 'static, + HasTable<Table = U>
+ LoadQuery<'static, PgConnection, T>
+ Send
+ Sync
+ 'static,
{ {
async fn create(&self, db: &DatabaseConnection, data: ActiveModel) -> Result<Model, AppError> { async fn get_all(&self) -> Result<Vec<T>, Error> {
Ok(data.insert(db).await?) let pool = self.pool.clone();
let result = tokio::task::spawn_blocking(move || {
let mut conn = pool.get().expect("Failed to get DB connection");
U::table().load::<T>(&mut conn)
})
.await??;
Ok(result)
} }
}
async fn get_by_id(&self, db: &DatabaseConnection, id: i32) -> Result<Option<Model>, AppError> {
Ok(Entity::find_by_id(id).one(db).await?)
}
async fn get_all(&self, db: &DatabaseConnection) -> Result<Vec<Model>, AppError> {
Ok(Entity::find().all(db).await?)
}
async fn update(
&self,
db: &DatabaseConnection,
id: i32,
data: ActiveModel,
) -> Result<Model, AppError> {
let model = Entity::find_by_id(id)
.one(db)
.await?
.ok_or(AppError::NotFound)?;
let mut active_model: ActiveModel = model.into();
// Update fields individually, handling Optionals correctly:
// Example: Assume your Model has a 'name' field.
if let Some(name) = data.get_name() {
// Assuming ActiveModel has get_name()
active_model.set_name(name); // And set_name()
}
if let Some(description) = data.get_description() {
active_model.set_description(description);
}
// ... update other fields similarly ...
Ok(active_model.update(db).await?)
}
async fn delete(&self, db: &DatabaseConnection, id: i32) -> Result<(), AppError> {
let model = Entity::find_by_id(id)
.one(db)
.await?
.ok_or(AppError::NotFound)?;
Ok(model.delete(db).await?)
}
}

23
src/config/db.rs Normal file
View File

@ -0,0 +1,23 @@
use diesel::pg::PgConnection;
use diesel::r2d2::{self, ConnectionManager, Pool, PoolError};
use std::env;
pub type DbPool = Pool<ConnectionManager<PgConnection>>;
pub fn establish_connection_pool() -> Result<DbPool, PoolError> {
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let manager = ConnectionManager::<PgConnection>::new(database_url);
Pool::builder().build(manager)
}
pub fn get_connection(
pool: &DbPool,
) -> Result<r2d2::PooledConnection<ConnectionManager<PgConnection>>, PoolError> {
pool.get()
}
pub fn init_db() -> DbPool {
establish_connection_pool().expect("Failed to create connection pool")
}

1
src/config/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod db;

View File

@ -1,12 +1,26 @@
use dotenvy::dotenv; use std::sync::Arc;
use axum::{serve, Router};
use config::db::init_db;
use tokio::net::TcpListener;
use crate::routes::user::controller::UserController;
use crate::routes::user::service::UserService;
mod base; mod base;
mod config; mod config;
mod models;
mod routes; mod routes;
mod utils;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn , std::error::Error>> { async fn main() {
// let pool = init_db();
let user_service = UserService::new(pool);
let user_controller = Arc::new(UserController::new(user_service));
let app = Router::new()
.merge(UserController::routes())
.with_state(user_controller);
let listener = TcpListener::bind("0.0.0.0:3000").await.unwrap();
serve(listener, app).await.unwrap();
} }

1
src/routes/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod user;

View File

@ -1,61 +0,0 @@
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
use crate::base::entity::BaseEntity;
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Serialize, Deserialize)]
#[sea_orm(table_name = "product")]
pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub name: String,
pub description: Option<String>,
// ... other product-specific fields ...
pub created_at: DateTime,
pub updated_at: DateTime,
}
#[derive(Copy, Clone, Debug, DeriveRelation)]
pub enum Relation {}
impl ActiveModelBehavior for ActiveModel {}
// ActiveModel - CORRECT STRUCTURE (No DeriveModel!)
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ActiveModel {
pub id: sea_orm::ActiveValue<i32>,
pub name: sea_orm::ActiveValue<String>,
pub description: sea_orm::ActiveValue<Option<String>>,
// ... other fields ...
pub created_at: sea_orm::ActiveValue<DateTime>,
pub updated_at: sea_orm::ActiveValue<DateTime>,
}
impl Entity {
pub fn find_by_id(id: i32) -> Select<'static> {
Self::find().filter(Column::Id.eq(id))
}
}
// Implement get and set methods for the ActiveModel
impl ActiveModel {
pub fn get_name(&self) -> Option<String> {
match self.name {
sea_orm::ActiveValue::Set(val) => Some(val),
_ => None
}
}
pub fn set_name(&mut self, val: String) {
self.name = sea_orm::Set(val);
}
pub fn get_description(&self) -> Option<String> {
match self.description {
sea_orm::ActiveValue::Set(val) => Some(val),
_ => None
}
}
pub fn set_description(&mut self, val: String) {
self.description = sea_orm::Set(val);
}
}

View File

@ -0,0 +1,29 @@
use axum::Router;
use axum::routing::get;
use crate::base::controller::BaseController;
use super::model::User;
use super::service::UserService;
pub struct UserController {
base_controller: BaseController<User, UserService>,
}
impl UserController {
pub fn new(service: UserService) -> Self {
Self {
base_controller: BaseController::new(service),
}
}
pub fn routes() -> Router {
Router::new()
.route("/users", get(Self::get_users))
}
async fn get_users(
State(controller): State<Arc<UserController>>,
) -> impl IntoResponse {
controller.base_controller.get_all().await
}
}

4
src/routes/user/mod.rs Normal file
View File

@ -0,0 +1,4 @@
pub mod model;
pub mod schema;
pub mod service;
pub mod controller;

18
src/routes/user/model.rs Normal file
View File

@ -0,0 +1,18 @@
use diesel::prelude::*;
use serde::{Deserialize, Serialize};
use crate::base::entity::BaseEntity;
use super::schema::users;
#[derive(Debug, Clone, Serialize, Deserialize, Queryable, Identifiable)]
#[diesel(table_name = users)]
pub struct User {
pub id: i32,
pub name: String,
pub email: String,
}
impl BaseEntity for User {
fn id(&self) -> i32 {
self.id
}
}

View File

@ -0,0 +1,7 @@
diesel::table! {
users (id) {
id -> Int4,
name -> Varchar,
email -> Varchar,
}
}

View File

@ -0,0 +1,5 @@
use crate::base::service::BaseService;
use super::model::User;
use super::schema::users;
pub type UserService = BaseService<User, users::table>;

9
src/schema.rs Normal file
View File

@ -0,0 +1,9 @@
// @generated automatically by Diesel CLI.
diesel::table! {
users (id) {
id -> Int4,
name -> Varchar,
email -> Varchar,
}
}

View File

@ -1,73 +0,0 @@
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use sea_orm::error::DbErr;
use serde_json::json;
use std::error::Error as StdError;
#[derive(Debug, thiserror::Error)]
pub enum AppError {
#[error("Not Found")]
NotFound,
#[error("Bad Request: {0}")]
BadRequest(String),
#[error("Unauthorized")]
Unauthorized,
#[error("Internal Server Error: {0}")]
InternalServerError(String),
#[error("Database Error: {0}")]
DatabaseError(#[from] DbErr),
#[error("Other Error: {0}")]
Other(#[from] anyhow::Error), // For other errors using anyhow
}
// Implement the IntoResponse trait for AppError
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
AppError::NotFound => (StatusCode::NOT_FOUND, "Not Found".to_string()),
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized".to_string()),
AppError::InternalServerError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
AppError::DatabaseError(err) => {
// Log the database error for debugging (important!)
eprintln!("Database Error: {}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
"Database error occurred".to_string(),
)
}
AppError::Other(err) => {
eprintln!("Other Error: {}", err);
(
StatusCode::INTERNAL_SERVER_ERROR,
"An unexpected error occurred".to_string(),
)
}
};
let body = Json(json!({
"error": message,
}));
(status, body).into_response()
}
}
// You can create a From trait implementation if you have a custom error type
// and want to convert it into AppError. For example, if you had a
// `MyCustomError`:
// impl From<MyCustomError> for AppError {
// fn from(err: MyCustomError) -> Self {
// AppError::InternalServerError(err.to_string()) // Or map to a more specific AppError
// }
// }
// Example usage in your service:
// async fn my_service_function(...) -> Result<..., AppError> {
// let result = some_fallible_function().map_err(|e| AppError::BadRequest(e.to_string()))?;
// // ...
// }

View File

@ -1 +0,0 @@
pub mod errors;