Response of insert doesn't contain default values

It is returning the structs it sent to the database, not the values the database inserted. This is obviously more performant than always fetching data back from the database when that isn’t needed. (And not all databases support returning inserted values, which means the worse case is actually having to issue a second query, not just parsing the response to an insert!) For large numbers of insertions (or small numbers of large insertions :wink: ) this makes a big difference.

You can, however, get Ecto to comply. From the documentation:

If you need to guarantee the data in the returned struct mirrors the database, you have three options:

Use on_conflict: :replace_all, although that will replace all fields in the database with current ones:

MyRepo.insert(%Post{title: "this is unique"},
              on_conflict: :replace_all, conflict_target: :title)

Specify read_after_writes: true in your schema for choosing fields that are read from the database after every operation. Or pass returning: true to insert to read all fields back:

MyRepo.insert(%Post{title: "this is unique"}, returning: true,
              on_conflict: on_conflict, conflict_target: :title)

Alternatively, read the data again from the database in a separate query. This option requires the primary key to be generated by the database:

{:ok, updated} = MyRepo.insert(%Post{title: "this is unique"}, on_conflict: on_conflict)
Repo.get(Post, updated.id)
7 Likes