npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

neogoose

v1.0.0

Published

Node.js Neo4j OGM inspired by Mongoose & GraphQL

Downloads

1

Readme

neogoose

Node.js Neo4j OGM inspired by Mongoose & GraphQL

Node.js CI npm version

neogoose

TLDR

Use GraphQL schema language to define Models. On Model CRUD input validated & output resolved through a generated GraphQL schema. Modularize your neo4js-graphql-js augmented schema with the additional power of an OGM for further database operations.

Models are not designed to support querying relationships use a session for this. This library is designed to place a CRUD api over nodes. You can also create an Executable schema to execute more complex queries.

Installation

First install Node.js, then start Neo4j & finally...

$ npm install neogoose

neo4j-driver and graphql are peerDependencies you may need to install them too.

$ npm install neo4j-driver graphql

Importing

const neogoose = require("neogoose");

Connecting

await neogoose.connect("neo4j://localhost");

Creating Multiple connections

const connection1 = await neogoose.createConnection("neo4j://1.1.1.1");
const connection2 = await neogoose.createConnection("neo4j://2.2.2.2");

Disconnecting

await neogoose.disconnect();

Defining a Model

Models are defined using GraphQL schema language.

const User = neogoose.model(
    "User",
    {
        typeDefs: `
            type User {
                id: ID!
                name: String!
                email: String!
            }
        `
    }
);

Creating a session

await neogoose.connect("neo4j://localhost");

// https://neo4j.com/developer/javascript/
const session = await neogoose.session();

Retrieving a model

const user = neogoose.model("User");

Executable schema

Compile your models into an neo4js-graphql-js augmented schema

const schema = neogoose.makeAugmentedSchema();

Transforms made before calling makeAugmentedSchema

  1. constraint directives removed
  2. Validation directives removed

⚠ All other schema directives here are ignored in neogoose land

Query

Used with;

  1. findOne
  2. findMany
  3. updateOne
  4. updateMany
  5. deleteOne
  6. deleteMany
  7. count

Equality

const dan = await User.findOne({
    name: "Dan",
});

$or

const users = await User.findMany({
    $or: [
        { name: "Dan" },
        { name: "Daniel" }
    ],
});

$and

const users = await User.findMany({
    $and: [
        { name: "Dan" },
        { repo: "neogoose" }
    ],
});

$regex

const users = await User.findMany({
    name: {
        $regex: '(?i)d.*' // equal to new Regex("^d", "i")
    },
});

⚠ Javascript regex not supported use regex stated here

$in

const users = await User.findMany({
    name: {
        $in: ["Dan", "Daniel"]
    },
});

Comparison Operators

  1. $eq
  2. $gt
  3. $gte
  4. $in
  5. $lt
  6. $lte
  7. $ne
  8. $nin

Logical Operators

  1. $and
  2. $or

Evaluation Operators

  1. $regex

Skip/Limit

Used with

  1. findMany
  2. updateMany
  3. deleteMany
const paginatedUsers = await User.findMany(
    query,
    { skip: 30, limit: 10 }
);

Creating nodes

  1. create
  2. createMany
const user = await User.create(
    {
        id: uuid(),
        name: "Dan",
        email: "[email protected]"
    },
    {
        return: true
    }
);

await User.createMany([ ... ])

Find nodes

  1. findMany
  2. findOne
const query = {
    name: "Dan",
};

const users = await User.findMany(query);

const dan = await User.findOne(query);

Update nodes

  1. updateOne
  2. updateMany
const query = {
    name: "Dan",
};

const update = {
    name: "naD"
};

await User.updateMany(query, update);

const user = await User.updateOne(
    query,
    update,
    { return: true } // use to return the updated node
);

Using $set

Regular update will replace all properties use $set to += properties on the node

const query = {
    name: "Dan",
};

const update = {
    repo: "neogoose"
};

const user = await User.updateOne(
    query,
    { $set: update },
    { return: true }
);

user.name // Dan
user.repo // neogoose

Deleting properties

$set to null

const user = await User.updateOne(
    query,
    { $set: { loggedIn: null }
);

Delete nodes

  1. deleteOne
  2. deleteMany
const query = {
    name: "Dan",
};

await User.deleteOne(
    query, 
    {
        detach: true // set to true for DETACH DELETE, delete nodes and relationships
    }
);

const users = await User.deleteMany(
    query, 
    { return: true } // use to return the deleted nodes
);

Count nodes

  1. count
const query = {
    name: "Dan",
};

const userCount = await User.count(
    query
);

Resolvers

Records returned from your Neo4j instance are 'pulled' through a GraphQL schema, you can use Resolvers to achieve 'virtuals' on a model.

const User = neogoose.model(
    "User",
    {
        typeDefs: `
            type User {
                id: ID!
                name: String!
                email: String!
                resolved: String!
            }
        `,
        resolvers: {
            User: {
                id: (root) => root.id, // Not needed
                resolved: () => "I was Resolved"
            }
        }
    }
);

Selection Set

Select more than Autogenerated Selection Set works well with Resolvers and complex nested types, Used with;

  1. findOne
  2. findMany
  3. updateOne
  4. updateMany
  5. deleteOne
  6. deleteMany
const User = neogoose.model(
    "User",
    {
        typeDefs: `
            type NestedType {
                abc: String
            }

            type User {
                id: ID!
                name: String!
                email: String!
                nested: NestedType!
            }
        `
    }
);

const selectionSet = `
    {
        id
        name
        email
        nested {
            abc
        }
    }
`

const dan = await User.findOne(
    {
        name: "Dan",
    },
    { selectionSet }
);

// exists(dan.nested.abc) === true

Autogenerated Selection Set

⚠ If you don't specify Selection Set an auto generated one will be made based on the provided type.

const User = neogoose.model(
    "User",
    {
        typeDefs: `
            type NestedType {
                abc: String
            }

            type User {
                id: ID!
                name: String!
                email: String!
                nested: NestedType!
            }
        `
    }
);

const AUTO_SELECTION_SET = `
    {
        id
        name
        email
        nested # ⚠ ERROR
    }
`

Validation

Built in support for @Validation directive.

const User = neogoose.model(
    "User",
    {
        typeDefs: `
            input UserProperties {
                id: ID! 
                name: String
                email: String
            }

            type User @Validation(properties: UserProperties) {
                id: ID!
                name: String!
                email: String!
            }
        `
    }
);

Auto Validation

⚠ If you don't specify @Validation an auto generated input will be made based on the provided type. Nested input types are not supported!

Before

{
    typeDefs: `
        type User  {
            id: ID!
            name: String!
            email: String!
        }
    `
}

After

The below is representing the Models auto generated schema if you don't provide @Validation directive.

{
    typeDefs: `
        input AUTO_GENERATED { # Default if you don't specify properties
            id: ID!
            name: String!
            email: String!  
        }

        type User @Validation(properties: AUTO_GENERATED) {
            id: ID!
            name: String!
            email: String!
        }
    `
}

Directives

Built in support for graphql-constraint-directive.

const User = neogoose.model(
    "User",
    {
        typeDefs: `
            input UserProperties {
                id: ID! @constraint(minLength: 5, format: "uid")
                name: String @constraint(minLength: 5)
                email: String @constraint(minLength: 5, format: "email")
            }

            type User @Validation(properties: UserProperties) {
                id: ID!
                name: String!
                email: String!
            }
        `
    }
);

@constraint directives are removed before augmented schema generation.