InsertQuery

    #[insert_query(module, table, result)] {
        #[field]
        #[nested_query]
        #[unless_conflict]
    }

insert_query attribute macro indicates that the struct represents an edgeDB insert query.

Its fields can be decorated with one of following tags :

Usage

Consider the following edgeDB schema πŸ‘‡

    module models {
       scalar type Gender extending enum<Male, Female>
        
       type Person {
            required property user_name -> str {
                constraint exclusive;
            }
            required property age -> int16;
            required property gender -> Gender;
            link address -> Address;
       }
        
       type Address {
            required property num -> int16;
            required property street -> str;
            required property city -> str;
            required property zipcode -> int32;
       }
   }

Let's write a struct that represents query to insert a new Person into the database

    #[insert_query(module="models", table="Person", result="Person")]
    pub struct InsertPerson {
        #[field(column_name="user_name")]
        pub name: String,    
        #[field(scalar="<int16>")]   
        pub age: u8,
        #[field(column_name="gender", scalar="<models::Gender>")]
        pub sex: Sex,
    }

    #[edgedb_enum]
    pub enum Sex {
        #[value("Male")]
        Man,
        #[value("Female")]
        Woman
    }

    #[query_result]
    pub struct Person {
        pub user_name: String,
        pub age: u8
    }

πŸ€·β€β™€οΈ But what about the person's address❔


Since the address is stored in a separate database table we need to insert a new Address while creating a new Person, right ?

Ok, so let's write the address's insert query corresponding struct.

    #[insert_query(module="models", table="Address")]
    pub struct InsertAddress {
        #[field(column_name="num", scalar="<int16>")]
        pub number: u16,
        pub street: String,
        pub city: String,
        #[field(column_name="zipcode", scalar="<int32>")]
        pub zip_code: u32
    }

To insert both entities with a single query, add the insert address query as a nested query of the person insert query.

    #[insert_query(module="models", table="Person", result="Person")]
    pub struct InsertPerson {
        ...
        #[nested_query]
        pub address: InsertAddress
    }

Okay, great! Now we can persist a Person with address.

πŸ€·β€β™€οΈ But what if a Person already exists with the same name ❔


Remember !!!

In the edgeDB schema, the type Person has an exclusive constraint on its field user_name.

    required property user_name -> str {
       constraint exclusive;
    }

To handle this case we need to use an unless conflict statement.

    #[insert_query(module="models", table="Person", result="Person")]
    pub struct InsertPerson {
        ...
        #[unless_conflict(on="user_name")]
        pub handle_conflict: edgedb_query::queries::conflict::UnlessConflict
    }

The new field handle_conflict decorated with #[unless_conflict] tag add a unless conflict on .user_name statement to the query.

It is possible to add an else query to the unless conflict statement by using a edgedb_query::queries::conflict::UnlessConflictElse<T: ToEdgeQuery> type instead of an UnlessConflict type.

    #[insert_query(module="models", table="Person", result="Person")]
    pub struct InsertPerson {
        ...
        #[unless_conflict(on="user_name")]
        pub handle_conflict: edgedb_query::queries::conflict::UnlessConflictElse<FindUserByName>
    }

    #[select_query]
    pub struct FindUserByName {
        ...
    }