Seraph.Query (Seraph v0.2.4)

Provide the query DSL.

Queries are used to retrieve and manipulate data from a repository (see Seraph.Repo). They can be written using keywords or macros.

Basic example:

# Keyword syntax
match [{n}],
return: [n]

# Macro syntax
match([{n}])
|> return([n])

Node and relationship representation

Seraph try to be as close to Cypher syntax as possible.

Nodes are represented by {variable, schema, properties} where:

All variants are valid depending on the context.

Note that primary label will be deducted from schema and additional labels should be added as properties under the key :additionalLabels

Node examples:

# Fully fleshed node
{u, MyApp.User, %{firstName: "John", lastName: "Doe"}}

# Node with no / useless properties
{u, MyApp.User}

# Node with only properties
{u, %{firstName: "John"}}

# Node with additional labels
{u, MyApp.User, %{additionalLabels: ["New", "Premium"]}}

Relationships are represented by [start_node, [variable, schema, properties], end_node] where:

  • start_node is a valid node representation
  • variable is a string,
  • schema is a Seraph.Schema.Relationship,
  • properties are a map
  • end_node is a valid node representation

All variants are valid depending on the context

Relationship examples:

# Fully flesh relationship
[{u, MyApp.User, %{firstName: "John"}}, [rel, MyApp.Wrote, %{nb_edits: 5}], {p, MyApp.Post}]

# Relatinship without properties
[{u, MyApp.User}, [rel, MyApp.Wrote], {p, MyApp.Post}]

# Relatinship without variable
[{u, MyApp.User}, [MyApp.Wrote], {p, MyApp.Post}]

About literals and interpolation

The following literals are allowe in queries:

  • Integers
  • Floats
  • Strings
  • Boolean
  • Lists

For the other types or dynamic values, you can interpolate them using ^:

first_name = "John"
match([{u, MyApp.User}])
|> where([u.firstName == ^first_name])

Keyword order and entry points

In Cypher, keyword can be used in any order but only some can start a query. The same applies for Seraph queries. The entry point keywords / macros are:

  • match
  • create
  • merge

Note that because of this versability, it is possible to write invalid queries, a databse error will then be raised.

About operators and functions

Each Keyword / macro has a specific set ef availabe operators and functions. Please see the keyword / macro documentation for the aviable operators and functions.

About nil

In Neo4j, NULL doesn't exists. This means that you can't have a null property and that setting a property to null will remove it.

Also, it is preferred to us is_nil in where clause instead of using %{property: nil}

Link to this section Summary

Functions

Create a CREATE clause from a list of nodes and/or relationships.

Create a DELETE clause from list of variables.

Create a LIMIT clause from value.

Create a MATCH clause from a list of nodes and / or relationships.

Create a MERGE clause from a node or relationship.

Create a ON CREATE SET clause from a list of expression.

Create a ON MATCH SET clause from a list of expression.

Create a ORDER BY clause from a list of orders.

Create a REMOVE clause from a list of properties and / or labels.

Create a RETURN clause from a list of variables and / or properties and / or functions.

Create a SET clause from a list of expressions.

Create a SKIP clause from value.

Create a WHERE clause from a boolean expression.

Link to this section Types

Specs

operation() :: :match | :where | :return

Specs

t() :: %Seraph.Query{
  identifiers: %{optional(String.t()) => Seraph.Query.Builder.Entity.t()},
  literal: [String.t()],
  operations: [{operation(), any()}],
  params: [{atom(), any()}]
}

Link to this section Functions

Link to this macro

create(expr, operations_kw \\ [])

(macro)

Create a CREATE clause from a list of nodes and/or relationships.

  • Cypher keyword: CREATE

  • Entry point: yes

  • Expects: a list of nodes and / or relationships

  • Invalid data:

    • Empty node: {},
    • Empty relationship: [{}, [], {}]
    • Node without schema: {u, %{prop1: value}} , {u}

    Examples

    # Creating a node (keyword syntax)
    create [{u, MyApp.User, %{uid: 1, firstName: "John"}}],
      return: [u]
    # Creating a node (macro syntax)
    create([{u, MyApp.User, %{uid: 1, firstName: "John"}}])
    |> return([u])
    # Creating a relationship (keyword syntax)
    create [
      [
        {u, MyApp.User, %{uid: 1}},
        [rel, MyApp.Wrote, %{nb_edit: 5}],
        {p, MyApp.Post, %{uid: 2}}
      ]
    ],
      return: [rel]
    # Creating a relationship with a previous MATCH (keyword syntax)
    match [
      {u, MyApp.User, %{uid: 1}},
      {p, MyApp.Post, %{uid: 2}}
    ],
      create: [[{u}, [rel, MyApp.Wrote, %{nb_edit: 5}], {p}]],
      return: [rel]
     # Creating a relationship (macro syntax)
    create([
      [
        {u, MyApp.User, %{uid: 1}},
        [rel, MyApp.Wrote, %{nb_edit: 5}],
        {p, MyApp.Post, %{uid: 2}}
      ]
    ])
    |> return([rel])
Link to this macro

delete(query, expr)

(macro)

Create a DELETE clause from list of variables.

  • Cypher keyword: DELETE
  • Entry point: no
  • Expects: a list of variables.

Examples

  # Keyword syntax
  match [{u, MyApp.User, %{uid: 5}}],
    delete: [u]

  # Macro syntax
  match([{u, MyApp.User, %{uid: 5}}])
  |> delete([u])
Link to this macro

limit(query, expr)

(macro)

Create a LIMIT clause from value.

  • Cypher keyword: LIMIT
    • Entry point: no
    • Expects: a value.

Examples

  # Keyword syntax
  match [{u, MyApp.User}],
    return: [u.firstName, u.lastName],
    limit: 2

  # Maccro syntax
  match([{u, MyApp.User}])
  |> return([u.firstName, u.lastName])
  |> limit(2)
Link to this macro

match(expr, operations_kw \\ [])

(macro)

Create a MATCH clause from a list of nodes and / or relationships.

  • Cypher keyword: MATCH
  • Entry point: yes
  • Expects: a list of nodes and / or relationships
  • Invalid data:
    • Empty node: {},
    • Empty relationship: [{}, [], {}]

Examples

  # Keyword syntax
  match [
    {u, User},
    {p, Post},
    [{u}, [rel, Wrote], {p}]
  ]

  # Macro syntax
  match([
    {u, User},
    {p, Post},
    [{u}, [rel, Wrote], {p}]
  ])
Link to this macro

merge(expr, operations_kw \\ [])

(macro)

Create a MERGE clause from a node or relationship.

  • Cypher keyword: MERGE
    • Entry point: yes
    • Expects: a node or a relationship
    • Invalid data:
      • Empty node: {},
      • Empty relationship: [{}, [], {}]
      • Relationship without schema: [{u}, [rel], {p}]

Examples

# Merging a node (keyword syntax)
merge [{u, MyApp.User, %{uid: 1, firstName: "John"}}],
  return: [u]

# Merging a node (macro syntax)
merge([{u, MyApp.User, %{uid: 1, firstName: "John"}}])
|> return([u])

# Merging a relationship (keyword syntax)
merge [
  [
    {u, MyApp.User, %{uid: 1}},
    [rel, MyApp.Wrote, %{nb_edit: 5}],
    {p, MyApp.Post, %{uid: 2}}
  ]
],
  return: [rel]

# Merging a relationship with a previous MATCH (keyword syntax)
match [
  {u, MyApp.User, %{uid: 1}},
  {p, MyApp.Post, %{uid: 2}}
],
  merge: [[{u}, [rel, MyApp.Wrote, %{nb_edit: 5}], {p}]],
  return: [rel]

  # Merging a relationship (macro syntax)
merge([
  [
    {u, MyApp.User, %{uid: 1}},
    [rel, MyApp.Wrote, %{nb_edit: 5}],
    {p, MyApp.Post, %{uid: 2}}
  ]
])
|> return([rel])
Link to this macro

on_create_set(query, expr)

(macro)

Create a ON CREATE SET clause from a list of expression.

Require a MERGE

See set/2 for usage details.

Link to this macro

on_match_set(query, expr)

(macro)

Create a ON MATCH SET clause from a list of expression.

Require a MERGE.

See set/2 for usage details.

Link to this macro

order_by(query, expr)

(macro)

Create a ORDER BY clause from a list of orders.

  • Cypher keyword: ORDER_BY
  • Entry point: no
  • Expects: a list of orders.

Default order is ascending (ASC)

Examples

  # with default order (keyword syntax)
  match [{u, MyApp.User}],
    return: [u.firstName, u.lastName],
    order_by: [u.firstName]

  # with specific order (keyword syntax)
  match [{u, MyApp.User}],
    return: [u.firstName, u.lastName],
    order_by: [desc: u.firstName]

  # Macro syntax
  match([{u, MyApp.User}])
  |> return([u.firstName, u.lastName])
  |> order_by([u.firstName])
Link to this macro

remove(query, expr)

(macro)

Create a REMOVE clause from a list of properties and / or labels.

  • Cypher keyword: REMOVE
  • Entry point: no
  • Expects: a list of properties and / or labels.

Examples

# Remove property (Keyword syntax)
match [{u, MyApp.User, %{uid: 1}}],
  remove: [u.firstName],
  return: [u]

# Remove label (Keyword syntax)
match [{u, MyApp.User, %{uid: 1}}],
  remove: [{u, OldLabel}],
  return: [u]

# Remove multiple labels (Keyword syntax)
match [{u, MyApp.User, %{uid: 1}}],
  remove: [{u, [OldLabel1, OldLabel2]}],
  return: [u]

# Remove property (Macro syntax)
match([{u, MyApp.User, %{uid: 1}}])
|> remove([u.firstName])
|> return([u])
Link to this macro

return(query, expr)

(macro)

Create a RETURN clause from a list of variables and / or properties and / or functions.

  • Cypher keyword: RETURN
  • Entry point: no
  • Expects: a list of variables and / or properties and / or functions.

Note that functions and bare value must be aliased.

Note that distinct has two usages:

  • At a general level, meaning RETURN DISTINCT n, n.prop, ....

    In this case, all result fields should be arguments of the distinct like this: return: [distinct(n, n.prop, ....)].

  • With aggregate function as other function: count(distinct(u))

Available functions

  • min

  • max

  • count

  • avg

  • sum

  • st_dev

  • percentile_disc

  • distinct

  • collect

  • size

  • id

  • labels

  • type

  • start_node

  • end_node

Examples

  # return matched data and properties
  match [{u, MyApp.User, %{uid: 1}, {p, MyApp.Post}],
    return: [u.firstName, p]

  # aliased return
  match [{u, MyApp.User}],
    return: [names: u.firstName, bare_value: 5]

  # distinct return
  match [{u, MyApp.User}],
    return: [distinct(u.firstName, u.lastName)]

  # return function result
  match [{u, MyApp.User, %{uid: 1}, {p, MyApp.Post}],
    return: [nb_post: count(distinct(p))]

  # Macro syntax
  match([{u, MyApp.User, %{uid: 1}, {p, MyApp.Post}])
  |> return([nb_post: count(distinct(p))])
Link to this macro

set(query, expr)

(macro)

Create a SET clause from a list of expressions.

  • Cypher keyword: SET
  • Entry point: no
  • Expects: a list of expressions.

Valid operators

  • +
  • -
  • *
  • /

Valid functions

  • collect
  • id
  • labels
  • type
  • size

Examples

  # with match (Keyword syntax)
  match [{u, Myapp.User, %{uid: 1}}],
    set: [u.firstName = "OtherName"]

  match [{p, MyApp.Post}],
    set: [p.viewCount = viewCount + 1]

  match [
    {p, MyApp.Post, %{uid: 45}},
    {u, MyApp.User},
    [{u}, [rel, MyApp.Read], {p}]
  ],
    set: [p.viewCount = size(collect(u.uid))]

  # with create (Keyword syntax)
  create [{u, Myapp.User, %{uid: 99}}],
    set: [u.firstName = "Collin", lastName = "Chou"]

  # Set label (Keyword syntax)
  match [{u, Myapp.User, %{uid: 1}}],
    set: [{u, NewAdditionalLabel}]

  # Set multiple label (Keyword syntax)
  match [{u, Myapp.User, %{uid: 1}}],
    set: [{u, [NewAdditionalLabel1, NewAdditionalLabel2]}]

  # Macro syntax
  match([{u, Myapp.User, %{uid: 1}}])
  |> set([u.firstName = "OtherName"])
Link to this macro

skip(query, expr)

(macro)

Create a SKIP clause from value.

  • Cypher keyword: SKIP
    • Entry point: no
    • Expects: a value.

Examples

  # Keyword syntax
  match [{u, MyApp.User}],
    return: [u.firstName, u.lastName],
    skip: 2

  # Maccro syntax
  match([{u, MyApp.User}])
  |> return([u.firstName, u.lastName])
  |> skip(2)
Link to this macro

where(query, expr)

(macro)

Create a WHERE clause from a boolean expression.

  • Cypher keyword: WHERE
  • Entry point: no
  • Expects: a boolean expression

Valid operators

  • and (infix)

  • or (infix)

  • xor

  • in (infix)

  • == (infix)

  • <> (infix)

  • > (infix)

  • >= (infix)

  • < (infix)

  • <= (infix)

  • is_nil

  • not

  • exists

  • starts_with

  • ends_with

  • contains

  • =~

Examples

# Keyword syntax
match [{u, MyApp.User}],
  where: exists(u.lastName) and start_with(u.firstName, "J"),
  return: [u.firstName]

# Macro syntax
match([{u, MyApp.User}])
|> where(exists(u.lastName) and start_with(u.firstName, "J"))
|> return([u.firstName])