Seraph.Schema.Node (Seraph v0.2.4)

Defines a Node schema.

a Node Schema is used to map a Neo4j node into an Elixir struct.

node/2 is used to map a Neo4j node into an Elixir struct and vice versa. It allows you to have your application data decoipled from your persisted data and to manipulate them easily.

Example

defmodule User do
  use Seraph.Schema.Node

  node "User" do
    property :name, :string
    property :age, :integer, default: 0

    incoming_relationship "FOLLOWED", MyApp.Blog.User, :followers, through: MyApp.Blog.Relationships.Followed

    outgoing_relationship "WROTE", MyApp.Blog.Post, :posts, through: MyApp.Blog.Relationships.Wrote
  end
end

By default, a node schema will generate a identifier which is named uuid and of type Ecto.UUID. This is to avoid to rely on Neo4j's internal ids for identifier purpose. The property macro defines a property in the node schema. The incoming_relationship macro defines relationship going from another node schema to the current one. The outgoing_relationship macro defines relationship going from the current node schema to another one. Schemas are regular structs and can be created and manipulated directly using Elixir's struct API:

iex> user = %User{name: "jane"}
iex> %{user | age: 30}

However, most commonly, structs are cast, validated and manipulated with the Seraph.Changeset module.

Schema attributes

Supported attributes for configuring the defined node schema. They must be set after the use Seraph.Schema.Node call and before the node/2 definition.

These attributes are:

  • @identifier configures the node schema identifier. It will be used at node's creation only. It expects a tuple {name, type, options}. No options are available for the moment.
  • @merge_keys configure the node schema merge keys. These keys will be used when updating the node data. It expects a list of atoms. Note that the merge keys must be properties of the node schema. If they are not defined, the identifier will be used as merge key.

Types

The available types are:

Ecto typeElixir typeLiteral syntax in query
:idinteger1, 2, 3
:binary_idbinary<<int, int, int, ...>>
:integerinteger1, 2, 3
:floatfloat1.0, 2.0, 3.0
:booleanbooleantrue, false
:stringUTF-8 encoded string"hello"
:binarybinary<<int, int, int, ...>>
{:array, inner_type}list[value, value, value, ...]
:mapmap
{:map, inner_type}map
:decimalDecimal
:dateDate
:timeTime
:time_usecTime
:naive_datetimeNaiveDateTime
:naive_datetime_usecNaiveDateTime
:utc_datetimeDateTime
:utc_datetime_usecDateTime

Reflection

Any node schema module will generate the __schema__ function that can be used for runtime introspection of the schema:

  • __schema__(:primary_label) - Returns the primary label as defined in node/2
  • __schema__(:identifier) - Returns the identifier data
  • __schema__(:merge_keys) - Returns the list of merge keys
  • __schema__(:properties) - Returns the list of properties names
  • __schema__(:relationships) - Returns the list of all relationships data
  • __schema__(:relationship, relationship_type) - Returns data about the specified relationship type
  • __schema__(:incoming_relationships) - Returns a list of all incoming relationship names
  • __schema__(:outgoing_relationships) - Returns a list of all outgoing relationship names

Link to this section Summary

Functions

Defines an incoming relationship on the node schema with the given data

Defines a node schema with a primary label, properties and relationships definitions. An additional field called __meta__ is added to the struct.

Defines an outgoing relationship on the node schema with the given data

Defines a property on the node schema with the given name and type.

Link to this section Types

Specs

t() :: %atom(){
  optional(atom()) => any(),
  :__meta__ => Seraph.Schema.Node.Metadata.t(),
  :__id__ => integer(),
  :properties => map()
}

Link to this section Functions

Link to this macro

incoming_relationship(type, related_node, name, relationship_module, opts \\ [])

(macro)

Defines an incoming relationship on the node schema with the given data:

  • type - the relationship type (must be uppercased)
  • related_node - the node schema the relationship is linked from
  • name - the name used for storing related nodes (when loaded)
  • relationship_module - Defines the Relationship module

Loaded relationship(s) will be stored in the struct with their type as key.

Options:

  • cardinality - Defines the cardinality of the relationship. Can take two values: :one or :many
Link to this macro

node(primary_label, list)

(macro)

Defines a node schema with a primary label, properties and relationships definitions. An additional field called __meta__ is added to the struct.

Note that primary label must be PascalCased.

Link to this macro

outgoing_relationship(type, related_node, name, relationship_module, opts \\ [])

(macro)

Defines an outgoing relationship on the node schema with the given data:

  • type - the relationship type (must be uppercased)
  • related_node - the node schema the relationship is linked to
  • name - the name used for storing related nodes (when loaded)
  • relationship_module - Defines the Relationship module

Loaded relationship(s) will be stored in the struct with their type as key.

Options:

  • cardinality - Defines the cardinality of the relationship. Can take two values: :one or :many
Link to this macro

property(name, type, opts \\ [])

(macro)

Defines a property on the node schema with the given name and type.

Options:

  • :default - Sets the default value on the node schema and the struct. The default value is calculated at compilation time, so don't use expressions like DateTime.utc_now or Ecto.UUID.generate as they would then be the same for all records.

  • :virtual - When true, the field is not persisted to the database.