Seraph.Schema.Relationship (Seraph v0.2.4)

Defines a relationship schema.

a Relationship Schema is used to map a Neo4j relationship into an Elixir struct.

relationship/3 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

# Complete form
defmodule MyApp.Wrote do
  use Seraph.Schema.Relationship

  @cardinality :one

  relationship "WROTE" do
    start_node MyApp.User
    end_node MyApp.Post

    property :views, :integer, default: 0
  end
end

# Short form (useful for relationship without properties)
defrelationship("FOLLOWS", MyApp.User, MyApp.User, cardinality: :one)

The start_node macro defines the node schema from which starts the relationship. The end_node macro defines the node schema to which ends the relationship. The property macro defines a property in the node schema.

Schemas are regular structs and can be created and manipulated directly using Elixir's struct API:

iex> user = %MyApp.Wrote{views: 1}
iex> %{user | views: 2}

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

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__(:type) - Returns the type defined relationship/3
  • __schema__(:start_node) - Returns the start_node schema
  • __schema__(:end_node) - Returns the end_node schema
  • __schema__(:cardinality) - Returns the cardinality
  • __schema__(:properties) - Returns the list of properties names

Link to this section Summary

Functions

Allow to define a relationship schema without properties in a quick way.

Defines the end node with its module.

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

Defines a relationship with a type and properties. An additional field called __meta__ is added to the struct.

Defines the start node with its module.

Link to this section Types

Link to this type

cardinality()

Specs

cardinality() :: [outgoing: :one | :many, incoming: :one | :many]

Specs

t() :: %atom(){
  __meta__: Seraph.Schema.Relationship.Metadata.t(),
  __id__: integer(),
  type: String.t(),
  direction: :outgoing | :incoming,
  start_node: Seraph.Schema.Node.t(),
  end_node: Seraph.Schema.Node.t(),
  properties: Ecto.Schema.t(),
  cardinality: cardinality()
}

Link to this section Functions

Link to this macro

defrelationship(rel_type, start_node, end_node, opts \\ [])

(macro)

Allow to define a relationship schema without properties in a quick way.

Will expand in a viable relationship schema without properties. Module name will be built upon start_node, end_node and relationship type as follows: [caller_module_name].[start_node]To[end_node].[relationship_type].

A free changeset will be provided with :end_node and :start_node as allowed changes, allowing to easily set them and to have a similar behaviour as fully-defined relationship

Options:

  • :cardinality - Defines the cardinality of the relationship. Can take two values: :one or :many. Default: :many

Example

  defmodule MyApp.NoPropsRelationships do
    import Seraph.Schema.Relationship

    defrelationship("ACTED_IN", MyApp.Person, MyApp.Movie, cardinality: :one)
    defrelationship("DIRECTED", MyApp.Person, MyApp.Movie)
  end

  # Will expand to

  defmodule MyApp.NoPropsRelationships do
    defmodule PersonToMovie.ActedIn do
      use Seraph.Schema.Relationship

      @cardinality :one

      relationship "ACTED_IN" do
        start_node MyApp.Person
        end_node MyApp.Movie
      end

      def changeset(relationship, params \ %{}) do
        Seraph.Changeset.cast(relationship, params, [:start_node, :end_node])
      end
    end

    defmodule PersonToMovie.Directed do
      use Seraph.Schema.Relationship

      @cardinality :many

      relationship "DIRECTED" do
        start_node MyApp.Person
        end_node MyApp.Movie
      end

      def changeset(relationship, params \ %{}) do
        Seraph.Changeset.cast(relationship, params, [:start_node, :end_node])
      end
    end
  end
Link to this macro

end_node(node)

(macro)

Defines the end node with its module.

Link to this macro

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

(macro)

Defines a property on the relationship 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.

Link to this macro

relationship(rel_type, list)

(macro)

Defines a relationship with a type and properties. An additional field called __meta__ is added to the struct.

Options:

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

Note:

  • type must be uppercased.
  • relationship info must match the info given in the start and end node schemas
Link to this macro

start_node(node)

(macro)

Defines the start node with its module.