Say hello to the Graph Model Domain Specific Language (GMDSL), created with the help of Github’s Copilot.

I was ready to iterate on the implementation of BrainExpanded, especially the backend graph data model. I wanted to explore the use of Neo4j as my graph store and also start getting ready for a live deployment to real alpha-testing users. As I was learning Cypher (Neo4j’s graph langauge), it occured to me that I had to iterate on many aspects of the end-to-end, before I could finalize the graph data model for the graph store.

  • Graph database data model. I wanted something simpler than Cypher when it comes to describing the graph nodes and edges.
  • OpenAPI for the Web Service. This is the part of the BrainExpanded API that allows client applications to access the graph and ensures the appropriate authorization.
  • C# classes to represent the data model. This is the implementation of the above contract but also additional, application-specific logic that requires queries against the graph store.
  • Python representation of the data model. To make it easier to implement the AI agents that operate over the BrainExpanded memory, I implemented a data model in Python to represent the entries in the graph store. However, I later decided that perhaps the AI agents should not access the database directly and, instead, also go through the Web API layer. So the OpenAPI contract might be enough.
  • As the OpenAPI changes, the Swift classes representing the data model will also change.

I also realized that the node types and relationships in the graph store will evolve differently for different users so the OpenAPI contract will have to evolve as well or be appropriately generic to support such an evolution. Stay tuned on this topic.

So what do software engineers do in such a case? They build a tool to automate things. Well, at least this is what I decided to do. I have been using Github’s Copilot a lot for BrainExpanded but for this little project, Copilot wrote 90-95% of the code with me supervising the iteration process as we were adding more features.

The result is a very simple DSL that helps me describe a simple graph data model. The tool then generates the Cypher, OpenAPI, and C# classes. The Python and Swift classes will be generated from the OpenAPI using existing tools.

Given that this is a generic tool and not tightly coupled with BrainExpanded, I am opening up the repository to everyone in case there is interest in adding more plugins or evolving its functionality. You can find it at https://github.com/savasp/gmdsl.

Here’s a simple example of a graph data model description:

namespace Example

// Import some core types for properties
import GM.Core

// New types can be declared for properties
type Address {
    street: String
    city: String
    state: String
    zipcode: Integer
    country: String
}

// Declare some graph nodes

node Person {
    firstName: String
    lastName: String
    dateOfBirth: DateTime
    placeOfBirth: Location
}

node Company {
    name: String
    address: Address
}

// Department graph node
node Department {
    name: String
}

// Declare some edges. As per Neo4j's data model, edges may have
// properties

edge PartOf(Department -> Company)

edge Friend(Person <-> Person) {
    metOn: DateTime
}

edge Works(Person -> Company) {
    role: String
}

I can now generate Cypher schema declarations, C# classes, and the OpenAPI contract.

Here’s the generated Cypher schema (with the generated comments removed). Over time, I will add the necessary logic to the cypher plugin to generate additional statements.

CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person) REQUIRE n.firstName IS NOT NULL;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person) REQUIRE n.lastName IS NOT NULL;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person) REQUIRE n.dateOfBirth IS NOT NULL;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Person) REQUIRE n.placeOfBirth IS NOT NULL;

CREATE CONSTRAINT IF NOT EXISTS FOR (n:Company) REQUIRE n.name IS NOT NULL;
CREATE CONSTRAINT IF NOT EXISTS FOR (n:Company) REQUIRE n.address IS NOT NULL;

CREATE CONSTRAINT IF NOT EXISTS FOR (n:Department) REQUIRE n.name IS NOT NULL;

CREATE CONSTRAINT IF NOT EXISTS FOR ()-[r:Friend]-() REQUIRE r.metOn IS NOT NULL;

CREATE CONSTRAINT IF NOT EXISTS FOR ()-[r:Works]-() REQUIRE r.role IS NOT NULL;

Here are two of the classes generated by the C# plugin. Relationships are represented as objects. This plugin has a bug. It assumes that nodes have IDs. I am working on a fix which will indeed require all nodes and relationships to have IDs since that’s necessary for my use case.

namespace Example
{
    public class Example.Person
    {
        public string firstName { get; set; }
        public string lastName { get; set; }
        public System.DateTime dateOfBirth { get; set; }
        public None placeOfBirth { get; set; }
    }

    public class Example.Friend
    {
        public string SourceId { get; set; }
        public string TargetId { get; set; }
        public System.DateTime metOn { get; set; }
    }
}

And here’s an example of a generated OpenAPI contract (only parts of it are shown). Both graph nodes and relationships are represented as HTTP resources with the usual HTTP verbs.

paths:
  /people:
    post:
      summary: Create Person
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/person'
      responses:
        '201':
          description: Created
  /people/{node-id}:
    get:
      summary: Get Person by ID
      responses:
        '200':
          description: OK
    put:
      summary: Update Person by ID
      ...
    delete:
      summary: Delete Person by ID
      ...
  /companies:
    post:
      ...
  /companies/{node-id}:
    get:
      ...
    put:
    ...
  ...
  /people/{node-id}/friends:
    post:
      summary: Create Friend from Person
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/friend'
          ...
  /people/{node-id}/friends/{relationship-id}:
    get:
      ...
    put:
      ...
    ...
  ...
components:
  schemas:
    person:
      type: object
      properties:
        firstName:
          type: string
        lastName:
          type: string
        dateOfBirth:
          type: string
        placeOfBirth:
          type: string
    ...
    friend:
      type: object
      properties:
        metOn:
          type: string

This was a fun few hours-long distraction from the main work on BrainExpanded. I enjoyed it and learned even more about how to use Github’s Copilot as a coding companion. How do the kids call it these days? “Vibe coding”? I don’t like the term but here we are 🙂

Savas Parastatidis

Savas Parastatidis works at Amazon as a Sr. Principal Engineer in Alexa AI'. Previously, he worked at Microsoft where he co-founded Cortana and led the effort as the team's architect. While at Microsoft, Savas also worked on distributed data storage and high-performance data processing technologies. He was involved in various e-Science projects while at Microsoft Research where he also investigated technologies related to knowledge representation & reasoning. Savas also worked on language understanding technologies at Facebook. Prior to joining Microsoft, Savas was a Principal Research Associate at Newcastle University where he undertook research in the areas of distributed, service-oriented computing and e-Science. He was also the Chief Software Architect at the North-East Regional e-Science Centre where he oversaw the architecture and the application of Web Services technologies for a number of large research projects. Savas worked as a Senior Software Engineer for Hewlett Packard where he co-lead the R&D effort for the industry's Web Service transactions service and protocol. You can find out more about Savas at https://savas.me/about

Share
Published by
Savas Parastatidis

Recent Posts

BrainExpanded – Web app and Data Sources

As I wrote in previous posts, the manual recording of memories for BrainExpanded is just…

2 weeks ago

BrainExpanded – End-to-end working

Imagine a world where your memory is enhanced by a team of intelligent agents, working…

4 weeks ago

BrainExpanded – Login State Caching Issue in iOS Share Extension

As part of the BrainExpanded project, I’m building an iOS app that lets users easily…

3 months ago

Is AI Good or Bad?

Artificial Intelligence (AI) has rapidly evolved over the past few decades, becoming an integral part…

3 months ago

BrainExpanded – Copilot

Happy New Year everyone! I was planning for my next BrainExpanded post to be a…

4 months ago

BrainExpanded – The Timeline

See "BrainExpanded - Introduction" for context on this post. Notes and links Over the years,…

5 months ago