The old way of doing this was using LISP:

Adding a new Memgraph-specific query

Adding a new query to Memgraph is not hard but it consists of multiple steps that affect different parts of code. Using a small example of adding a FREE MEMORY query we will go through all the necessary steps while the additional functionalities like adding a query with a variable can be deduced by looking at the similar queries. The point of this tutorial is to only show you all the places you need to change to add a completely functional new query.

Modifying the grammar

First step is adding the new keywords, if any, to the Memgraph's grammar.

For our query, we have two keywords: FREE and MEMORY.

We go to the src/query/frontend/opencypher/grammar/CypherLexer.g4 file and check if the keywords are already defined. We see that MEMORY is actually defined but FREE is missing.

Next we go to the src/query/frontend/opencypher/grammar/MemgraphCypherLexer.g4 file which contains Memgraph specific keywords. We also see that FREE is not present so we add it here:

import CypherLexer ;

ALTER          : A L T E R ; 
ASYNC          : A S Y N C ; 
AUTH           : A U T H ; 
BAD            : B A D ; 
CLEAR          : C L E A R ; 
CSV            : C S V ; 
DATA           : D A T A ; 
DELIMITER      : D E L I M I T E R ; 
DATABASE       : D A T A B A S E ; 
DENY           : D E N Y ; 
DIRECTORY      : D I R E C T O R Y ; 
DROP           : D R O P ; 
DUMP           : D U M P ; 
FOR            : F O R ; 
FREE           : F R E E ; 
FROM           : F R O M ; 
GRANT          : G R A N T ; 
GRANTS         : G R A N T S ; 
HEADER         : H E A D E R ; 
IDENTIFIED     : I D E N T I F I E D ; 
IGNORE         : I G N O R E ; 
LOAD           : L O A D ; 
LOCK           : L O C K ; 
MAIN           : M A I N ; 
MODE           : M O D E ; 
NO             : N O ; 
PASSWORD       : P A S S W O R D ; 
PORT           : P O R T ; 
PRIVILEGES     : P R I V I L E G E S ; 
REGISTER       : R E G I S T E R ; 
REPLICA        : R E P L I C A ; 
REPLICAS       : R E P L I C A S ; 
REPLICATION    : R E P L I C A T I O N ; 
REVOKE         : R E V O K E ; 
ROLE           : R O L E ; 
ROLES          : R O L E S ; 
QUOTE          : Q U O T E ; 
STATS          : S T A T S ; 
SYNC           : S Y N C ; 
TIMEOUT        : T I M E O U T ; 
TO             : T O ; 
UNLOCK         : U N L O C K ; 
USER           : U S E R ; 
USERS          : U S E R S ;

After that, we read the comment at the beginning of the file and notice that we need to add the new keyword to the kKeywords in src/query/frontend/stripped_lexer_constants.hpp :

const trie::Trie kKeywords = {
      "union",  "all",        "optional",  "match",   "unwind",     "as",       "merge",    "on",    "create",
      "set",    "detach",     "delete",    "remove",  "with",       "distinct", "return",   "order", "by",
      "skip",   "limit",      "ascending", "asc",     "descending", "desc",     "where",    "or",    "xor",
      "and",    "not",        "in",        "starts",  "ends",       "contains", "is",       "null",  "case",
      "when",   "then",       "else",      "end",     "count",      "filter",   "extract",  "any",   "none",
      "single", "true",       "false",     "reduce",  "coalesce",   "user",     "password", "alter", "drop",
      "show",   "stats",      "unique",    "explain", "profile",    "storage",  "index",    "info",  "exists",
      "assert", "constraint", "node",      "key",     "dump",       "database", "call",     "yield", "memory",
      "mb",     "kb",         "unlimited", "free"};

Defining a new query

We added all the new keywords to Memgraph's grammar now we can define how our query actually looks like.

We go to the src/query/frontend/opencypher/grammar/MemgraphCypher.g4 and define our new query. Again, we need to add the new FREE keyword:

memgraphCypherKeyword : cypherKeyword
                      | ALTER
                      | ASYNC
                      | AUTH
                      | BAD
                      | CLEAR
                      | CSV
                      | DATA
                      | DELIMITER
                      | DATABASE
                      | DENY
                      | DROP
                      | DUMP
                      | FOR
                      | FREE
                      | FROM
                      | GRANT
                      | HEADER
                      | IDENTIFIED
                      | LOAD
                      | LOCK
                      | MAIN
                      | MODE
                      | NO
                      | PASSWORD
                      | PORT
                      | PRIVILEGES
                      | REGISTER
                      | REPLICA
                      | REPLICAS
                      | REPLICATION
                      | REVOKE
                      | ROLE
                      | ROLES
                      | QUOTE
                      | STATS
                      | SYNC
                      | TIMEOUT
                      | TO
                      | UNLOCK
                      | USER
                      | USERS
                      ;

Then we define the name of our query. In this case it will be freeMemoryQuery and we add it to the query :

query : cypherQuery
      | indexQuery
      | explainQuery
      | profileQuery
      | infoQuery
      | constraintQuery
      | authQuery
      | dumpQuery
      | replicationQuery
      | lockPathQuery
      | freeMemoryQuery
      ;

Add the end of the file, we simply define the query:

freeMemoryQuery : FREE MEMORY ;

You can take a look at the replication and authentication queries in the same file to see how to define more complex queries.