Equal Code: cypher-template-strings

Hello and welcome to the first in a new series that's going to be published regularly from Equal Care Co-op: Equal Code. This series is aimed at the more technical folk in our community.

Blobs of colour are connected by thin lines
The Equal Care database is not far off this!

Hello and welcome to the first in a new series that's going to be published regularly from Equal Care Co-op: Equal Code. This series is aimed at the more technical folk in our community, to make sure they know about all the excellent work that we're digging into.

For any readers who aren't a member of the co-op... welcome! If you, like us, are fed up with the usual tech landscape and think there's a better way: there is. This series is our journey to grow that approach, and you're very welcome to join us for the ride.

Over the course of 2023, I'll be regularly posting articles for this series amongst articles about what Equal Care is doing. We don't have a "tech blog" because we don't separate our tech from our people. It's built by us, for us, to solve our problems. We're making the social care system better, one step at a time, by creating technology that enables people to have more control over giving or receiving care.

If you're interested in what we've got to say, then please subscribe for updates!

Today's post is about a small contribution to the open source community, but it's a great improvement for us. Open source principles are very well aligned to co-operative principles, so it's a match made in heaven!

About me

The engineering team

To kick things off, let me introduce myself. I'm Matt, and I'm the engineering team at Equal Care. I've worked in places of all shapes and sizes, but I'm happiest when I'm working in small teams, on big problems. This isn't a CV, so if you're interested in me head over to neverstew.com.


ES6 tagged template strings for prepared statements with neo4j. Latest version: 0.5.1, last published: 5 days ago. Start using cypher-template-strings in your project by running `npm i cypher-template-strings`. There are no other projects in the npm registry using cypher-template-strings.

This week's content is about an open source package that we maintain: cypher-template-strings. cypher-template-strings is an idiomatic way to construct cypher queries, used in some of the biggest graph databases, in modern javascript.

When I arrived at Equal Care, where we use Neo4J as our primary data store (there's another blog post worth of content on our choice of Neo4J), I was really missing some of the conveniences afforded to you when working with enormous open source technologies like PostgreSQL. The fluency with which you can construct a query to a database like Postgres is fantastic and the options are enormous. From ORMs to SQL query builders; you get a lot of choice.

The Neo4J community has been a great source of knowledge so far, but there just aren't as many battle-tested tools that you can pick and use right away. For languages that don't align to the Neo4J stack (JVM-based), the community can be especially small.

One of the packages that I missed the most is sql-template-strings. It turns otherwise verbose queries into an expressive language that is self-describing. In more complex queries, the difference in cognitive load can be huge.

// postgres:
pg.query('SELECT author FROM books WHERE name = $1 AND author = $2', [book, author])

// is equivalent to
pg.query(SQL`SELECT author FROM books WHERE name = ${book} AND author = ${author}`) 

This is where cypher-template-strings comes in!

// neo4j-driver:
driver.run('MATCH (person:Person { id: $id }) RETURN person', { id })

// is equivalent to
driver.run(cypher`MATCH (person:Person { id: ${id} }) RETURN person`)

Nesting statements

One of the primary sources of complex queries in our application tends to be when we're constructing queries that might change based on a few options. Pagination is a great example: sometimes results need to be paginated, sometimes they don't.

cypher-template-strings enhances the paradigm from sql-template-strings by providing the ability to nest statements inside one another. Here's an example of how we might add pagination to the query above:

  MATCH (person:Person {id: ${id}})
  RETURN person
  ${skip && cypher`SKIP ${skip}`}
  ${limit && cypher`LIMIT ${limit}`}

For me, this is an excellent balance of safety and usability. The tooling gets out of my way and lets me write queries the way I want to, whilst remaining safe against injection attacks etc.

Get in touch

If you enjoyed this short article, subscribe for more!

I'm always happy to talk with anyone that finds something interesting in these posts. Please feel free to reach out to me at matt@equalcare.coop.