Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
"modus/sdk/dgraph",
"modus/sdk/graphql",
"modus/sdk/http",
"modus/sdk/neo4j",
"modus/sdk/models",
"modus/sdk/postgresql"
]
Expand Down
37 changes: 37 additions & 0 deletions modus/app-manifest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ connection types:
| `http` | Connect to an HTTP(S) web server | `http`, `graphql`, `models` |
| `postgresql` | Connect to a PostgreSQL database | `postgresql` |
| `dgraph` | Connect to a Dgraph database | `dgraph` |
| `neo4j` | Connect to a Neo4j database | `neo4j` |

<Warning>
**Don't include secrets directly in the manifest!**
Expand Down Expand Up @@ -329,6 +330,42 @@ This connection type supports connecting to Dgraph databases. You can use the
The API key for the Dgraph database.
</ResponseField>

### Neo4j connection

This connection type supports connecting to Neo4j databases. You can use the
[Neo4j APIs](/modus/sdk/neo4j) in the Modus SDK to interact with the database.

**Example:**

```json modus.json
{
"connections": {
"my-neo4j": {
"type": "neo4j",
"dbUri": "bolt://localhost:7687",
"username": "neo4j",
"password": "{{NEO4J_PASSWORD}}"
}
}
}
```

<ResponseField name="type" type="string" required>
Always set to `"neo4j"` for this connection type.
</ResponseField>

<ResponseField name="dbUri" type="string" required>
The URI for the Neo4j database.
</ResponseField>

<ResponseField name="username" type="string" required>
The username for the Neo4j database.
</ResponseField>

<ResponseField name="password" type="string" required>
The password for the Neo4j database.
</ResponseField>

### Working locally with secrets

When you run your app locally using `modus dev`, the runtime replaces the
Expand Down
2 changes: 1 addition & 1 deletion modus/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export MODUS_PEMS='{\"key1\":\"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0B
```

```bash MODUS_JWKS_ENDPOINTS
export MODUS_JWKS_ENDPOINTS='{"my-auth-provider":"https://myauthprovider.com/application/o/myappname/jwks/"}'
export MODUS_JWKS_ENDPOINTS='{"my-auth-provider":"https://myauthprovider.com/application/o/myappname/.wellknown/jwks.json"}'
```

</CodeGroup>
Expand Down
174 changes: 174 additions & 0 deletions modus/data-fetching.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,180 @@ export function getPerson(name: string): Person {

</CodeGroup>

### Neo4j

Neo4j is a graph database management system. Modus provides a simple way to
query and mutate data in Neo4j with the `neo4j` APIs.

Here is an example of mutating & fetching a person from a Neo4j database using
the Modus SDK:

```go Go
package main

import (
"github.com/hypermodeinc/modus/sdk/go/pkg/neo4j"
)


const host = "my-database"

func CreatePeopleAndRelationships() (string, error) {
people := []map[string]any{
{"name": "Alice", "age": 42, "friends": []string{"Bob", "Peter", "Anna"}},
{"name": "Bob", "age": 19},
{"name": "Peter", "age": 50},
{"name": "Anna", "age": 30},
}

for _, person := range people {
_, err := neo4j.ExecuteQuery(host,
"MERGE (p:Person {name: $person.name, age: $person.age})",
map[string]any{"person": person})
if err != nil {
return "", err
}
}

for _, person := range people {
if person["friends"] != "" {
_, err := neo4j.ExecuteQuery(host, `
MATCH (p:Person {name: $person.name})
UNWIND $person.friends AS friend_name
MATCH (friend:Person {name: friend_name})
MERGE (p)-[:KNOWS]->(friend)
`, map[string]any{
"person": person,
})
if err != nil {
return "", err
}
}
}

return "People and relationships created successfully", nil
}

type Person struct {
Name string `json:"name"`
Age int64 `json:"age"`
}

func GetAliceFriendsUnder40() ([]Person, error) {
response, err := neo4j.ExecuteQuery(host, `
MATCH (p:Person {name: $name})-[:KNOWS]-(friend:Person)
WHERE friend.age < $age
RETURN friend
`,
map[string]any{
"name": "Alice",
"age": 40,
},
neo4j.WithDbName("neo4j"),
)
if err != nil {
return nil, err
}

nodeRecords := make([]Person, len(response.Records))

for i, record := range response.Records {
node, _ := neo4j.GetRecordValue[neo4j.Node](record, "friend")
name, err := neo4j.GetProperty[string](&node, "name")
if err != nil {
return nil, err
}
age, err := neo4j.GetProperty[int64](&node, "age")
if err != nil {
return nil, err
}
nodeRecords[i] = Person{
Name: name,
Age: age,
}
}

return nodeRecords, nil
}
```

```ts AssemblyScript
import { neo4j } from "@hypermode/modus-sdk-as"

// This host name should match one defined in the modus.json manifest file.
const hostName: string = "my-database"

@json
class Person {
name: string
age: i32
friends: string[] | null

constructor(name: string, age: i32, friends: string[] | null = null) {
this.name = name
this.age = age
this.friends = friends
}
}

export function CreatePeopleAndRelationships(): string {
const people: Person[] = [
new Person("Alice", 42, ["Bob", "Peter", "Anna"]),
new Person("Bob", 19),
new Person("Peter", 50),
new Person("Anna", 30),
]

for (let i = 0; i < people.length; i++) {
const createPersonQuery = `
MATCH (p:Person {name: $person.name})
UNWIND $person.friends AS friend_name
MATCH (friend:Person {name: friend_name})
MERGE (p)-[:KNOWS]->(friend)
`
const peopleVars = new neo4j.Variables()
peopleVars.set("person", people[i])
const result = neo4j.executeQuery(hostName, createPersonQuery, peopleVars)
if (!result) {
throw new Error("Error creating person.")
}
}

return "People and relationships created successfully"
}

export function GetAliceFriendsUnder40(): Person[] {
const vars = new neo4j.Variables()
vars.set("name", "Alice")
vars.set("age", 40)

const query = `
MATCH (p:Person {name: $name})-[:KNOWS]-(friend:Person)
WHERE friend.age < $age
RETURN friend
`

const result = neo4j.executeQuery(hostName, query, vars)
if (!result) {
throw new Error("Error getting friends.")
}

const personNodes: Person[] = []

for (let i = 0; i < result.Records.length; i++) {
const record = result.Records[i]
const node = record.getValue<neo4j.Node>("friend")
const person = new Person(
node.getProperty<string>("name"),
node.getProperty<i32>("age"),
)
personNodes.push(person)
}

return personNodes
}
```

## Fetching from APIs

### HTTP
Expand Down
Loading
Loading