Merge branch 'master' into transaction-3
This commit is contained in:
commit
7bc6477091
24
.github/workflows/rust.yml
vendored
24
.github/workflows/rust.yml
vendored
@ -177,7 +177,7 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
path: [async-std, tokio, actix_example, actix4_example, rocket_example]
|
path: [basic, actix_example, actix4_example, rocket_example]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
@ -193,6 +193,28 @@ jobs:
|
|||||||
args: >
|
args: >
|
||||||
--manifest-path examples/${{ matrix.path }}/Cargo.toml
|
--manifest-path examples/${{ matrix.path }}/Cargo.toml
|
||||||
|
|
||||||
|
issues:
|
||||||
|
name: Issues
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest]
|
||||||
|
path: [86]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: >
|
||||||
|
--manifest-path issues/${{ matrix.path }}/Cargo.toml
|
||||||
|
|
||||||
sqlite:
|
sqlite:
|
||||||
name: SQLite
|
name: SQLite
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
||||||
and this project adheres to [Semantic Versioning](http://semver.org/).
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
|
## 0.2.6 - 2021-10-09
|
||||||
|
|
||||||
|
- [[#224]] [sea-orm-cli] Date & Time column type mapping
|
||||||
|
- Escape rust keywords with `r#` raw identifier
|
||||||
|
|
||||||
|
[#224]: https://github.com/SeaQL/sea-orm/pull/224
|
||||||
|
|
||||||
## 0.2.5 - 2021-10-06
|
## 0.2.5 - 2021-10-06
|
||||||
|
|
||||||
- [[#227]] Resolve "Inserting actual none value of Option<Date> results in panic"
|
- [[#227]] Resolve "Inserting actual none value of Option<Date> results in panic"
|
||||||
|
@ -3,7 +3,7 @@ members = [".", "sea-orm-macros", "sea-orm-codegen"]
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "sea-orm"
|
name = "sea-orm"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
|
authors = ["Chris Tsang <tyt2y7@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "🐚 An async & dynamic ORM for Rust"
|
description = "🐚 An async & dynamic ORM for Rust"
|
||||||
@ -29,8 +29,8 @@ futures = { version = "^0.3" }
|
|||||||
futures-util = { version = "^0.3" }
|
futures-util = { version = "^0.3" }
|
||||||
log = { version = "^0.4", optional = true }
|
log = { version = "^0.4", optional = true }
|
||||||
rust_decimal = { version = "^1", optional = true }
|
rust_decimal = { version = "^1", optional = true }
|
||||||
sea-orm-macros = { version = "^0.2.5", path = "sea-orm-macros", optional = true }
|
sea-orm-macros = { version = "^0.2.6", path = "sea-orm-macros", optional = true }
|
||||||
sea-query = { version = "^0.17.0", features = ["thread-safe"] }
|
sea-query = { version = "^0.17.1", features = ["thread-safe"] }
|
||||||
sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] }
|
sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] }
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
serde_json = { version = "^1", optional = true }
|
serde_json = { version = "^1", optional = true }
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust.
|
SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust.
|
||||||
|
|
||||||
[](https://www.sea-ql.org/SeaORM/docs/index)
|
[](https://www.sea-ql.org/SeaORM/docs/index)
|
||||||
[](https://github.com/SeaQL/sea-orm/tree/master/examples/async-std)
|
[](https://github.com/SeaQL/sea-orm/tree/master/examples/basic)
|
||||||
[](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example)
|
[](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example)
|
||||||
[](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example)
|
[](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example)
|
||||||
[](https://discord.com/invite/uCPdDXzbdv)
|
[](https://discord.com/invite/uCPdDXzbdv)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
[package]
|
[package]
|
||||||
name = "sea-orm-cli"
|
name = "sea-orm-cli"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Command line utility for SeaORM"
|
description = "Command line utility for SeaORM"
|
||||||
@ -21,7 +21,7 @@ path = "src/main.rs"
|
|||||||
clap = { version = "^2.33.3" }
|
clap = { version = "^2.33.3" }
|
||||||
dotenv = { version = "^0.15" }
|
dotenv = { version = "^0.15" }
|
||||||
async-std = { version = "^1.9", features = [ "attributes" ] }
|
async-std = { version = "^1.9", features = [ "attributes" ] }
|
||||||
sea-orm-codegen = { version = "^0.2.5", path = "../sea-orm-codegen" }
|
sea-orm-codegen = { version = "^0.2.6", path = "../sea-orm-codegen" }
|
||||||
sea-schema = { version = "^0.2.9", default-features = false, features = [
|
sea-schema = { version = "^0.2.9", default-features = false, features = [
|
||||||
"debug-print",
|
"debug-print",
|
||||||
"sqlx-mysql",
|
"sqlx-mysql",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "sea-orm-codegen"
|
name = "sea-orm-codegen"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
authors = ["Billy Chan <ccw.billy.123@gmail.com>"]
|
authors = ["Billy Chan <ccw.billy.123@gmail.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Code Generator for SeaORM"
|
description = "Code Generator for SeaORM"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "sea-orm-macros"
|
name = "sea-orm-macros"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
authors = [ "Billy Chan <ccw.billy.123@gmail.com>" ]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
description = "Derive macros for SeaORM"
|
description = "Derive macros for SeaORM"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{future::Future, pin::Pin};
|
use std::{future::Future, pin::Pin};
|
||||||
|
|
||||||
use sqlx::{
|
use sqlx::{
|
||||||
sqlite::{SqliteArguments, SqliteQueryResult, SqliteRow},
|
sqlite::{SqliteArguments, SqlitePoolOptions, SqliteQueryResult, SqliteRow},
|
||||||
Sqlite, SqlitePool,
|
Sqlite, SqlitePool,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,7 +29,11 @@ impl SqlxSqliteConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn connect(string: &str) -> Result<DatabaseConnection, DbErr> {
|
pub async fn connect(string: &str) -> Result<DatabaseConnection, DbErr> {
|
||||||
if let Ok(pool) = SqlitePool::connect(string).await {
|
if let Ok(pool) = SqlitePoolOptions::new()
|
||||||
|
.max_connections(1)
|
||||||
|
.connect(string)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
Ok(DatabaseConnection::SqlxSqlitePoolConnection(
|
||||||
SqlxSqlitePoolConnection { pool },
|
SqlxSqlitePoolConnection { pool },
|
||||||
))
|
))
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::*, ConnectionTrait, DeleteResult, EntityTrait, Iterable, PrimaryKeyToColumn,
|
error::*, ConnectionTrait, DeleteResult, EntityTrait, Iterable, PrimaryKeyToColumn, Value,
|
||||||
PrimaryKeyTrait, Value,
|
|
||||||
};
|
};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use sea_query::ValueTuple;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
@ -10,7 +10,8 @@ pub struct ActiveValue<V>
|
|||||||
where
|
where
|
||||||
V: Into<Value>,
|
V: Into<Value>,
|
||||||
{
|
{
|
||||||
value: Option<V>,
|
// Don't want to call ActiveValue::unwrap() and cause panic
|
||||||
|
pub(self) value: Option<V>,
|
||||||
state: ActiveValueState,
|
state: ActiveValueState,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,6 +68,42 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
|
|
||||||
fn default() -> Self;
|
fn default() -> Self;
|
||||||
|
|
||||||
|
#[allow(clippy::question_mark)]
|
||||||
|
fn get_primary_key_value(&self) -> Option<ValueTuple> {
|
||||||
|
let mut cols = <Self::Entity as EntityTrait>::PrimaryKey::iter();
|
||||||
|
macro_rules! next {
|
||||||
|
() => {
|
||||||
|
if let Some(col) = cols.next() {
|
||||||
|
if let Some(val) = self.get(col.into_column()).value {
|
||||||
|
val
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
match <Self::Entity as EntityTrait>::PrimaryKey::iter().count() {
|
||||||
|
1 => {
|
||||||
|
let s1 = next!();
|
||||||
|
Some(ValueTuple::One(s1))
|
||||||
|
}
|
||||||
|
2 => {
|
||||||
|
let s1 = next!();
|
||||||
|
let s2 = next!();
|
||||||
|
Some(ValueTuple::Two(s1, s2))
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
let s1 = next!();
|
||||||
|
let s2 = next!();
|
||||||
|
let s3 = next!();
|
||||||
|
Some(ValueTuple::Three(s1, s2, s3))
|
||||||
|
}
|
||||||
|
_ => panic!("The arity cannot be larger than 3"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
async fn insert<'a, C>(self, db: &'a C) -> Result<Self, DbErr>
|
||||||
where
|
where
|
||||||
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
<Self::Entity as EntityTrait>::Model: IntoActiveModel<Self>,
|
||||||
@ -76,19 +113,12 @@ pub trait ActiveModelTrait: Clone + Debug {
|
|||||||
let am = self;
|
let am = self;
|
||||||
let exec = <Self::Entity as EntityTrait>::insert(am).exec(db);
|
let exec = <Self::Entity as EntityTrait>::insert(am).exec(db);
|
||||||
let res = exec.await?;
|
let res = exec.await?;
|
||||||
// Assume valid last_insert_id is not equals to Default::default()
|
let found = <Self::Entity as EntityTrait>::find_by_id(res.last_insert_id)
|
||||||
if res.last_insert_id
|
.one(db)
|
||||||
!= <<Self::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::ValueType::default()
|
.await?;
|
||||||
{
|
match found {
|
||||||
let found = <Self::Entity as EntityTrait>::find_by_id(res.last_insert_id)
|
Some(model) => Ok(model.into_active_model()),
|
||||||
.one(db)
|
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
|
||||||
.await?;
|
|
||||||
match found {
|
|
||||||
Some(model) => Ok(model.into_active_model()),
|
|
||||||
None => Err(DbErr::Exec("Failed to find inserted item".to_owned())),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(Self::default())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,23 +247,23 @@ where
|
|||||||
matches!(self.state, ActiveValueState::Unset)
|
matches!(self.state, ActiveValueState::Unset)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn take(&mut self) -> V {
|
pub fn take(&mut self) -> Option<V> {
|
||||||
self.state = ActiveValueState::Unset;
|
self.state = ActiveValueState::Unset;
|
||||||
self.value.take().unwrap()
|
self.value.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap(self) -> V {
|
pub fn unwrap(self) -> V {
|
||||||
self.value.unwrap()
|
self.value.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_value(self) -> Value {
|
pub fn into_value(self) -> Option<Value> {
|
||||||
self.value.unwrap().into()
|
self.value.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_wrapped_value(self) -> ActiveValue<Value> {
|
pub fn into_wrapped_value(self) -> ActiveValue<Value> {
|
||||||
match self.state {
|
match self.state {
|
||||||
ActiveValueState::Set => ActiveValue::set(self.into_value()),
|
ActiveValueState::Set => ActiveValue::set(self.into_value().unwrap()),
|
||||||
ActiveValueState::Unchanged => ActiveValue::unchanged(self.into_value()),
|
ActiveValueState::Unchanged => ActiveValue::unchanged(self.into_value().unwrap()),
|
||||||
ActiveValueState::Unset => ActiveValue::unset(),
|
ActiveValueState::Unset => ActiveValue::unset(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
use super::{ColumnTrait, IdenStatic, Iterable};
|
use super::{ColumnTrait, IdenStatic, Iterable};
|
||||||
use crate::{TryFromU64, TryGetableMany};
|
use crate::{TryFromU64, TryGetableMany};
|
||||||
use sea_query::IntoValueTuple;
|
use sea_query::{FromValueTuple, IntoValueTuple};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
//LINT: composite primary key cannot auto increment
|
//LINT: composite primary key cannot auto increment
|
||||||
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
pub trait PrimaryKeyTrait: IdenStatic + Iterable {
|
||||||
type ValueType: Sized
|
type ValueType: Sized
|
||||||
+ Send
|
+ Send
|
||||||
+ Default
|
|
||||||
+ Debug
|
+ Debug
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ IntoValueTuple
|
+ IntoValueTuple
|
||||||
|
+ FromValueTuple
|
||||||
+ TryGetableMany
|
+ TryGetableMany
|
||||||
+ TryFromU64;
|
+ TryFromU64;
|
||||||
|
|
||||||
|
@ -2,14 +2,15 @@ use crate::{
|
|||||||
error::*, ActiveModelTrait, ConnectionTrait, DbBackend, EntityTrait, Insert, PrimaryKeyTrait,
|
error::*, ActiveModelTrait, ConnectionTrait, DbBackend, EntityTrait, Insert, PrimaryKeyTrait,
|
||||||
Statement, TryFromU64,
|
Statement, TryFromU64,
|
||||||
};
|
};
|
||||||
use sea_query::InsertStatement;
|
use sea_query::{FromValueTuple, InsertStatement, ValueTuple};
|
||||||
use std::marker::PhantomData;
|
use std::{future::Future, marker::PhantomData};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Inserter<A>
|
pub struct Inserter<A>
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
|
primary_key: Option<ValueTuple>,
|
||||||
query: InsertStatement,
|
query: InsertStatement,
|
||||||
model: PhantomData<A>,
|
model: PhantomData<A>,
|
||||||
}
|
}
|
||||||
@ -27,12 +28,14 @@ where
|
|||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
pub async fn exec<'a, C>(self, db: &'a C) -> Result<InsertResult<A>, DbErr>
|
pub fn exec<'a, C>(
|
||||||
|
self,
|
||||||
|
db: &'a C,
|
||||||
|
) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + 'a
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
// TODO: extract primary key's value from query
|
|
||||||
// so that self is dropped before entering await
|
// so that self is dropped before entering await
|
||||||
let mut query = self.query;
|
let mut query = self.query;
|
||||||
if db.get_database_backend() == DbBackend::Postgres {
|
if db.get_database_backend() == DbBackend::Postgres {
|
||||||
@ -45,8 +48,7 @@ where
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inserter::<A>::new(query).exec(db).await
|
Inserter::<A>::new(self.primary_key, query).exec(db)
|
||||||
// TODO: return primary key if extracted before, otherwise use InsertResult
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,46 +56,59 @@ impl<A> Inserter<A>
|
|||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
pub fn new(query: InsertStatement) -> Self {
|
pub fn new(primary_key: Option<ValueTuple>, query: InsertStatement) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
primary_key,
|
||||||
query,
|
query,
|
||||||
model: PhantomData,
|
model: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn exec<'a, C>(self, db: &'a C) -> Result<InsertResult<A>, DbErr>
|
pub fn exec<'a, C>(
|
||||||
|
self,
|
||||||
|
db: &'a C,
|
||||||
|
) -> impl Future<Output = Result<InsertResult<A>, DbErr>> + 'a
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
A: 'a,
|
A: 'a,
|
||||||
{
|
{
|
||||||
let builder = db.get_database_backend();
|
let builder = db.get_database_backend();
|
||||||
exec_insert(builder.build(&self.query), db).await
|
exec_insert(self.primary_key, builder.build(&self.query), db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only Statement impl Send
|
// Only Statement impl Send
|
||||||
async fn exec_insert<'a, A, C>(statement: Statement, db: &C) -> Result<InsertResult<A>, DbErr>
|
async fn exec_insert<'a, A, C>(
|
||||||
|
primary_key: Option<ValueTuple>,
|
||||||
|
statement: Statement,
|
||||||
|
db: &'a C,
|
||||||
|
) -> Result<InsertResult<A>, DbErr>
|
||||||
where
|
where
|
||||||
C: ConnectionTrait<'a>,
|
C: ConnectionTrait<'a>,
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
type PrimaryKey<A> = <<A as ActiveModelTrait>::Entity as EntityTrait>::PrimaryKey;
|
||||||
type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
|
type ValueTypeOf<A> = <PrimaryKey<A> as PrimaryKeyTrait>::ValueType;
|
||||||
let last_insert_id = match db.get_database_backend() {
|
let last_insert_id_opt = match db.get_database_backend() {
|
||||||
DbBackend::Postgres => {
|
DbBackend::Postgres => {
|
||||||
use crate::{sea_query::Iden, Iterable};
|
use crate::{sea_query::Iden, Iterable};
|
||||||
let cols = PrimaryKey::<A>::iter()
|
let cols = PrimaryKey::<A>::iter()
|
||||||
.map(|col| col.to_string())
|
.map(|col| col.to_string())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let res = db.query_one(statement).await?.unwrap();
|
let res = db.query_one(statement).await?.unwrap();
|
||||||
res.try_get_many("", cols.as_ref()).unwrap_or_default()
|
res.try_get_many("", cols.as_ref()).ok()
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let last_insert_id = db.execute(statement).await?.last_insert_id();
|
let last_insert_id = db.execute(statement).await?.last_insert_id();
|
||||||
ValueTypeOf::<A>::try_from_u64(last_insert_id)
|
ValueTypeOf::<A>::try_from_u64(last_insert_id).ok()
|
||||||
.ok()
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let last_insert_id = match last_insert_id_opt {
|
||||||
|
Some(last_insert_id) => last_insert_id,
|
||||||
|
None => match primary_key {
|
||||||
|
Some(value_tuple) => FromValueTuple::from_value_tuple(value_tuple),
|
||||||
|
None => return Err(DbErr::Exec("Fail to unpack last_insert_id".to_owned())),
|
||||||
|
},
|
||||||
|
};
|
||||||
Ok(InsertResult { last_insert_id })
|
Ok(InsertResult { last_insert_id })
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
//! SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust.
|
//! SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust.
|
||||||
//!
|
//!
|
||||||
//! [](https://www.sea-ql.org/SeaORM/docs/index)
|
//! [](https://www.sea-ql.org/SeaORM/docs/index)
|
||||||
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/async-std)
|
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/basic)
|
||||||
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example)
|
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/actix_example)
|
||||||
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example)
|
//! [](https://github.com/SeaQL/sea-orm/tree/master/examples/rocket_example)
|
||||||
//! [](https://discord.com/invite/uCPdDXzbdv)
|
//! [](https://discord.com/invite/uCPdDXzbdv)
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
use crate::{ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, QueryTrait};
|
use crate::{
|
||||||
|
ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, PrimaryKeyTrait,
|
||||||
|
QueryTrait,
|
||||||
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use sea_query::InsertStatement;
|
use sea_query::{InsertStatement, ValueTuple};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Insert<A>
|
pub struct Insert<A>
|
||||||
where
|
where
|
||||||
A: ActiveModelTrait,
|
A: ActiveModelTrait,
|
||||||
{
|
{
|
||||||
pub(crate) query: InsertStatement,
|
pub(crate) query: InsertStatement,
|
||||||
pub(crate) columns: Vec<bool>,
|
pub(crate) columns: Vec<bool>,
|
||||||
|
pub(crate) primary_key: Option<ValueTuple>,
|
||||||
pub(crate) model: PhantomData<A>,
|
pub(crate) model: PhantomData<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +35,7 @@ where
|
|||||||
.into_table(A::Entity::default().table_ref())
|
.into_table(A::Entity::default().table_ref())
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
columns: Vec::new(),
|
columns: Vec::new(),
|
||||||
|
primary_key: None,
|
||||||
model: PhantomData,
|
model: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,6 +112,12 @@ where
|
|||||||
M: IntoActiveModel<A>,
|
M: IntoActiveModel<A>,
|
||||||
{
|
{
|
||||||
let mut am: A = m.into_active_model();
|
let mut am: A = m.into_active_model();
|
||||||
|
self.primary_key =
|
||||||
|
if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
|
||||||
|
am.get_primary_key_value()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
let mut columns = Vec::new();
|
let mut columns = Vec::new();
|
||||||
let mut values = Vec::new();
|
let mut values = Vec::new();
|
||||||
let columns_empty = self.columns.is_empty();
|
let columns_empty = self.columns.is_empty();
|
||||||
@ -120,7 +131,7 @@ where
|
|||||||
}
|
}
|
||||||
if av_has_val {
|
if av_has_val {
|
||||||
columns.push(col);
|
columns.push(col);
|
||||||
values.push(av.into_value());
|
values.push(av.into_value().unwrap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.query.columns(columns);
|
self.query.columns(columns);
|
||||||
|
@ -58,11 +58,7 @@ pub async fn test_create_cake(db: &DbConn) {
|
|||||||
.expect("could not insert cake_baker");
|
.expect("could not insert cake_baker");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake_baker_res.last_insert_id,
|
cake_baker_res.last_insert_id,
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
||||||
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(cake.is_some());
|
assert!(cake.is_some());
|
||||||
|
@ -57,11 +57,7 @@ pub async fn test_create_lineitem(db: &DbConn) {
|
|||||||
.expect("could not insert cake_baker");
|
.expect("could not insert cake_baker");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake_baker_res.last_insert_id,
|
cake_baker_res.last_insert_id,
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
||||||
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Customer
|
// Customer
|
||||||
|
@ -57,11 +57,7 @@ pub async fn test_create_order(db: &DbConn) {
|
|||||||
.expect("could not insert cake_baker");
|
.expect("could not insert cake_baker");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake_baker_res.last_insert_id,
|
cake_baker_res.last_insert_id,
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
||||||
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Customer
|
// Customer
|
||||||
|
@ -84,11 +84,7 @@ async fn init_setup(db: &DatabaseConnection) {
|
|||||||
.expect("could not insert cake_baker");
|
.expect("could not insert cake_baker");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake_baker_res.last_insert_id,
|
cake_baker_res.last_insert_id,
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
||||||
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let customer_kate = customer::ActiveModel {
|
let customer_kate = customer::ActiveModel {
|
||||||
@ -225,11 +221,7 @@ async fn create_cake(db: &DatabaseConnection, baker: baker::Model) -> Option<cak
|
|||||||
.expect("could not insert cake_baker");
|
.expect("could not insert cake_baker");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake_baker_res.last_insert_id,
|
cake_baker_res.last_insert_id,
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
||||||
(cake_baker.cake_id.unwrap(), cake_baker.baker_id.unwrap())
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Cake::find_by_id(cake_insert_res.last_insert_id)
|
Cake::find_by_id(cake_insert_res.last_insert_id)
|
||||||
|
@ -34,14 +34,7 @@ pub async fn create_metadata(db: &DatabaseConnection) -> Result<(), DbErr> {
|
|||||||
|
|
||||||
assert_eq!(Metadata::find().one(db).await?, Some(metadata.clone()));
|
assert_eq!(Metadata::find().one(db).await?, Some(metadata.clone()));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(res.last_insert_id, metadata.uuid);
|
||||||
res.last_insert_id,
|
|
||||||
if cfg!(feature = "sqlx-postgres") {
|
|
||||||
metadata.uuid
|
|
||||||
} else {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
let update_res = Metadata::update(metadata::ActiveModel {
|
let update_res = Metadata::update(metadata::ActiveModel {
|
||||||
value: Set("0.22".to_owned()),
|
value: Set("0.22".to_owned()),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user