Giter Club home page Giter Club logo

neoism's Introduction

neoism - Neo4j client for Go

Neoism Logo

Package neoism is a Go client library providing access to the Neo4j graph database via its REST API.

Status

System Status
Travis CI Travis CI
CircleCI CircleCI
Coveralls Coveralls
Codecov Codecov

This driver is fairly complete, and may now be suitable for general use. The code has an extensive set of integration tests, but little real-world testing. YMMV; use in production at your own risk.

Requirements

Go 1.1 or later is required.

Tested against Neo4j 2.2.4 and Go 1.4.1.

Installation

Development

go get -v github.com/jmcvetta/neoism

Stable

Neoism is versioned using gopkg.in.

Current release is v1

go get gopkg.in/jmcvetta/neoism.v1

Documentation

See GoDoc or Go Walker for automatically generated documentation.

Usage

Connect to Neo4j Database

db, err := neoism.Connect("http://localhost:7474/db/data")

Create a Node

n, err := db.CreateNode(neoism.Props{"name": "Captain Kirk"})

Issue a Cypher Query

// res will be populated with the query results.  It must be a slice of structs.
res := []struct {
		// `json:` tags matches column names in query
		A   string `json:"a.name"` 
		Rel string `json:"type(r)"`
		B   string `json:"b.name"`
	}{}

// cq holds the Cypher query itself (required), any parameters it may have 
// (optional), and a pointer to a result object (optional).
cq := neoism.CypherQuery{
	// Use backticks for long statements - Cypher is whitespace indifferent
	Statement: `
		MATCH (a:Person)-[r]->(b)
		WHERE a.name = {name}
		RETURN a.name, type(r), b.name
	`,
	Parameters: neoism.Props{"name": "Dr McCoy"},
	Result:     &res,
}

// Issue the query.
err := db.Cypher(&cq)

// Get the first result.
r := res[0]

Issue Cypher queries with a transaction

tx, err := db.Begin(qs)
if err != nil {
  // Handle error
}

cq0 := neoism.CypherQuery{
  Statement: `MATCH (a:Account) WHERE a.uuid = {account_id} SET balance = balance + {amount}`,
  Parameters: neoism.Props{"uuid": "abc123", amount: 20},
}
err = db.Cypher(&cq0)
if err != nil {
  // Handle error
}

cq1 := neoism.CypherQuery{
  Statement: `MATCH (a:Account) WHERE a.uuid = {account_id} SET balance = balance + {amount}`,
  Parameters: neoism.Props{"uuid": "def456", amount: -20},
}
err = db.Cypher(&cq1)
if err != nil {
  // Handle error
}

err := tx.Commit()
if err != nil {
  // Handle error
}

Roadmap

Completed:

  • Node (create/edit/relate/delete/properties)
  • Relationship (create/edit/delete/properties)
  • Legacy Indexing (create/edit/delete/add node/remove node/find/query)
  • Cypher queries
  • Batched Cypher queries
  • Transactional endpoint (Neo4j 2.0)
  • Node labels (Neo4j 2.0)
  • Schema index (Neo4j 2.0)
  • Authentication (Neo4j 2.2)

To Do:

  • Streaming API support - see Issue #22
  • Unique Indexes - probably will not expand support for legacy indexing.
  • Automatic Indexes - "
  • High Availability
  • Traversals - May never be supported due to security concerns. From the manual: "The Traversal REST Endpoint executes arbitrary Groovy code under the hood as part of the evaluators definitions. In hosted and open environments, this can constitute a security risk."
  • Built-In Graph Algorithms
  • Gremlin

Testing

Neoism's test suite respects, but does not require, a NEO4J_URL environment variable. By default it assumes Neo4j is running on localhost:7474, with username neo4j and password foobar.

export NEO4J_URL=http://your_user:[email protected]/db/data/
go test -v .

If you are using a fresh untouched Neo4j instance, you can use the included set_neo4j_password.sh script to set the password to that expected by Neoism's tests:

sh set_neo4j_password.sh

Support

Support and consulting services are available from Silicon Beach Heavy Industries.

Contributing

Contributions in the form of Pull Requests are gladly accepted. Before submitting a PR, please ensure your code passes all tests, and that your changes do not decrease test coverage. I.e. if you add new features also add corresponding new tests.

License

This is Free Software, released under the terms of the GPL v3.

neoism's People

Contributors

asandeep avatar azr avatar bruth avatar cheerfulstoic avatar ebramanti avatar freeeve avatar garywahaha avatar jaschaephraim avatar jmcvetta avatar mjgarton avatar n5i avatar srom avatar wwwdata avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

neoism's Issues

build fails in circleci

It seems circleci builds fail, probably due to an upgrade of neo4j to 2.3.1 used during the build.

One of the issues is fixed at #89

The other is less obvious how to fix. It seems that indexes that are created by the tests do not show up when querying the labels, so they don't get cleaned up by cleanupIndexes(). It's not so obvious how to fix this one.

Cypher result nesting

I am trying to figure out if this is a problem with my code or if it is simply not supported. I want to return a nested json object. Does neoism support that?

For instance cypher:

    WITH {key: "Value"} AS inner
    RETURN {outer: inner}

I can't seem to get this to unmarshal, but it could be my code. Anyone?

Embedded props

Hello there,

Correct me if I'm wrong but it seems to me that embedded props is something not possible at the moment.

params := neoism.Props{
    "movieProps": neoism.Props{
        "title": "The Matrix",
    },
})

I could help doing it if you'd like !

Cheers.

Run transaction with SERIALIZABLE isolation level

First, thanks for the great library!

Not sure if I'm just not seeing it, but is there any way to run a transaction with a different isolation level? There are a couple of transactions that I need to run as SERIALIZABLE instead of READ_COMMITED.

Neo4j 2.0

Thinking about what's necessary to support new features in Neo4j 2.0:

  • Node labels
  • Schema index
    • Rename old index stuff to "Legacy*"?
  • Transactional endpoint

node.GetOrCreateNode doesn't set label to node

Hi there,

I'm not sure if this is an issue or not, but I have to run :

    node, created, err := app.DB.GetOrCreateNode("Word", "Text", params)

    if created {
        node.AddLabel("Word")
    }

To make sure the node has a "Word" label.

Cheers !

NodeIndex() does not containt Href

Hi, if you get index by calling NodeIndex and then you try to add new node to that index, it does not work, there is no URI

&neo4j.NodeIndex{index:neo4j.index{db:(*neo4j.Database)(nil), Name:"users", HrefTemplate:"", Provider:"", IndexType:"", CaseSensitive:true, HrefIndex:""}}

Tests fails

go version : go version go1.2.2 linux/amd64
Neo4J version: "neo4j_version" : "2.1.1"

Output for go test :

[Sun Aug 24 rex] $ go test
18:09:01 pretty.go:46: /home/rex/workspace/go/src/github.com/jmcvetta/neoism/database_test.go:71: &neoism.Database{
Session: &napping.Session{
Client: (_http.Client)(nil),
UnsafeBasicAuth: false,
Log: false,
Userinfo: (_url.Userinfo)(nil),
Header: &http.Header{
"User-Agent": {"neoism"},
},
Params: (*napping.Params)(nil),
},
Url: "http://localhost:7474/db/data",
HrefNode: "http://localhost:7474/db/data/node",
HrefRefNode: "",
HrefNodeIndex: "http://localhost:7474/db/data/index/node",
HrefRelIndex: "http://localhost:7474/db/data/index/relationship",
HrefExtInfo: "http://localhost:7474/db/data/ext",
HrefRelTypes: "http://localhost:7474/db/data/relationship/types",
HrefBatch: "http://localhost:7474/db/data/batch",
HrefCypher: "http://localhost:7474/db/data/cypher",
HrefTransaction: "http://localhost:7474/db/data/transaction",
Version: "2.1.1",
Extensions: map[string]interface {}{
},
}
18:09:01 session.go:163: Get foo://bar.com: unsupported protocol scheme "foo"
18:09:01 database.go:55: Status 404 trying to connect to http://localhost:7474/db/datadatadata
18:09:01 database.go:55: Status 200 trying to connect to http://localhost:7474
--- FAIL: TestCreateIndex (0.54 seconds)
schema_test.go:82:
--- FAIL: TestIndexes (1.32 seconds)
assert.go:15: /home/rex/workspace/go/src/github.com/jmcvetta/neoism/schema_test.go:51
assert.go:24: ! 3 != 8
schema_test.go:82:
--- FAIL: TestDropIndex (0.62 seconds)
schema_test.go:82:
FAIL
exit status 1
FAIL github.com/jmcvetta/neoism 28.585s

Add Support for neo4j 2.2.0

Hi, it seems that neoism does not connect to neo4j 2.2.0,I always get the error

<*errors.errorString | 0xc20802ab00>: {
            s: "Invalid database.  Check URI.",
        }

however seems to work fine with 2.1.x versions

according to the manual, we need to send an Authorization header now with a base64 encoded user:password string http://neo4j.com/docs/2.2.0/rest-api-security.html

but it is still possible to deactivate authentication. So that is a workaround for now: http://neo4j.com/docs/2.2.0/security-server.html#security-server-auth

Allow zero-date

I use time.Time fields in go to represent optional dates as well. time has a IsZero() method to check if the date is set or not.
When no date is stored in the database and I query a node with a date = "null" neoism skips this node.
Expected behavior is that neoism sets the date as empty time.Time{} into the struct.

Set label as param

Is there any way to do something like

statement := `MATCH (xxx) CREATE (n:MyMode:{label} {name:{name}})<-[:R]-(yyy);`
params := neoism.Props{
  "name": user.Name,
  "label": user.Label,
}

API Changes

The currently API, involving things like NodeManager and RelationshipIndexManager, was inspired by Neo4j's built-in Python bindings and by Neography and various other 3rd-party clients. It is okay to use; but it doesn't quite feel right, doesn't feel like an idiomatic Go package.

Therefore I am thinking about moving all the methods currently attached to the various *Manager structs directly onto Database. So instead of writing db.Nodes.Create(nil) you would write db.CreateNode(nil).

Still thinking this over. Open to suggestions.

Breakage with 2.0.0-M05

Neoism passes all tests with Neo4j 2.0.0-M03:

$ go test 2>/dev/null
PASS
ok      github.com/jmcvetta/neoism  15.520s

However the tests fail with Neo4j 2.0.0-M05:

$ go test 2>/dev/null
--- FAIL: TestCypherParameters (2.85 seconds)
    cypher_test.go:60: This syntax is no longer supported (missing properties are now returned as null). Please use (not(has(<ident>.name)) OR <ident>.name=<value>) if you really need the old behavior. (line 4, column 12)
        "           WHERE m.name? = {name}"
                    ^
    assert.go:15: /home/jason/work/go/src/github.com/jmcvetta/neoism/cypher_test.go:68
    assert.go:24: ! []string{"id(n)", "id(r)", "id(m)"} != []string(nil)
--- FAIL: TestCypher (0.78 seconds)
    cypher_test.go:172: This syntax is no longer supported (missing properties are now returned as null). Please use (not(has(<ident>.name)) OR <ident>.name=<value>) if you really need the old behavior. (line 1, column 54)
        "start x = node(5) match x -[r]-> n return type(r), n.name?, n.age?"
                                                              ^
    assert.go:15: /home/jason/work/go/src/github.com/jmcvetta/neoism/cypher_test.go:186
    assert.go:24: ! []string{"type(r)", "n.name?", "n.age?"} != []string(nil)
--- FAIL: TestTxBegin (66.85 seconds)
    transaction_test.go:68: json: cannot unmarshal object into Go value of type []*json.RawMessage
    database_test.go:55: {
          "message" : "Relationship 36 not found",
          "exception" : "NotFoundException",
          "fullname" : "org.neo4j.graphdb.NotFoundException",
          "stacktrace" : [ "org.neo4j.kernel.impl.core.NodeManager.getRelationshipForProxy(NodeManager.java:562)", "org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteRelationship(OldTxStateBridgeImpl.java:145)", "org.neo4j.kernel.impl.api.state.TxStateImpl.relationshipDoDelete(TxStateImpl.java:263)", "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.relationshipDelete(StateHandlingStatementOperations.java:90)", "org.neo4j.kernel.api.operations.ConstraintEnforcingEntityWriteOperations.relationshipDelete(ConstraintEnforcingEntityWriteOperations.java:143)", "org.neo4j.kernel.impl.api.LockingStatementOperations.relationshipDelete(LockingStatementOperations.java:188)", "org.neo4j.kernel.api.DataStatement.relationshipDelete(DataStatement.java:62)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$RelationshipOperations.delete(TransactionBoundQueryContext.scala:167)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$RelationshipOperations.delete(TransactionBoundQueryContext.scala:165)", "org.neo4j.cypher.internal.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:114)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.org$neo4j$cypher$internal$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:53)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:37)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:59)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "org.neo4j.cypher.internal.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)", "org.neo4j.cypher.internal.pipes.PipeWithSource.createResults(Pipe.scala:71)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:153)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:140)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:139)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anon$1.execute(ExecutionPlanBuilder.scala:51)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:70)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:143)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:93)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty6WebServer.invokeDirectly(Jetty6WebServer.java:304)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:123)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:73)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
        }
--- FAIL: TestTxCommit (90.02 seconds)
    transaction_test.go:96: json: cannot unmarshal object into Go value of type []*json.RawMessage
    database_test.go:55: {
          "message" : "Node 72 not found",
          "exception" : "NotFoundException",
          "fullname" : "org.neo4j.graphdb.NotFoundException",
          "stacktrace" : [ "org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:421)", "org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:112)", "org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:249)", "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:83)", "org.neo4j.kernel.api.operations.ConstraintEnforcingEntityWriteOperations.nodeDelete(ConstraintEnforcingEntityWriteOperations.java:137)", "org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:181)", "org.neo4j.kernel.api.DataStatement.nodeDelete(DataStatement.java:47)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:126)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:124)", "org.neo4j.cypher.internal.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:114)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.org$neo4j$cypher$internal$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:59)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "org.neo4j.cypher.internal.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)", "org.neo4j.cypher.internal.pipes.PipeWithSource.createResults(Pipe.scala:71)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:153)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:140)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:139)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anon$1.execute(ExecutionPlanBuilder.scala:51)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:70)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:143)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:93)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty6WebServer.invokeDirectly(Jetty6WebServer.java:304)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:123)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:73)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
        }
--- FAIL: TestTxBadResultObj (90.01 seconds)
    database_test.go:55: {
          "message" : "Node 73 not found",
          "exception" : "NotFoundException",
          "fullname" : "org.neo4j.graphdb.NotFoundException",
          "stacktrace" : [ "org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:421)", "org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:112)", "org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:249)", "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:83)", "org.neo4j.kernel.api.operations.ConstraintEnforcingEntityWriteOperations.nodeDelete(ConstraintEnforcingEntityWriteOperations.java:137)", "org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:181)", "org.neo4j.kernel.api.DataStatement.nodeDelete(DataStatement.java:47)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:126)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:124)", "org.neo4j.cypher.internal.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:114)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.org$neo4j$cypher$internal$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:59)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "org.neo4j.cypher.internal.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)", "org.neo4j.cypher.internal.pipes.PipeWithSource.createResults(Pipe.scala:71)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:153)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:140)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:139)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anon$1.execute(ExecutionPlanBuilder.scala:51)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:70)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:143)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:93)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty6WebServer.invokeDirectly(Jetty6WebServer.java:304)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:123)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:73)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
        }
--- FAIL: TestTxBadQuery (0.03 seconds)
    assert.go:15: /home/jason/work/go/src/github.com/jmcvetta/neoism/transaction_test.go:170
    assert.go:24: ! *errors.errorString != *json.UnmarshalTypeError
--- FAIL: TestTxQuery (89.99 seconds)
    transaction_test.go:193: json: cannot unmarshal object into Go value of type []*json.RawMessage
    database_test.go:55: {
          "message" : "Node 76 not found",
          "exception" : "NotFoundException",
          "fullname" : "org.neo4j.graphdb.NotFoundException",
          "stacktrace" : [ "org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:421)", "org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:112)", "org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:249)", "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:83)", "org.neo4j.kernel.api.operations.ConstraintEnforcingEntityWriteOperations.nodeDelete(ConstraintEnforcingEntityWriteOperations.java:137)", "org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:181)", "org.neo4j.kernel.api.DataStatement.nodeDelete(DataStatement.java:47)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:126)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundQueryContext$NodeOperations.delete(TransactionBoundQueryContext.scala:124)", "org.neo4j.cypher.internal.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:92)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:114)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.org$neo4j$cypher$internal$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:59)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "org.neo4j.cypher.internal.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)", "org.neo4j.cypher.internal.pipes.PipeWithSource.createResults(Pipe.scala:71)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:153)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:140)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:139)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anon$1.execute(ExecutionPlanBuilder.scala:51)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:70)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:143)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:93)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty6WebServer.invokeDirectly(Jetty6WebServer.java:304)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:188)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:159)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:123)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:73)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)" ]
        }
FAIL
exit status 1
FAIL    github.com/jmcvetta/neoism  354.080s

Looks like this is caused by some syntax changes... still investigating.

Node labels

Support new node labels feature in Neo4j 2.0.

Calling methods on nodes returned by CypherQuery is awkward

I was stuck for a few hours today trying to figure out what I was doing wrong until the helpful guys at StackOverflow pointed me in the right direction. See here for details and example code:

http://stackoverflow.com/questions/27405705/golang-neoism-calling-methods-of-objects-returned-by-query-leads-to-panic

It turns out that you have to initialize the Db property of nodes returned by CypherQuery manually before you can call methods like SetProperty. Of course, you can do that once you are aware it has to be done, but it feels very awkward. Is there a more intuitive way of handling this?

Cypher collection results don't work

I'll try to submit a patch... this is my query:

match n:Run-[:scores]->scores
return n.version, n.released, collect(scores)

The last column is throwing an error.

Schema index

Support new schema index features in Neo4j 2.0.

Comments in cypher causes error

I'm receiving the "Unable to commit transaction" error when comment is present in cypher. Query() is used.

Under the comment I mean a string escaped with "//".

The bug appeared after the lib updating about a month ago. Previous version worked well.

Null Pointer Exception

websites, _ := DB.NodesByLabel("Website")
for _, website := range websites {
stmt := MATCH (webpage:Webpage)-[]->(website:Website{website:{website}}) RETURN webpage;
address, _ := website.Property("address")
params := neoism.Props{"website": address}

    // query results
    res := []struct {
        Webpage neoism.Node `json:"webpage"`
    }{}

    // construct query
    cq := neoism.CypherQuery{
        Statement:  stmt,
        Parameters: params,
        Result:     &res,
    }
    // execute query
    err := DB.Cypher(&cq)
    fmt.Println(err, res[0].Webpage.Id())  
}

Here err is nil but res[0].Webpage is typeof Node and still have not Id() method and Data present in this object.

Support for update statistics?

Hi there, thank you for this library!

One issue for me is that it is impossible to easily tell if a query resulted in updates in the database (e.g. how many nodes, relationships, labels, properties were added or deleted). Is this supported by the Neo4j REST API?

Fetch *Node via CypherQuery?

Hello.

First off, thanks for writing this great API.

I'm trying to perform a Relate() to join two nodes. I need to obviously have a *Node reference to call this and it seems that the only way to get a *Node reference is to either call Node(id int), GetOrCreateNode(...), or CreateNode(...). It doesn't seem like I can fetch one via the CypherQuery() method, as that gives a slice of Node variables without allowing me to get the Id of the Node.

So my question is that, if I don't know the ID of a given node, what is the easiest way to fetch a *Node reference without needing to call GetOrCreateNode() (or any one of the other functions mentioned above)?

Batch support

Thinking about how to implement batch operations. Afaik the REST API allows any standard call to be included in a batch operation. A not-yet-existing node can be referred to by its batch ID number. It looks like the batch ID syntax ({ 2 } refers to the result of batch item 2) gets replaced in subsequent commands by the self URL of the previously created entity. Not sure how well this will work for all operations.

For instance, we can probably add a newly created node to an index by supplying the batch ID syntax in the uri field of the POST. But how can we delete that same index later in the batch, since the actual node ID is required to compose the URL for the DELETE request?

Should batch support be added to existing Node and Relationship objects? That approach means that some methods, when used in a batch, will always return errors. Maybe it is better to have separate TxNode and TxRelationship objects with a limited subset of methods?

http://www.mail-archive.com/[email protected]/msg14045.html

The py2neo driver lets you do index removes in a batch, but they can only refer to a pre-existing node: https://github.com/nigelsmall/py2neo/blob/master/src/py2neo/neo4j.py#L390

Make `Node` struct directly populatable from JSON

Currently Node and Relationship cannot be directly populated from REST results. This is because they both have baseEntity embedded. A helper method, populate(), is used instead.

This is inconvenient, because it means we cannot call Cypher() with a [][]Node result object and get out Node slices automagically populated.

However it will be a bit of an undertaking to make this work in a nice way.

Error building newest version

I get this error

../../jmcvetta/neoism/entity.go:61: not enough arguments in call to e.Db.Session.Delete

Looks to be because Delete requires url string, p *url.Values, result, errMsg interface{} now instead of url string, result, errMsg interface{}.

Tests fail with a fresh installation of neo4j and neoism

When trying to run the tests for the project with a fresh installation of Neo4j 2.0 M06, TestCypherBatch, TestTxBegin, TestTxCommit and TestTxQuery all fail.

Output:

[~] go test -v
=== RUN TestCypherParameters
--- PASS: TestCypherParameters (0.49 seconds)
=== RUN TestCypher
--- PASS: TestCypher (0.08 seconds)
=== RUN TestCypherBadQuery
--- PASS: TestCypherBadQuery (0.02 seconds)
=== RUN TestCypherBatch
--- FAIL: TestCypherBatch (0.08 seconds)
    cypher_test.go:237: {
          "message" : "Parenthesis are required to identify nodes in patterns (line 1, column 8)\n\" MATCH a:Person, b:Person WHERE a.name = 'Mr Spock' AND b.name = 'Mr Sulu' CREATE a-[r:Knows]->b RETURN r \"\n        ^",
          "exception" : "SyntaxException",
          "fullname" : "org.neo4j.cypher.SyntaxException",
          "stacktrace" : [ "org.neo4j.cypher.internal.parser.v2_0.CypherParserImpl$$anonfun$parse$1.apply(CypherParserImpl.scala:46)", "org.neo4j.cypher.internal.parser.v2_0.CypherParserImpl$$anonfun$parse$1.apply(CypherParserImpl.scala:45)", "scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)", "scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)", "scala.collection.immutable.List.foreach(List.scala:318)", "scala.collection.TraversableLike$class.map(TraversableLike.scala:244)", "scala.collection.AbstractTraversable.map(Traversable.scala:105)", "org.neo4j.cypher.internal.parser.v2_0.CypherParserImpl.parse(CypherParserImpl.scala:45)", "org.neo4j.cypher.internal.CypherParser$VersionProxy.parse(CypherParser.scala:43)", "org.neo4j.cypher.ExecutionEngine$$anonfun$3.apply(ExecutionEngine.scala:96)", "org.neo4j.cypher.ExecutionEngine$$anonfun$3.apply(ExecutionEngine.scala:95)", "org.neo4j.cypher.internal.LRUCache.getOrElseUpdate(LRUCache.scala:34)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:95)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:90)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty9WebServer.invokeDirectly(Jetty9WebServer.java:310)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:200)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:171)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:126)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:76)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "java.lang.Thread.run(Thread.java:744)" ]
        }
=== RUN TestCypherBadBatch
--- PASS: TestCypherBadBatch (0.03 seconds)
=== RUN TestConnect
--- PASS: TestConnect (0.00 seconds)
=== RUN TestConnectInvalidUrl
22:17:47 session.go:145: Get foo://bar.com: unsupported protocol scheme "foo"
22:17:47 database.go:55: Status 404 trying to connect to http://localhost:7474/db/datadatadata
22:17:47 database.go:55: Status 200 trying to connect to http://localhost:7474
--- PASS: TestConnectInvalidUrl (0.00 seconds)
=== RUN TestCreateLegacyNodeIndex
--- PASS: TestCreateLegacyNodeIndex (0.01 seconds)
=== RUN TestLegacyNodeIndexCreateWithConf
--- PASS: TestLegacyNodeIndexCreateWithConf (0.01 seconds)
=== RUN TestDeleteLegacyNodeIndex
--- PASS: TestDeleteLegacyNodeIndex (0.02 seconds)
=== RUN TestListLegacyNodeIndexes
--- PASS: TestListLegacyNodeIndexes (0.01 seconds)
=== RUN TestAddNodeToIndex
--- PASS: TestAddNodeToIndex (0.02 seconds)
=== RUN TestAddNodeToExistingIndex
--- PASS: TestAddNodeToExistingIndex (0.03 seconds)
=== RUN TestRemoveNodeFromIndex
--- PASS: TestRemoveNodeFromIndex (0.03 seconds)
=== RUN TestRemoveNodeAndKeyFromIndex
--- PASS: TestRemoveNodeAndKeyFromIndex (0.03 seconds)
=== RUN TestRemoveNodeKeyAndValueFromIndex
--- PASS: TestRemoveNodeKeyAndValueFromIndex (0.02 seconds)
=== RUN TestFindNodeByExactMatch
--- PASS: TestFindNodeByExactMatch (0.07 seconds)
=== RUN TestFindNodeByQuery
--- PASS: TestFindNodeByQuery (0.09 seconds)
=== RUN TestCreateNode
--- PASS: TestCreateNode (0.02 seconds)
=== RUN TestCreateNodeWithProperties
--- PASS: TestCreateNodeWithProperties (0.02 seconds)
=== RUN TestGetOrCreateNode
--- PASS: TestGetOrCreateNode (0.04 seconds)
=== RUN TestGetNode
--- PASS: TestGetNode (0.02 seconds)
=== RUN TestGetNonexistentNode
--- PASS: TestGetNonexistentNode (0.01 seconds)
=== RUN TestDeleteNode
--- PASS: TestDeleteNode (0.02 seconds)
=== RUN TestDeleteNodeWithRelationships
--- PASS: TestDeleteNodeWithRelationships (0.02 seconds)
=== RUN TestSetPropertyOnNode
--- PASS: TestSetPropertyOnNode (0.02 seconds)
=== RUN TestSetBadPropertyOnNode
--- PASS: TestSetBadPropertyOnNode (0.02 seconds)
=== RUN TestUpdatePropertyOnNode
--- PASS: TestUpdatePropertyOnNode (0.02 seconds)
=== RUN TestGetPropertiesForNode
--- PASS: TestGetPropertiesForNode (0.02 seconds)
=== RUN TestDeleteAllPropertiesFromNode
--- PASS: TestDeleteAllPropertiesFromNode (0.02 seconds)
=== RUN TestDeleteNamedPropertyFromNode
--- PASS: TestDeleteNamedPropertyFromNode (0.02 seconds)
=== RUN TestNodeProperty
--- PASS: TestNodeProperty (0.02 seconds)
=== RUN TestAddLabels
--- PASS: TestAddLabels (0.03 seconds)
=== RUN TestLabelsInvalidNode
--- PASS: TestLabelsInvalidNode (0.02 seconds)
=== RUN TestRemoveLabel
--- PASS: TestRemoveLabel (0.03 seconds)
=== RUN TestAddLabelInvalidName
--- PASS: TestAddLabelInvalidName (0.02 seconds)
=== RUN TestSetLabels
--- PASS: TestSetLabels (0.03 seconds)
=== RUN TestNodesByLabel
--- PASS: TestNodesByLabel (0.04 seconds)
=== RUN TestGetAllLabels
--- PASS: TestGetAllLabels (0.02 seconds)
=== RUN TestRelationshipIndexes
--- PASS: TestRelationshipIndexes (0.01 seconds)
=== RUN TestBadCreateLegacyRelIndex
--- PASS: TestBadCreateLegacyRelIndex (0.00 seconds)
=== RUN TestGetRelationshipById
--- PASS: TestGetRelationshipById (0.02 seconds)
=== RUN TestCreateRelationship
--- PASS: TestCreateRelationship (0.03 seconds)
=== RUN TestCreateRelationshipWithProperties
--- PASS: TestCreateRelationshipWithProperties (0.02 seconds)
=== RUN TestDeleteRelationship
--- PASS: TestDeleteRelationship (0.02 seconds)
=== RUN TestGetAllPropertiesOnRelationship
--- PASS: TestGetAllPropertiesOnRelationship (0.02 seconds)
=== RUN TestSetAllPropertiesOnRelationship
--- PASS: TestSetAllPropertiesOnRelationship (0.02 seconds)
=== RUN TestGetSinglePropertyOnRelationship
--- PASS: TestGetSinglePropertyOnRelationship (0.02 seconds)
=== RUN TestSetSinglePropertyOnRelationship
--- PASS: TestSetSinglePropertyOnRelationship (0.02 seconds)
=== RUN TestGetAllRelationships
--- PASS: TestGetAllRelationships (0.03 seconds)
=== RUN TestGetIncomingRelationships
--- PASS: TestGetIncomingRelationships (0.03 seconds)
=== RUN TestGetOutgoingRelationships
--- PASS: TestGetOutgoingRelationships (0.02 seconds)
=== RUN TestGetTypedRelationships
--- PASS: TestGetTypedRelationships (0.03 seconds)
=== RUN TestGetRelationshipsOnNodeWithoutRelationships
--- PASS: TestGetRelationshipsOnNodeWithoutRelationships (0.01 seconds)
=== RUN TestGetRelationshipTypes
--- PASS: TestGetRelationshipTypes (0.05 seconds)
=== RUN TestRelationshipStartEnd
--- PASS: TestRelationshipStartEnd (0.03 seconds)
=== RUN TestCreateIndex
--- PASS: TestCreateIndex (0.05 seconds)
=== RUN TestIndexes
--- PASS: TestIndexes (0.04 seconds)
=== RUN TestDropIndex
--- PASS: TestDropIndex (0.04 seconds)
=== RUN TestTxBegin
--- FAIL: TestTxBegin (0.05 seconds)
    transaction_test.go:69: Error with a query inside a transaction.
=== RUN TestTxCommit
--- FAIL: TestTxCommit (83.78 seconds)
    transaction_test.go:115: Parenthesis are required to identify nodes in patterns (line 1, column 8)
        " MATCH n:Person WHERE n.name = {name} RETURN n.name "
                ^
    database_test.go:55: {
          "message" : "Node 73 not found",
          "exception" : "NotFoundException",
          "fullname" : "org.neo4j.graphdb.NotFoundException",
          "stacktrace" : [ "org.neo4j.kernel.impl.core.NodeManager.getNodeForProxy(NodeManager.java:420)", "org.neo4j.kernel.impl.api.state.OldTxStateBridgeImpl.deleteNode(OldTxStateBridgeImpl.java:111)", "org.neo4j.kernel.impl.api.state.TxStateImpl.nodeDoDelete(TxStateImpl.java:249)", "org.neo4j.kernel.impl.api.StateHandlingStatementOperations.nodeDelete(StateHandlingStatementOperations.java:86)", "org.neo4j.kernel.api.operations.ConstraintEnforcingEntityOperations.nodeDelete(ConstraintEnforcingEntityOperations.java:132)", "org.neo4j.kernel.impl.api.LockingStatementOperations.nodeDelete(LockingStatementOperations.java:182)", "org.neo4j.kernel.api.OperationsFacade.nodeDelete(OperationsFacade.java:424)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:128)", "org.neo4j.cypher.internal.spi.gdsimpl.TransactionBoundExecutionContext$NodeOperations.delete(TransactionBoundExecutionContext.scala:126)", "org.neo4j.cypher.internal.spi.DelegatingOperations.delete(DelegatingQueryContext.scala:94)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$super$delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply$mcV$sp(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations$$anonfun$delete$1.apply(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext.org$neo4j$cypher$internal$spi$ExceptionTranslatingQueryContext$$translateException(ExceptionTranslatingQueryContext.scala:149)", "org.neo4j.cypher.internal.spi.ExceptionTranslatingQueryContext$ExceptionTranslatingOperations.delete(ExceptionTranslatingQueryContext.scala:118)", "org.neo4j.cypher.internal.spi.UpdateCountingQueryContext$CountingOps.delete(UpdateCountingQueryContext.scala:114)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.org$neo4j$cypher$internal$mutation$DeleteEntityAction$$delete(DeleteEntityAction.scala:50)", "org.neo4j.cypher.internal.mutation.DeleteEntityAction.exec(DeleteEntityAction.scala:36)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe.org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$exec(ExecuteUpdateCommandsPipe.scala:59)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "org.neo4j.cypher.internal.pipes.ExecuteUpdateCommandsPipe$$anonfun$org$neo4j$cypher$internal$pipes$ExecuteUpdateCommandsPipe$$executeMutationCommands$1$$anonfun$apply$2.apply(ExecuteUpdateCommandsPipe.scala:48)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "scala.collection.Iterator$$anon$13.hasNext(Iterator.scala:371)", "org.neo4j.cypher.internal.pipes.EmptyResultPipe.internalCreateResults(EmptyResultPipe.scala:28)", "org.neo4j.cypher.internal.pipes.PipeWithSource.createResults(Pipe.scala:71)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder.org$neo4j$cypher$internal$executionplan$ExecutionPlanBuilder$$prepareStateAndResult(ExecutionPlanBuilder.scala:152)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:139)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anonfun$2.apply(ExecutionPlanBuilder.scala:138)", "org.neo4j.cypher.internal.executionplan.ExecutionPlanBuilder$$anon$1.execute(ExecutionPlanBuilder.scala:51)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:70)", "org.neo4j.cypher.ExecutionEngine$$anonfun$execute$1.apply(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:136)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:69)", "org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:90)", "org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:80)", "org.neo4j.server.rest.web.CypherService.cypher(CypherService.java:100)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "org.neo4j.server.web.Jetty9WebServer.invokeDirectly(Jetty9WebServer.java:310)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.invoke(NonStreamingBatchOperations.java:55)", "org.neo4j.server.rest.batch.BatchOperations.performRequest(BatchOperations.java:200)", "org.neo4j.server.rest.batch.BatchOperations.parseAndPerform(BatchOperations.java:171)", "org.neo4j.server.rest.batch.NonStreamingBatchOperations.performBatchJobs(NonStreamingBatchOperations.java:48)", "org.neo4j.server.rest.web.BatchOperationService.batchProcess(BatchOperationService.java:126)", "org.neo4j.server.rest.web.BatchOperationService.performBatchOperations(BatchOperationService.java:76)", "java.lang.reflect.Method.invoke(Method.java:606)", "org.neo4j.server.rest.transactional.TransactionalRequestDispatcher.dispatch(TransactionalRequestDispatcher.java:132)", "org.neo4j.server.rest.security.SecurityFilter.doFilter(SecurityFilter.java:112)", "java.lang.Thread.run(Thread.java:744)" ]
        }
=== RUN TestTxBadResultObj
--- PASS: TestTxBadResultObj (0.02 seconds)
=== RUN TestTxBadQuery
--- PASS: TestTxBadQuery (0.01 seconds)
=== RUN TestTxQuery
22:19:12 pretty.go:46: /Users/marpaia/go/src/github.com/jmcvetta/neoism/transaction_test.go:210: []neoism.TxError{
    {Code:42001, Status:"STATEMENT_SYNTAX_ERROR", Message:"Parenthesis are required to identify nodes in patterns (line 2, column 11)\n\"\t\t\t\tMATCH a:Person, b:Person\"\n           ^"},
}
--- FAIL: TestTxQuery (0.02 seconds)
    transaction_test.go:211: Error with a query inside a transaction.
=== RUN TestTxRollback
--- PASS: TestTxRollback (0.02 seconds)
=== RUN TestTxQueryBad
--- PASS: TestTxQueryBad (0.01 seconds)
FAIL
exit status 1
FAIL    github.com/jmcvetta/neoism  86.006s

Node.SetProperty Only Allows String Properties

The function signature of Node.SetProperty is as follows:

func (e *Node) SetProperty(key string, value string) error

I would like my value to be a bool. Can you make the type of value be interface{}? You should be able to deal with non-string properties as you do when you pass a neoism.Props struct to Node.SetProperties...

repo name conflicts with neo4j itself

I know it's probably overly annoying to change it now, but the name is the same as neo4j itself, which is maybe only annoying to people like me who have forked both. If you ever have reason to rename it... please take this into consideration. :)

Feel free to close this issue.

Examples needed.

Currently the only example code for new users of neoism is embedded in the Go package docs: http://godoc.org/github.com/jmcvetta/neoism

It would be nice to split that out into an actual example program. Not sure if there is a way to have the contents of a .go file included in the automatic package docs, or if this will have to be copypasta.

Upsert

Hi,

I am trying to add a Upsert function to this package. I've copied GetOrCreateNode() as follows:

// UpdateOrCreateNode updates a node's properties or creates it if it doesn’t already exist.
func (db *Database) UpdateOrCreateNode(label, key string, p Props) (n *Node, created bool, err error) {

    value, ok := p[key]
    if !ok {
        return nil, false, errors.New("Properties must contain key")
    }
    n = &Node{}
    n.Db = db
    ne := NeoError{}
    uri := join(db.HrefNodeIndex, label) + "?uniqueness=create_or_fail"
    type s struct {
        Key   string      `json:"key"`
        Value interface{} `json:"value"`
        Props Props       `json:"properties"`
    }
    payload := s{
        Key:   key,
        Value: value,
        Props: p,
    }
    fmt.Println(db)
    resp, err := db.Session.Post(uri, &payload, &n, &ne)
    if err != nil {
        return nil, false, err
    }
    switch resp.Status() {
    case 409:

        // update the node since it exists
        existingNode := &Node{}
        resp.Unmarshal(&existingNode)
        existingNode.Db = db
        existingNode.SetProperties(p)
        return existingNode, false, nil // Updated node

    case 201:
        return n, true, nil // Created node
    }
    return nil, false, ne // Error
}

Note that with 'create_or_fail' Neo4j returns a 409 (Conflict) but does return the node in n.

Napping, however, doesn't unmarshall it:

https://github.com/jmcvetta/napping/blob/master/session.go#L203

Do you have any suggestion re making this less messy in anticipation of pushing it to you?

Can't connect to GrapheneDB

Hello there,

When I try to connect to Graphene DB I get the following output :

14:40:14.646490 database.go:55: Status 200 trying to connect to http://app****:****@app***.sb02.stations.graphenedb.com:24783
panic: Invalid database.  Check URI.

I think it comes from the style of the url.

Cheers.

query results and JSON handling

Starting a thread to talk about JSON (un)marshalling for query results.
disclaimer: I'm not overly familiar with this package yet.
I've seen some comments in other issues on this topic.

Also a couple comments in the code:

func (cq *CypherQuery) Unmarshal(v interface{}) error {
    // We do a round-trip thru the JSON marshaller.  A fairly simple way to
    // do type-safe unmarshalling, but perhaps not the most efficient solution.
// Cypher executes a db query written in the Cypher language.  Data returned
// from the db is used to populate `result`, which should be a pointer to a
// slice of structs.  TODO:  Or a pointer to a two-dimensional array of structs?
func (db *Database) Cypher(q *CypherQuery) error {

There also seems to be multiple round-trips through the marshaller, both in neoism and the napping API client.

I think what happens is the response to an API call, correct me if I'm wrong.

  • napping/session.go:Send()
    • r.body, err = ioutil.ReadAll(resp.Body)
    • err = json.Unmarshal(r.body, r.Result) where r.Result is an interface{} with the underlying object actual being a cpyherResult struct.
  • neoism/cypher.go
    • Cypher() uses the CypherQuery.Unmarshal()
    • CypherQuery.Unmarshal() uses a round-trip to golang/json : Marshal and Unmarshal
    • some of this is eased with the cypherResult : Data [][]*json.RawMessage

This stack is probably important to understanding the performance issues as cypherResult uses json.RawMessage in order to delay the actual unmarshalling, but there is an intermediate interface{}, as well as several calls to Unmarshal. Still sorting this out in my head...

Also, any thoughts on building an ORM or using Golang reflection for some of this process?
What about a chainable API?

Post EOF error

Neoism sometimes returns the error Post http://neo4jhost:7474/db/data/cypher: EOF. It's happened on multiple different queries, so it doesn't seem to be query specific. An example query that failed was

MATCH (d:Dog {name: {name}})
SET d.found = true

Rerunning the same query later succeeded. Any ideas as to why this is happening and how I can prevent it?

Support for paths

There appears to be no support for returning paths. I think adding such support will ease the lack of a traversal API. e.g. it would be great to do something like:

cq := `start node=node(1) match path=node-[*]->(endpoint :leaf) return node,path,endpoint`
type response struct {
    Node neoism.Node `json:"node"`
    Path neoism.Path `json:"path"`
    Endpoint neoism.Node `json:"endpoint"`
} // note: Node and Endpoint are redundant if Path worked

Effectively finding me all the paths from node 1 to any leaves. So a Path can be a struct with []*Relationships (or Rels) + the db fields. With that information, i'd easily be able to walk from Path[0].Start() to Path[-1].End().

disclaimer: i do understand that i can iterate from the node myself through node.Outgoing() recursively and it wouldn't be much difference, but being able to specify the structure of the expected path declaratively is the real win with Path support.

support for GAE Google App Engine

Have you considered adding support for Google Ap Engine? There are a few of dependancies that currently break this as well as a need to swap out the default http.Client. Thanks.

Neo4j properties can be of many primitive types or an array

the Node.Property() and Relationship.Property() methods are convenient to use for string props but not for non-string props. Have you guys had any discussions on it? Like introducing another method that returns interfaces.. The all props method does however return map[string]interface{}, just thinking if there is a way to make them consistent...

token-based authentication for Neo 2.2

Neo4j 2.2 adds token-based authentication and is available in RC. I saw this listed as a future enhancement but wanted to formally track it here. Thanks.

GetOrCreateNode doesn't attach a label to a node, as it's signature indicates

The GetOrCreateNode (https://github.com/jmcvetta/neoism/blob/master/node.go#L38) function accept a parameter label, which would indicate that a node with the given parameters would be returned (created if necessary) and have the given label attached.

This isn't the case, because the label variable actually indicates an index, not a label in the REST api. See http://docs.neo4j.org/chunked/stable/rest-api-indexes.html#rest-api-create-node-index for more details.

Additionally, it seems as though that, although the index that is specified gets created, the node that gets created is not apart of the index?

For example, consider the following Go:

package main

import (
    "github.com/jmcvetta/neoism"
)

func main() {
    db, _ := neoism.Connect("http://localhost:7474/db/data")

    db.GetOrCreateNode("Person", "name", neoism.Props{"name": "Matt"})
}

and, after, running that, consider the following API calls:

[~] curl http://localhost:7474/db/data/index/node
{
  "hcHKCYjxGedR" : {
    "template" : "http://localhost:7474/db/data/index/node/hcHKCYjxGedR/{key}/{value}",
    "provider" : "lucene",
    "type" : "exact"
  },
  "Person" : {
    "template" : "http://localhost:7474/db/data/index/node/Person/{key}/{value}",
    "provider" : "lucene",
    "type" : "exact"
  }
}                                                                                                                    
[~] curl http://localhost:7474/db/data/index/node/Person
[ ]

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.