Last active
August 4, 2021 03:22
-
-
Save zeroasterisk/6c385d6df943514dc02d3f860d7a32c2 to your computer and use it in GitHub Desktop.
Example Elixir+Ecto schema to mirror a Mongo DB with complicated data structures
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Eltoroportal.Accounts.User do | |
use Ecto.Schema | |
import Ecto.Changeset | |
alias Eltoroportal.Accounts.User | |
@primary_key {:_id, :string, autogenerate: false} | |
schema "users" do | |
field :username, :string | |
# field :created, :date # <-- ? mongo translation? | |
# field :addresses, {:array, :map} # ? array of sub-documents - this fits the docs fairly well | |
field :emails, {:array, Email}, on_replace: :update | |
# field :profile, :map # ? sub-document with static keys, should be easy to map (multi-layer) | |
# field :roles, :map # ? sub-document with dynamic keys, and array of strings | |
embeds_one :services, Service, on_replace: :update | |
timestamps() | |
end | |
@doc false | |
def changeset(%User{} = user, attrs) do | |
user | |
|> cast(attrs, [:username]) | |
|> cast_embed(:services) | |
|> validate_required([:username]) | |
end | |
defmodule Service do | |
use Ecto.Schema | |
import Ecto.Changeset | |
@primary_key false | |
schema "" do | |
embeds_one :password, ServicePassword, on_replace: :update | |
embeds_one :google, ServiceGoogle, on_replace: :update | |
end | |
def changeset(struct, params) do | |
struct | |
|> cast(params, []) | |
|> cast_embed(:password) | |
|> cast_embed(:google) | |
end | |
end | |
defmodule ServicePassword do | |
use Ecto.Schema | |
import Ecto.Changeset | |
@primary_key false | |
schema "" do | |
field :bcrypt, :string | |
end | |
def changeset(struct, params) do | |
struct | |
|> cast(params, [:bcrypt]) | |
end | |
end | |
defmodule ServiceGoogle do | |
use Ecto.Schema | |
import Ecto.Changeset | |
@primary_key false | |
schema "" do | |
field :id, :string | |
field :accessToken, :string | |
field :idToken, :string | |
field :expiresAt, :integer | |
field :scope, {:array, :string} | |
field :email, :string | |
field :verified_email, :boolean | |
field :name, :string | |
field :given_name, :string | |
field :family_name, :string | |
field :locale, :string | |
field :gender, :string | |
field :picture, :string | |
end | |
def changeset(struct, params) do | |
struct | |
|> cast(params, [ | |
:id, | |
:accessToken, | |
:idToken, | |
:expiresAt, | |
:scope, | |
:email, | |
:verified_email, | |
:name, | |
:given_name, | |
:family_name, | |
:locale, | |
:gender, | |
:picture | |
]) | |
end | |
end | |
defmodule Email do | |
use Ecto.Schema | |
import Ecto.Changeset | |
@primary_key false | |
schema "" do | |
field :label, :string | |
field :address, :string # regEx: SimpleSchema.RegEx.Email, | |
field :service, :string # ? | |
field :verified, :boolean | |
end | |
def changeset(struct, params) do | |
struct | |
|> cast(params, [ | |
:label, | |
:address, | |
:service, | |
:verified, | |
]) | |
|> update_change(:address, &String.downcase/1) | |
|> validate_required([:address]) | |
|> validate_format(:address, ~r/([\w]+)@([\w]+).([\w]{2,32})/) | |
# |> validate_unique(:address, on: Repo) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"_id" : "1122334455667788", | |
"username": "alanblount", | |
"created" : ISODate("2017-01-01T00:00:00.000-04:00"), | |
"emails" : [ | |
{ | |
"address" : "alan@example.com", | |
"verified" : true, | |
"service" : "google", | |
"label" : "primary" | |
} | |
], | |
"addresses": [ | |
{ "type": 1, "address": "123 n. 1st st", city: "Louisville", state: "KY", zip: "40206" } | |
], | |
"profile" : { | |
"name" : "Alan Blount", | |
"email" : "alan@example.com", | |
"avatar" : "https://lh4.googleusercontent.com/-GRaizMd9Jbo/AAAAAAAAAAI/AAAAAAAAACM/_tkoXy1kU2c/photo.jpg", | |
"lastLogin" : ISODate("2017-06-14T13:11:32.402-04:00"), | |
"agreed" : true, | |
"company" : "Somewhere", | |
"approved" : true, | |
"mapcenter" : { | |
"lat" : 34.1835891424516, | |
"lng" : -84.342645 | |
} | |
}, | |
"roles": { | |
"groupname_1": ["value1", "value2"], | |
"groupname_2": ["something"], | |
}, | |
"services" : { | |
"password" : { | |
"bcrypt" : "$2a$10$sg/xxxxxxxxxxxxxxxx" | |
}, | |
"google" : { | |
"id" : "1111111111111111", | |
"accessToken" : "xxxx.xxxxxxxxx-xxxxxxx-xxxxxxx-x-xxxxxxxx", | |
"idToken" : "xxxxxxxxxxx", | |
"expiresAt" : 1492357827963.0, | |
"scope" : [ | |
"https://www.googleapis.com/auth/userinfo.email", | |
"https://www.googleapis.com/auth/userinfo.profile" | |
], | |
"email" : "alan@example.com", | |
"verified_email" : true, | |
"name" : "Alan Blount", | |
"given_name" : "Alan", | |
"family_name" : "Blount", | |
"picture" : "https://lh4.googleusercontent.com/-GRaizMd9Jbo/AAAAAAAAAAI/AAAAAAAAAFI/W7JfoXRl4T0/photo.jpg", | |
"locale" : "en", | |
"gender" : "male" | |
}, | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment