Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/z5labs/gogm
Golang Object Graph Mapper for Neo4j
https://github.com/z5labs/gogm
cli cypher edges go golang graph-mapper neo4j ogm
Last synced: about 2 months ago
JSON representation
Golang Object Graph Mapper for Neo4j
- Host: GitHub
- URL: https://github.com/z5labs/gogm
- Owner: z5labs
- License: mit
- Created: 2019-07-02T19:20:00.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2023-05-11T20:41:56.000Z (over 1 year ago)
- Last Synced: 2023-11-07T20:35:04.008Z (about 1 year ago)
- Topics: cli, cypher, edges, go, golang, graph-mapper, neo4j, ogm
- Language: Go
- Homepage:
- Size: 869 KB
- Stars: 133
- Watchers: 5
- Forks: 31
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
[![Go Report Card](https://goreportcard.com/badge/github.com/mindstand/gogm/v2)](https://goreportcard.com/report/github.com/mindstand/gogm/v2)
[![Actions Status](https://github.com/mindstand/gogm/workflows/Go/badge.svg)](https://github.com/mindstand/gogm/actions)
[![GoDoc](https://godoc.org/github.com/mindstand/gogm/v2?status.svg)](https://godoc.org/github.com/mindstand/gogm/v2)
# GoGM Golang Object Graph Mapper v2## Installation
```
go get github.com/mindstand/gogm/v2
```
Note: Do not use `-u` when installing. If you do, gogm will not compile.This is caused by a dependency being updated to go1.18 making it incompatable with go1.17. In a future update, gogm will be updated to go1.18 eliminating this issue.
## Features
- Struct Mapping through the `gogm` struct decorator
- Full support for ACID transactions
- Underlying connection pooling
- Support for HA Casual Clusters using `bolt+routing` through the [Official Neo4j Go Driver](https://github.com/neo4j/neo4j-go-driver)
- Custom queries in addition to built in functionality
- Builder pattern cypher queries using [MindStand's cypher dsl package](https://github.com/mindstand/go-cypherdsl)
- CLI to generate link and unlink functions for gogm structs.
- Multi database support with Neo4j v4## What's new in V2
- GoGM is an object now! This means you can have multiple instances of GoGM at a time
- OpenTracing and Context Support
- Driver has been updated from v1.6 to v4
- Log interface, so anyone can use the logger of their choice instead of being forced to use logrus
- Primary Key strategies to use any type of primary key. GoGM is no longer UUID only!
- TLS now supported| Note: GoGM v1 has been deprecated.
## Usage
### Primary Key Strategy
Primary key strategies allow more customization over primary keys. A strategy is provided to gogm on initialization.
Built in primary key strategies are:
- `gogm.DefaultPrimaryKeyStrategy` -- just use the graph id from neo4j as the primary key
- `gogm.UUIDPrimaryKeyStrategy` -- uuid's as primary keys
```go
// Example of the internal UUID strategy
PrimaryKeyStrategy{
// StrategyName is the name to reference the strategy
StrategyName: "UUID",
// DBName is the name of the field in the database
DBName: "uuid",
// FieldName is the name of the field in go, this will validate to make sure all pk's use the same field name
FieldName: "UUID",
// Type is the reflect type of the primary key, in this case it's a string but it can be any primitive
Type: reflect.TypeOf(""),
// GenIDFunc defines how new ids are generated, in this case we're using googles uuid library
GenIDFunc: func() (id interface{}) {
return uuid.New().String()
},
}
```### Load Strategy
Load strategies allow control over the queries generated by `Load` operations.
Different strategies change the size of the queries sent to the database as well as the amount of work the database has to do.
A load strategy is provided to gomg on initialization.The defined load strategies are:
- `gogm.PATH_LOAD_STRATEGY` -- Use cypher path queries to generate simple queries for load operations.
- `gogm.SCHEMA_LOAD_STRATEGY` -- Leverage the GoGM schema to generate more complex queries for load operations which results in less work for the database.Depending on your use case, `PATH_LOAD_STRATEGY` may result in higher latency.
### Struct Configuration
##### text notates deprecationDecorators that can be used
- `name=` -- used to set the field name that will show up in neo4j.
- `relationship=` -- used to set the name of the edge on that field.
- `direction=` -- used to specify direction of that edge field.
- `index` -- marks field to have an index applied to it.
- `unique` -- marks field to have unique constraint.
- `pk=` -- marks field as a primary key and specifies which pk strategy to use. Can only have one pk, composite pk's are not supported.
- `properties` -- marks that field is using a map. GoGM only supports properties fields of `map[string]interface{}`, `map[string]`, `map[string][]` and `[]`
- `-` -- marks that field will be ignored by the ogm#### Not on relationship member variables
All relationships must be defined as either a pointer to a struct or a slice of struct pointers `*SomeStruct` or `[]*SomeStruct`Use `;` as delimiter between decorator tags.
Ex.
```go
type TdString stringtype MyNeo4jObject struct {
// provides required node field
// use gogm.BaseUUIDNode if you want to use UUIDs
gogm.BaseNodeField string `gogm:"name=field"`
Props map[string]interface{} `gogm:"properties;name=props"` //note that this would show up as `props.` in neo4j
IgnoreMe bool `gogm="-"`
UniqueTypeDef TdString `gogm:"name=unique_type_def"`
Relation *SomeOtherStruct `gogm="relationship=SOME_STRUCT;direction=OUTGOING"`
ManyRelation []*SomeStruct `gogm="relationship=MANY;direction=INCOMING"`
}```
### GOGM Usage
- Edges must implement the [Edge interface](https://github.com/mindstand/gogm/blob/master/interface.go#L28). View the complete example [here](https://github.com/mindstand/gogm/blob/master/examples/example.go).
```go
package mainimport (
"github.com/mindstand/gogm/v2"
"time"
)type tdString string
type tdInt int//structs for the example (can also be found in decoder_test.go)
type VertexA struct {
// provides required node fields
gogm.BaseNodeTestField string `gogm:"name=test_field"`
TestTypeDefString tdString `gogm:"name=test_type_def_string"`
TestTypeDefInt tdInt `gogm:"name=test_type_def_int"`
MapProperty map[string]string `gogm:"name=map_property;properties"`
SliceProperty []string `gogm:"name=slice_property;properties"`
SingleA *VertexB `gogm:"direction=incoming;relationship=test_rel"`
ManyA []*VertexB `gogm:"direction=incoming;relationship=testm2o"`
MultiA []*VertexB `gogm:"direction=incoming;relationship=multib"`
SingleSpecA *EdgeC `gogm:"direction=outgoing;relationship=special_single"`
MultiSpecA []*EdgeC `gogm:"direction=outgoing;relationship=special_multi"`
}type VertexB struct {
// provides required node fields
gogm.BaseNodeTestField string `gogm:"name=test_field"`
TestTime time.Time `gogm:"name=test_time"`
Single *VertexA `gogm:"direction=outgoing;relationship=test_rel"`
ManyB *VertexA `gogm:"direction=outgoing;relationship=testm2o"`
Multi []*VertexA `gogm:"direction=outgoing;relationship=multib"`
SingleSpec *EdgeC `gogm:"direction=incoming;relationship=special_single"`
MultiSpec []*EdgeC `gogm:"direction=incoming;relationship=special_multi"`
}type EdgeC struct {
// provides required node fields
gogm.BaseNodeStart *VertexA
End *VertexB
Test string `gogm:"name=test"`
}func main() {
// define your configuration
config := gogm.Config{
Host: "0.0.0.0",
Port: 7687,
// deprecated in favor of protocol
// IsCluster: false,
Protocol: "neo4j", //also supports neo4j+s, neo4j+ssc, bolt, bolt+s and bolt+ssc
// Specify CA Public Key when using +ssc or +s
CAFileLocation: "my-ca-public.crt",
Username: "neo4j",
Password: "password",
PoolSize: 50,
IndexStrategy: gogm.VALIDATE_INDEX, //other options are ASSERT_INDEX and IGNORE_INDEX
TargetDbs: nil,
// default logger wraps the go "log" package, implement the Logger interface from gogm to use your own logger
Logger: gogm.GetDefaultLogger(),
// define the log level
LogLevel: "DEBUG",
// enable neo4j go driver to log
EnableDriverLogs: false,
// enable gogm to log params in cypher queries. WARNING THIS IS A SECURITY RISK! Only use this when debugging
EnableLogParams: false,
// enable open tracing. Ensure contexts have spans already. GoGM does not make root spans, only child spans
OpentracingEnabled: false,
// specify the method gogm will use to generate Load queries
LoadStrategy: gogm.PATH_LOAD_STRATEGY // set to SCHEMA_LOAD_STRATEGY for schema-aware queries which may reduce load on the database
}// register all vertices and edges
// this is so that GoGM doesn't have to do reflect processing of each edge in real time
// use nil or gogm.DefaultPrimaryKeyStrategy if you only want graph ids
// we are using the default key strategy since our vertices are using BaseNode
_gogm, err := gogm.New(&config, gogm.DefaultPrimaryKeyStrategy, &VertexA{}, &VertexB{}, &EdgeC{})
if err != nil {
panic(err)
}//param is readonly, we're going to make stuff so we're going to do read write
sess, err := _gogm.NewSessionV2(gogm.SessionConfig{AccessMode: gogm.AccessModeWrite})
if err != nil {
panic(err)
}//close the session
defer sess.Close()aVal := &VertexA{
TestField: "woo neo4j",
}bVal := &VertexB{
TestTime: time.Now().UTC(),
}//set bi directional pointer
bVal.Single = aVal
aVal.SingleA = bValerr = sess.SaveDepth(context.Background(), aVal, 2)
if err != nil {
panic(err)
}//load the object we just made (save will set the uuid)
var readin VertexA
err = sess.Load(context.Background(), &readin, aVal.UUID)
if err != nil {
panic(err)
}fmt.Printf("%+v", readin)
}```
## Migrating from V1 to V2
### Initialization
Initialization in gogm v1
```go
config := gogm.Config{
IndexStrategy: gogm.VALIDATE_INDEX, //other options are ASSERT_INDEX and IGNORE_INDEX
PoolSize: 50,
Port: 7687,
IsCluster: false, //tells it whether or not to use `bolt+routing`
Host: "0.0.0.0",
Password: "password",
Username: "neo4j",
}err := gogm.Init(&config, &VertexA{}, &VertexB{}, &EdgeC{})
if err != nil {
panic(err)
}
```Equivalent in GoGM v2
```go
// define your configuration
config := gogm.Config{
IndexStrategy: gogm.VALIDATE_INDEX, //other options are ASSERT_INDEX and IGNORE_INDEX
PoolSize: 50,
Port: 7687,
IsCluster: false, //tells it whether or not to use `bolt+routing`
Host: "0.0.0.0",
Password: "password",
Username: "neo4j",
}// register all vertices and edges
// this is so that GoGM doesn't have to do reflect processing of each edge in real time
// use nil or gogm.DefaultPrimaryKeyStrategy if you only want graph ids
_gogm, err := gogm.New(&config, gogm.UUIDPrimaryKeyStrategy, &VertexA{}, &VertexB{}, &EdgeC{})
if err != nil {
panic(err)
}
gogm.SetGlobalGoGM(_gogm)
```##### Note that we call gogm.SetGloablGogm so that we can still access it from a package level
### Create a session
Creating a session in GoGM v1
```go
sess, err := gogm.NewSession(false)
```
##### Note this still works in v2, its using the global gogm to create the session. Also note this is making an instance of the deprecated `ISession`
Equivalent in GoGM v2
```go
// this would also work with a local instance of gogm (localGogm.NewSessionV2)
sess, err := gogm.G().NewSessionV2(gogm.SessionConfig{AccessMode: gogm.AccessModeWrite})
```### Summary
- Minimal change requires creating a global gogm, everything else should still work with ISession (gogm v1 session object)
- `ISession` is now deprecated but still supported
- SessionV2 is the new standard
### GoGM CLI## CLI Installation
```
go get -u github.com/mindstand/gogm/v2/cmd/gogmcli
```## CLI Usage
```
NAME:
gogmcli - used for neo4j operations from gogm schemaUSAGE:
gogmcli [global options] command [command options] [arguments...]VERSION:
2.1.1COMMANDS:
generate, g, gen to generate link and unlink functions for nodes
help, h Shows a list of commands or help for one commandGLOBAL OPTIONS:
--debug, -d execute in debug mode (default: false)
--help, -h show help (default: false)
--version, -v print the version (default: false)
```## Inspiration
Inspiration came from the Java OGM implementation by Neo4j.## Road Map
- Schema Migration
- Errors overhaul using go 1.13 error wrapping## How you can help
- Report Bugs
- Fix bugs
- Contribute (refer to contribute.md)