sea_orm/query/
insert.rs

1use crate::{
2    ActiveModelTrait, ActiveValue, ColumnTrait, EntityName, EntityTrait, IntoActiveModel, Iterable,
3    PrimaryKeyTrait, QueryTrait,
4};
5use core::marker::PhantomData;
6use sea_query::{Expr, InsertStatement, Keyword, OnConflict, SimpleExpr, Value, ValueTuple};
7
8/// Performs INSERT operations on a ActiveModel
9#[derive(Debug)]
10pub struct Insert<A>
11where
12    A: ActiveModelTrait,
13{
14    pub(crate) query: InsertStatement,
15    pub(crate) primary_key: Option<ValueTuple>,
16    pub(crate) model: PhantomData<A>,
17}
18
19/// Performs INSERT operations on many ActiveModels
20#[derive(Debug)]
21pub struct InsertMany<A>
22where
23    A: ActiveModelTrait,
24{
25    pub(crate) query: InsertStatement,
26    pub(crate) primary_key: Option<ValueTuple>,
27    pub(crate) empty: bool,
28    pub(crate) model: PhantomData<A>,
29}
30
31/// Performs INSERT operations on one or more ActiveModels, will do nothing if input is empty.
32///
33/// All interfaces works the same as `Insert<A>`.
34#[derive(Debug)]
35pub struct TryInsert<A>
36where
37    A: ActiveModelTrait,
38{
39    pub(crate) insert_struct: Insert<A>,
40    pub(crate) empty: bool,
41}
42
43impl<A> Insert<A>
44where
45    A: ActiveModelTrait,
46{
47    /// Insert one Model or ActiveModel
48    ///
49    /// Model
50    /// ```
51    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
52    ///
53    /// assert_eq!(
54    ///     Insert::one(cake::Model {
55    ///         id: 1,
56    ///         name: "Apple Pie".to_owned(),
57    ///     })
58    ///     .build(DbBackend::Postgres)
59    ///     .to_string(),
60    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
61    /// );
62    /// ```
63    /// ActiveModel
64    /// ```
65    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
66    ///
67    /// assert_eq!(
68    ///     Insert::one(cake::ActiveModel {
69    ///         id: NotSet,
70    ///         name: Set("Apple Pie".to_owned()),
71    ///     })
72    ///     .build(DbBackend::Postgres)
73    ///     .to_string(),
74    ///     r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
75    /// );
76    /// ```
77    pub fn one<M>(m: M) -> Self
78    where
79        M: IntoActiveModel<A>,
80    {
81        let mut query = InsertStatement::new();
82        query
83            .into_table(A::Entity::default().table_ref())
84            .or_default_values();
85
86        let mut am: A = m.into_active_model();
87        let primary_key =
88            if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
89                am.get_primary_key_value()
90            } else {
91                None
92            };
93        let mut columns = Vec::new();
94        let mut values = Vec::new();
95
96        for col in <A::Entity as EntityTrait>::Column::iter() {
97            let av = am.take(col);
98
99            match av {
100                ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
101                    columns.push(col);
102                    values.push(col.save_as(Expr::val(value)));
103                }
104                ActiveValue::NotSet => {}
105            }
106        }
107
108        query.columns(columns);
109        query.values_panic(values);
110
111        Self {
112            query,
113            primary_key,
114            model: PhantomData,
115        }
116    }
117
118    /// Insert many Model or ActiveModel.
119    /// Alias to [`InsertMany::many`].
120    ///
121    /// ```
122    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
123    ///
124    /// assert_eq!(
125    ///     Insert::many([
126    ///         cake::Model {
127    ///             id: 1,
128    ///             name: "Apple Pie".to_owned(),
129    ///         },
130    ///         cake::Model {
131    ///             id: 2,
132    ///             name: "Orange Scone".to_owned(),
133    ///         }
134    ///     ])
135    ///     .build(DbBackend::Postgres)
136    ///     .to_string(),
137    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#,
138    /// );
139    /// ```
140    pub fn many<M, I>(models: I) -> InsertMany<A>
141    where
142        M: IntoActiveModel<A>,
143        I: IntoIterator<Item = M>,
144    {
145        InsertMany::many(models)
146    }
147
148    /// Set ON CONFLICT logic
149    ///
150    /// on conflict do nothing
151    /// ```
152    /// use sea_orm::{DbBackend, entity::*, query::*, sea_query::OnConflict, tests_cfg::cake};
153    ///
154    /// let orange = cake::ActiveModel {
155    ///     id: ActiveValue::set(2),
156    ///     name: ActiveValue::set("Orange".to_owned()),
157    /// };
158    /// assert_eq!(
159    ///     cake::Entity::insert(orange)
160    ///         .on_conflict(
161    ///             OnConflict::column(cake::Column::Name)
162    ///                 .do_nothing()
163    ///                 .to_owned()
164    ///         )
165    ///         .build(DbBackend::Postgres)
166    ///         .to_string(),
167    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO NOTHING"#,
168    /// );
169    /// ```
170    ///
171    /// on conflict do update (upsert)
172    /// ```
173    /// use sea_orm::{entity::*, query::*, sea_query::OnConflict, tests_cfg::cake, DbBackend};
174    ///
175    /// let orange = cake::ActiveModel {
176    ///     id: ActiveValue::set(2),
177    ///     name: ActiveValue::set("Orange".to_owned()),
178    /// };
179    /// let query = cake::Entity::insert(orange)
180    ///     .on_conflict(
181    ///         OnConflict::column(cake::Column::Name)
182    ///             .update_column(cake::Column::Name)
183    ///             .to_owned()
184    ///     );
185    /// assert_eq!(
186    ///     query
187    ///         .build(DbBackend::MySql)
188    ///         .to_string(),
189    ///     "INSERT INTO `cake` (`id`, `name`) VALUES (2, 'Orange') ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)"
190    /// );
191    /// assert_eq!(
192    ///     query
193    ///         .build(DbBackend::Postgres)
194    ///         .to_string(),
195    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO UPDATE SET "name" = "excluded"."name""#,
196    /// );
197    /// assert_eq!(
198    ///     query
199    ///         .build(DbBackend::Sqlite)
200    ///         .to_string(),
201    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO UPDATE SET "name" = "excluded"."name""#,
202    /// );
203    /// ```
204    pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
205        self.query.on_conflict(on_conflict);
206        self
207    }
208
209    /// Allow insert statement to return without error if nothing's been inserted
210    pub fn do_nothing(self) -> TryInsert<A>
211    where
212        A: ActiveModelTrait,
213    {
214        TryInsert::from_one(self)
215    }
216
217    /// Alias to `do_nothing`
218    pub fn on_empty_do_nothing(self) -> TryInsert<A>
219    where
220        A: ActiveModelTrait,
221    {
222        TryInsert::from_one(self)
223    }
224
225    /// Set ON CONFLICT on primary key do nothing, but with MySQL specific polyfill.
226    ///
227    /// ```
228    /// use sea_orm::{entity::*, query::*, sea_query::OnConflict, tests_cfg::cake, DbBackend};
229    ///
230    /// let orange = cake::ActiveModel {
231    ///     id: ActiveValue::set(2),
232    ///     name: ActiveValue::set("Orange".to_owned()),
233    /// };
234    ///
235    /// assert_eq!(
236    ///     cake::Entity::insert(orange.clone())
237    ///         .on_conflict_do_nothing()
238    ///         .build(DbBackend::MySql)
239    ///         .to_string(),
240    ///     r#"INSERT INTO `cake` (`id`, `name`) VALUES (2, 'Orange') ON DUPLICATE KEY UPDATE `id` = `id`"#,
241    /// );
242    /// assert_eq!(
243    ///     cake::Entity::insert(orange.clone())
244    ///         .on_conflict_do_nothing()
245    ///         .build(DbBackend::Postgres)
246    ///         .to_string(),
247    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("id") DO NOTHING"#,
248    /// );
249    /// assert_eq!(
250    ///     cake::Entity::insert(orange)
251    ///         .on_conflict_do_nothing()
252    ///         .build(DbBackend::Sqlite)
253    ///         .to_string(),
254    ///     r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("id") DO NOTHING"#,
255    /// );
256    /// ```
257    pub fn on_conflict_do_nothing(mut self) -> TryInsert<A>
258    where
259        A: ActiveModelTrait,
260    {
261        self.query.on_conflict(on_conflict_primary_key::<A>());
262
263        TryInsert::from_one(self)
264    }
265}
266
267impl<A> InsertMany<A>
268where
269    A: ActiveModelTrait,
270{
271    /// Insert many Model or ActiveModel
272    pub fn many<M, I>(models: I) -> Self
273    where
274        M: IntoActiveModel<A>,
275        I: IntoIterator<Item = M>,
276    {
277        let mut query = InsertStatement::new();
278        query.into_table(A::Entity::default().table_ref());
279
280        let mut columns: Vec<_> = <A::Entity as EntityTrait>::Column::iter()
281            .map(|_| None)
282            .collect();
283        let mut null_value: Vec<Option<Value>> = std::iter::repeat_n(None, columns.len()).collect();
284        let mut all_values: Vec<Vec<SimpleExpr>> = Vec::new();
285        let mut primary_key = None;
286
287        for model in models.into_iter() {
288            let mut am: A = model.into_active_model();
289            primary_key =
290                if !<<A::Entity as EntityTrait>::PrimaryKey as PrimaryKeyTrait>::auto_increment() {
291                    am.get_primary_key_value()
292                } else {
293                    None
294                };
295            let mut values = Vec::with_capacity(columns.len());
296            for (idx, col) in <A::Entity as EntityTrait>::Column::iter().enumerate() {
297                let av = am.take(col);
298                match av {
299                    ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
300                        columns[idx] = Some(col); // mark the column as used
301                        null_value[idx] = Some(value.as_null()); // store the null value with the correct type
302                        values.push(col.save_as(Expr::val(value))); // same as add() above
303                    }
304                    ActiveValue::NotSet => {
305                        values.push(SimpleExpr::Keyword(Keyword::Null)); // indicate a missing value
306                    }
307                }
308            }
309            all_values.push(values);
310        }
311
312        let empty = all_values.is_empty();
313
314        if !all_values.is_empty() {
315            // filter only used column
316            query.columns(columns.iter().cloned().flatten());
317        }
318
319        for values in all_values {
320            // since we've aligned the column set, this never panics
321            query.values_panic(values.into_iter().enumerate().filter_map(|(i, v)| {
322                if columns[i].is_some() {
323                    // only if the column is used
324                    if !matches!(v, SimpleExpr::Keyword(Keyword::Null)) {
325                        // use the value expression
326                        Some(v)
327                    } else {
328                        // use null as standin, which must be Some
329                        null_value[i].clone().map(SimpleExpr::Value)
330                    }
331                } else {
332                    None
333                }
334            }));
335        }
336
337        Self {
338            query,
339            primary_key,
340            empty,
341            model: PhantomData,
342        }
343    }
344
345    /// Set ON CONFLICT logic
346    pub fn on_conflict(mut self, on_conflict: OnConflict) -> Self {
347        self.query.on_conflict(on_conflict);
348        self
349    }
350
351    /// Allow insert statement to return without error if nothing's been inserted
352    pub fn do_nothing(self) -> TryInsert<A>
353    where
354        A: ActiveModelTrait,
355    {
356        TryInsert::from_many(self)
357    }
358
359    /// Alias to `do_nothing`
360    pub fn on_empty_do_nothing(self) -> TryInsert<A>
361    where
362        A: ActiveModelTrait,
363    {
364        TryInsert::from_many(self)
365    }
366
367    /// Set ON CONFLICT on primary key do nothing, but with MySQL specific polyfill.
368    /// See also [`Insert::on_conflict_do_nothing`].
369    pub fn on_conflict_do_nothing(mut self) -> TryInsert<A>
370    where
371        A: ActiveModelTrait,
372    {
373        self.query.on_conflict(on_conflict_primary_key::<A>());
374
375        TryInsert::from_many(self)
376    }
377
378    /// panic when self is empty
379    pub(crate) fn into_one(self) -> Insert<A> {
380        assert!(!self.empty);
381
382        let Self {
383            query,
384            primary_key,
385            empty: _,
386            model,
387        } = self;
388
389        Insert {
390            query,
391            primary_key,
392            model,
393        }
394    }
395}
396
397impl<A> QueryTrait for Insert<A>
398where
399    A: ActiveModelTrait,
400{
401    type QueryStatement = InsertStatement;
402
403    fn query(&mut self) -> &mut InsertStatement {
404        &mut self.query
405    }
406
407    fn as_query(&self) -> &InsertStatement {
408        &self.query
409    }
410
411    fn into_query(self) -> InsertStatement {
412        self.query
413    }
414}
415
416impl<A> QueryTrait for InsertMany<A>
417where
418    A: ActiveModelTrait,
419{
420    type QueryStatement = InsertStatement;
421
422    fn query(&mut self) -> &mut InsertStatement {
423        &mut self.query
424    }
425
426    fn as_query(&self) -> &InsertStatement {
427        &self.query
428    }
429
430    fn into_query(self) -> InsertStatement {
431        self.query
432    }
433}
434
435impl<A> TryInsert<A>
436where
437    A: ActiveModelTrait,
438{
439    fn from_one(insert: Insert<A>) -> Self {
440        Self {
441            insert_struct: insert,
442            empty: false,
443        }
444    }
445
446    fn from_many(insert: InsertMany<A>) -> Self {
447        let InsertMany {
448            query,
449            primary_key,
450            empty,
451            model,
452        } = insert;
453
454        Self {
455            insert_struct: Insert {
456                query,
457                primary_key,
458                model,
459            },
460            empty,
461        }
462    }
463
464    /// Try insert one item
465    pub fn one<M>(m: M) -> Self
466    where
467        M: IntoActiveModel<A>,
468    {
469        Self::from_one(Insert::one(m))
470    }
471
472    /// Try insert many items
473    pub fn many<M, I>(models: I) -> Self
474    where
475        M: IntoActiveModel<A>,
476        I: IntoIterator<Item = M>,
477    {
478        Self::from_many(Insert::many(models))
479    }
480
481    /// Set ON CONFLICT logic
482    pub fn on_conflict(mut self, on_conflict: OnConflict) -> Insert<A> {
483        self.insert_struct.query.on_conflict(on_conflict);
484        self.insert_struct
485    }
486
487    /// Set ON CONFLICT on primary key do nothing, but with MySQL specific polyfill.
488    pub fn on_conflict_do_nothing(mut self) -> Self {
489        self.insert_struct
490            .query
491            .on_conflict(on_conflict_primary_key::<A>());
492
493        self
494    }
495}
496
497impl<A> QueryTrait for TryInsert<A>
498where
499    A: ActiveModelTrait,
500{
501    type QueryStatement = InsertStatement;
502
503    fn query(&mut self) -> &mut InsertStatement {
504        &mut self.insert_struct.query
505    }
506
507    fn as_query(&self) -> &InsertStatement {
508        &self.insert_struct.query
509    }
510
511    fn into_query(self) -> InsertStatement {
512        self.insert_struct.query
513    }
514}
515
516fn on_conflict_primary_key<A: ActiveModelTrait>() -> OnConflict {
517    let primary_keys = <A::Entity as EntityTrait>::PrimaryKey::iter();
518    let mut on_conflict = OnConflict::columns(primary_keys.clone());
519    on_conflict.do_nothing_on(primary_keys);
520    on_conflict
521}
522
523#[cfg(test)]
524mod tests {
525    use sea_query::OnConflict;
526
527    use crate::tests_cfg::{cake, cake_filling};
528    use crate::{
529        ActiveValue, DbBackend, DbErr, EntityTrait, Insert, IntoActiveModel, NotSet, QueryTrait,
530        Set,
531    };
532
533    #[test]
534    fn insert_1() {
535        assert_eq!(
536            Insert::<cake::ActiveModel>::one(cake::ActiveModel {
537                id: ActiveValue::not_set(),
538                name: ActiveValue::set("Apple Pie".to_owned()),
539            })
540            .build(DbBackend::Postgres)
541            .to_string(),
542            r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
543        );
544    }
545
546    #[test]
547    fn insert_2() {
548        assert_eq!(
549            Insert::<cake::ActiveModel>::one(cake::ActiveModel {
550                id: ActiveValue::set(1),
551                name: ActiveValue::set("Apple Pie".to_owned()),
552            })
553            .build(DbBackend::Postgres)
554            .to_string(),
555            r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
556        );
557    }
558
559    #[test]
560    fn insert_3() {
561        assert_eq!(
562            Insert::<cake::ActiveModel>::one(cake::Model {
563                id: 1,
564                name: "Apple Pie".to_owned(),
565            })
566            .build(DbBackend::Postgres)
567            .to_string(),
568            r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
569        );
570    }
571
572    #[test]
573    fn insert_many_1() {
574        assert_eq!(
575            Insert::<cake::ActiveModel>::many([
576                cake::Model {
577                    id: 1,
578                    name: "Apple Pie".to_owned(),
579                },
580                cake::Model {
581                    id: 2,
582                    name: "Orange Scone".to_owned(),
583                }
584            ])
585            .build(DbBackend::Postgres)
586            .to_string(),
587            r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#,
588        );
589    }
590
591    #[test]
592    fn insert_many_2() {
593        assert_eq!(
594            Insert::<cake::ActiveModel>::many([
595                cake::ActiveModel {
596                    id: NotSet,
597                    name: Set("Apple Pie".to_owned()),
598                },
599                cake::ActiveModel {
600                    id: NotSet,
601                    name: Set("Orange Scone".to_owned()),
602                }
603            ])
604            .build(DbBackend::Postgres)
605            .to_string(),
606            r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie'), ('Orange Scone')"#,
607        );
608    }
609
610    #[test]
611    fn insert_many_3() {
612        let apple = cake_filling::ActiveModel {
613            cake_id: ActiveValue::set(2),
614            filling_id: ActiveValue::NotSet,
615        };
616        let orange = cake_filling::ActiveModel {
617            cake_id: ActiveValue::NotSet,
618            filling_id: ActiveValue::set(3),
619        };
620        assert_eq!(
621            Insert::<cake_filling::ActiveModel>::many([apple, orange])
622                .build(DbBackend::Postgres)
623                .to_string(),
624            r#"INSERT INTO "cake_filling" ("cake_id", "filling_id") VALUES (2, NULL), (NULL, 3)"#,
625        );
626    }
627
628    #[test]
629    fn insert_6() {
630        let orange = cake::ActiveModel {
631            id: ActiveValue::set(2),
632            name: ActiveValue::set("Orange".to_owned()),
633        };
634
635        assert_eq!(
636            cake::Entity::insert(orange)
637                .on_conflict(
638                    OnConflict::column(cake::Column::Name)
639                        .do_nothing()
640                        .to_owned()
641                )
642                .build(DbBackend::Postgres)
643                .to_string(),
644            r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO NOTHING"#,
645        );
646    }
647
648    #[test]
649    fn insert_7() {
650        let orange = cake::ActiveModel {
651            id: ActiveValue::set(2),
652            name: ActiveValue::set("Orange".to_owned()),
653        };
654
655        assert_eq!(
656            cake::Entity::insert(orange)
657                .on_conflict(
658                    OnConflict::column(cake::Column::Name)
659                        .update_column(cake::Column::Name)
660                        .to_owned()
661                )
662                .build(DbBackend::Postgres)
663                .to_string(),
664            r#"INSERT INTO "cake" ("id", "name") VALUES (2, 'Orange') ON CONFLICT ("name") DO UPDATE SET "name" = "excluded"."name""#,
665        );
666    }
667
668    #[test]
669    fn insert_8() -> Result<(), DbErr> {
670        use crate::{DbBackend, MockDatabase, Statement, Transaction};
671
672        mod post {
673            use crate as sea_orm;
674            use crate::entity::prelude::*;
675
676            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
677            #[sea_orm(table_name = "posts")]
678            pub struct Model {
679                #[sea_orm(primary_key, select_as = "INTEGER", save_as = "TEXT")]
680                pub id: i32,
681                pub title: String,
682                pub text: String,
683            }
684
685            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
686            pub enum Relation {}
687
688            impl ActiveModelBehavior for ActiveModel {}
689        }
690
691        let model = post::Model {
692            id: 1,
693            title: "News wrap up 2022".into(),
694            text: "brbrbrrrbrbrbrr...".into(),
695        };
696
697        let db = MockDatabase::new(DbBackend::Postgres)
698            .append_query_results([[model.clone()]])
699            .into_connection();
700
701        post::Entity::insert(model.into_active_model()).exec(&db)?;
702
703        assert_eq!(
704            db.into_transaction_log(),
705            [Transaction::many([Statement::from_sql_and_values(
706                DbBackend::Postgres,
707                r#"INSERT INTO "posts" ("id", "title", "text") VALUES (CAST($1 AS TEXT), $2, $3) RETURNING CAST("id" AS INTEGER)"#,
708                [
709                    1.into(),
710                    "News wrap up 2022".into(),
711                    "brbrbrrrbrbrbrr...".into(),
712                ]
713            )])]
714        );
715
716        Ok(())
717    }
718
719    #[test]
720    fn insert_9() -> Result<(), DbErr> {
721        use crate::{DbBackend, MockDatabase, MockExecResult, Statement, Transaction};
722
723        mod post {
724            use crate as sea_orm;
725            use crate::entity::prelude::*;
726
727            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
728            #[sea_orm(table_name = "posts")]
729            pub struct Model {
730                #[sea_orm(
731                    primary_key,
732                    auto_increment = false,
733                    select_as = "INTEGER",
734                    save_as = "TEXT"
735                )]
736                pub id_primary: i32,
737                #[sea_orm(
738                    primary_key,
739                    auto_increment = false,
740                    select_as = "INTEGER",
741                    save_as = "TEXT"
742                )]
743                pub id_secondary: i32,
744                pub title: String,
745                pub text: String,
746            }
747
748            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
749            pub enum Relation {}
750
751            impl ActiveModelBehavior for ActiveModel {}
752        }
753
754        let model = post::Model {
755            id_primary: 1,
756            id_secondary: 1001,
757            title: "News wrap up 2022".into(),
758            text: "brbrbrrrbrbrbrr...".into(),
759        };
760
761        let db = MockDatabase::new(DbBackend::Postgres)
762            .append_query_results([[model.clone()]])
763            .into_connection();
764
765        post::Entity::insert(model.into_active_model()).exec(&db)?;
766
767        assert_eq!(
768            db.into_transaction_log(),
769            [Transaction::many([Statement::from_sql_and_values(
770                DbBackend::Postgres,
771                r#"INSERT INTO "posts" ("id_primary", "id_secondary", "title", "text") VALUES (CAST($1 AS TEXT), CAST($2 AS TEXT), $3, $4) RETURNING CAST("id_primary" AS INTEGER), CAST("id_secondary" AS INTEGER)"#,
772                [
773                    1.into(),
774                    1001.into(),
775                    "News wrap up 2022".into(),
776                    "brbrbrrrbrbrbrr...".into(),
777                ]
778            )])]
779        );
780
781        Ok(())
782    }
783}