Polypheny Go Driver

The Polypheny Go Driver connects Go applications to Polypheny over the Prism Query Interface. It supports SQL through Go’s database/sql package. A driver-specific connection API exposes MongoQL reads and Prism entity metadata.

Installation and compatibility

Use Go 1.23 or newer and a running Polypheny instance with the Prism TCP interface enabled. This page documents driver version v0.1.0, which includes the Prism 2.2 Go bindings. The driver checks the server’s compatibility response when opening a connection. Document collection metadata requires server-side support for the Prism 2.2 document metadata fields.

From an existing Go module, install the driver with the following command.

go get github.com/polypheny/Polypheny-Go-Driver@v0.1.0

Import github.com/polypheny/Polypheny-Go-Driver to register the driver as polypheny. Use a blank import for SQL-only applications, or import the package as polypheny to access its types. For a complete SQL application with setup and transaction examples, see Integrating a Go Application with Polypheny.

Connection settings

Pass polypheny and a DSN in the form host:port,username:password to sql.Open. The default Prism TCP port is 20590. For a local instance with user pa and an empty password, the DSN is localhost:20590,pa:. Keep the final colon when the password is empty. The DSN parser has no escape syntax for commas or colons in the username or password. To use an IPv6 address, enclose it in brackets before the port.

The driver uses unencrypted TCP. Use a trusted network or an encrypted tunnel, keep credentials out of source control, and avoid logging the DSN. Use PingContext to verify connectivity, credentials and protocol compatibility because sql.Open may return before it connects. Reuse the resulting *sql.DB as the application connection pool and close it at shutdown.

SQL execution

Task database/sql API
Read a single row QueryRowContext, then Scan. Check sql.ErrNoRows when the query matches no rows.
Read multiple rows QueryContext, then Next and Scan. Close the rows and check Err after iteration.
Run a statement that returns an update count ExecContext. Use RowsAffected for writes and provide generated IDs explicitly when needed. LastInsertId returns an unsupported-operation error.
Reuse a parameterized statement PrepareContext, then ExecContext, QueryContext, or QueryRowContext on the *sql.Stmt. Close the statement when finished.
Group operations in a transaction BeginTx, then execute all operations through the returned *sql.Tx. Finish with Commit or Rollback.

Use ? for positional SQL parameters and pass values in placeholder order. The driver rejects named arguments such as sql.Named. Statements outside an explicit transaction use auto-commit. The driver accepts the default transaction isolation level with ReadOnly false and rejects nested transactions. The driver fetches all Prism pages and buffers the full result before handing rows to database/sql. Use SQL filters and limits for large results.

SQL value conversions

After the standard database/sql argument conversion, the driver accepts nil, bool, int64, float64, string, []byte and time.Time. A nil []byte becomes SQL NULL. The driver sends time.Time values as Prism timestamps with millisecond precision. Bind variables represent values. Use fixed SQL or validate identifiers separately when constructing a query.

Prism result Value supplied to Scan
NULL nil. Use a nullable scan destination such as sql.NullString when the column can contain NULL.
Boolean bool
Integer, long int64
Float, double float64
String string
Binary, file []byte
Date, time, timestamp time.Time in UTC. A time of day is anchored to the Unix epoch date.
Decimal Exact string, which can use exponent notation. Scan into a string to preserve precision.

SQL row decoding supports the scalar values above. Use the document API for nested documents and arrays.

MongoQL and entity metadata

Reserve a connection with (*sql.DB).Conn, call (*sql.Conn).Raw, and assert the underlying connection as *polypheny.PolyphenyConn inside the callback. Keep the raw driver connection inside the callback and close the *sql.Conn to return it to the pool.

  • QueryMongoContext executes a MongoQL query in the server’s default namespace and returns a pointer to a slice of documents. It expects a document result and takes the query as a string, with no bind arguments or namespace parameter. Use fixed query text for the example below. Top-level map keys are strings even though the signature uses map[any]any. Nested documents are map[string]any, arrays are []any, and numbers retain their Prism width as int32, int64, float32 or float64. Decimal values remain strings.
  • SearchEntities lists entities in an explicitly named namespace. Pass nil to list all entities, or pass a pointer to a name pattern. % matches any sequence and _ matches a single character when used as wildcards. Inspect the returned prism.EntitiesResponse with GetEntities and use GetTable or GetDocument to select the variant. The Go driver exposes no graph query API.

Document metadata

The generated prism package provides the response types. The server returns document fields inferred from a bounded sample of the collection. Treat the result as an observation of the current data. Empty collections can return no fields and no example document.

Type Go getter Meaning
Document GetNamespaceName() Namespace containing the collection.
Document GetCollectionName() Collection name.
Document GetFields() Observed field paths and types, as []*prism.DocumentField.
Document GetSampleDocumentJson() Sample document as a JSON string. Check SampleDocumentJson != nil to distinguish a present value from an absent field.
Document GetDocumentIndexes() Index metadata as []*prism.DocumentIndex, when exposed by the storage adapter.
DocumentField GetFieldPath() Dotted path such as profile.city. The server escapes literal dots and backslashes within key names.
DocumentField GetTypeName() Inferred type, for example string, int, double, bool, array, or object. The server can report null for a field observed only with null values or mixed for incompatible observed types.
DocumentField GetIsOptional() Whether the sample contained a missing or null value for the path.
DocumentIndex GetFieldPath() Indexed field path.
DocumentIndex GetIndexType() Index method name reported by the adapter.
DocumentIndex GetUnique() Whether the adapter reports the indexed field as unique.

Example

In a test instance with public as the default namespace, run these statements in the SQL console to create the example fixtures.

CREATE TABLE public.go_driver_people (id INTEGER PRIMARY KEY, name VARCHAR(40));
INSERT INTO public.go_driver_people (id, name) VALUES (1, 'Ada');
CREATE DOCUMENT NAMESPACE go_driver_documents;

Select go_driver_documents in the MongoQL console and run each of these commands individually.

db.createCollection("people")
db.people.insertOne({"name": "Ada", "profile": {"city": "Basel"}})
db.people.insertOne({"name": "Lin"})

Save this program as main.go in a Go module with the driver installed. The example reads the relational table as documents and inspects the separate document collection’s metadata.

package main

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"time"

	polypheny "github.com/polypheny/Polypheny-Go-Driver"
)

func inspect(ctx context.Context, db *sql.DB) error {
	conn, err := db.Conn(ctx)
	if err != nil {
		return err
	}
	defer conn.Close()

	return conn.Raw(func(raw any) error {
		driverConn, ok := raw.(*polypheny.PolyphenyConn)
		if !ok {
			return fmt.Errorf("unexpected driver connection %T", raw)
		}
		rows, err := driverConn.QueryMongoContext(ctx, `db.go_driver_people.find({id: 1})`)
		if err != nil {
			return err
		}
		for _, row := range *rows {
			fmt.Println("Name:", row["name"])
		}

		pattern := "people"
		response, err := driverConn.SearchEntities(ctx, "go_driver_documents", &pattern)
		if err != nil {
			return err
		}
		for _, entity := range response.GetEntities() {
			document := entity.GetDocument()
			if document == nil {
				continue
			}
			fmt.Printf("Collection: %s.%s\n", document.GetNamespaceName(), document.GetCollectionName())
			for _, field := range document.GetFields() {
				fmt.Printf("%s: %s (optional=%t)\n", field.GetFieldPath(), field.GetTypeName(), field.GetIsOptional())
			}
			if document.SampleDocumentJson != nil {
				fmt.Println("Sample:", document.GetSampleDocumentJson())
			}
			for _, index := range document.GetDocumentIndexes() {
				fmt.Printf("Index on %s: %s (unique=%t)\n", index.GetFieldPath(), index.GetIndexType(), index.GetUnique())
			}
		}
		return nil
	})
}

func run() error {
	db, err := sql.Open("polypheny", "localhost:20590,pa:")
	if err != nil {
		return err
	}
	defer db.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	return inspect(ctx, db)
}

func main() {
	if err := run(); err != nil {
		log.Fatal(err)
	}
}
go run .

The example prints Ada from the relational table and reports profile.city as an optional string field in the document collection. The sample contents and available indexes depend on the storage adapter and the data.

To remove the example fixtures, run these statements in the SQL console.

DROP NAMESPACE go_driver_documents;
DROP TABLE public.go_driver_people;

Driver API reference

Use database/sql for application-level SQL. The exported driver objects below implement database/sql/driver and back the standard library’s connection, statement, transaction and row types. The package exposes no standalone functions.

Type Method Behavior
PolyphenyDriver Open(name string) (driver.Conn, error) Parses the DSN and opens a Prism connection with a background context.
PolyphenyDriver OpenConnector(name string) (driver.Connector, error) Parses the DSN and returns a reusable connector.
*Connector Connect(ctx context.Context) (driver.Conn, error) Opens, authenticates and negotiates the Prism connection.
*Connector Driver() driver.Driver Returns the underlying PolyphenyDriver.
*PolyphenyConn IsValid() bool Reports whether the connection remains eligible for reuse by the pool.
*PolyphenyConn Ping(ctx context.Context) error Checks that the Prism server responds on this connection.
*PolyphenyConn Prepare(query string) (driver.Stmt, error) Prepares SQL with a background context.
*PolyphenyConn PrepareContext(ctx context.Context, query string) (driver.Stmt, error) Prepares SQL with positional parameters on the server.
*PolyphenyConn Close() error Disconnects and releases the TCP connection.
*PolyphenyConn Begin() (driver.Tx, error) Starts a transaction using the default options and a background context.
*PolyphenyConn BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) Starts a transaction by disabling auto-commit. Accepts the default isolation level and ReadOnly: false.
*PolyphenyConn Exec(query string, args []driver.Value) (driver.Result, error) Executes SQL with a background context and returns an update count.
*PolyphenyConn ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) Executes SQL, using a prepared statement when positional arguments are supplied. Returns an update count.
*PolyphenyConn Query(query string, args []driver.Value) (driver.Rows, error) Queries SQL rows with a background context.
*PolyphenyConn QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) Queries SQL rows, using a prepared statement when positional arguments are supplied.
*PolyphenyConn QueryMongoContext(ctx context.Context, query string) (*[]map[any]any, error) Runs a MongoQL query and returns its documents.
*PolyphenyConn SearchEntities(ctx context.Context, namespace string, pattern *string) (*prism.EntitiesResponse, error) Lists entities and their Prism metadata in one namespace.
*PreparedStatement Close() error Releases the prepared statement on the server.
*PreparedStatement NumInput() int Returns the number of positional parameters.
*PreparedStatement Exec(args []driver.Value) (driver.Result, error) Executes prepared SQL with a background context and returns an update count.
*PreparedStatement ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) Executes prepared SQL with positional arguments and returns an update count.
*PreparedStatement Query(args []driver.Value) (driver.Rows, error) Queries prepared SQL rows with a background context.
*PreparedStatement QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) Queries prepared SQL rows with positional arguments.
*PolyphenyRows Columns() []string Returns the SQL column labels, falling back to column names.
*PolyphenyRows Close() error Closes the buffered row iterator.
*PolyphenyRows Next(dest []driver.Value) error Copies the next row into dest, returning io.EOF when exhausted.
*PolyphenyResult RowsAffected() (int64, error) Returns the update count.
*PolyphenyResult LastInsertId() (int64, error) Returns -1 and an unsupported-operation error.
*PolyphenyTransaction Commit() error Commits the transaction and restores auto-commit.
*PolyphenyTransaction Rollback() error Rolls back the transaction and restores auto-commit.
*ClientError Error() string Returns the error message.

ArgSpec represents a prepared statement parameter internally and exposes no fields or methods. See the versioned Go API documentation for symbol declarations and the Prism Protocol for wire types.

Error handling

Check errors from the context-aware methods, Scan, Rows.Err, and transaction completion. The driver can return *polypheny.ClientError for server and driver errors. Use errors.As to identify it. Context and network errors can also occur. A timeout or cancellation during the Prism exchange can invalidate the underlying connection so the pool can open a replacement. Check server-side effects before retrying a write after a connection failure.

© Polypheny GmbH. All Rights Reserved.