Documentation ¶
Overview ¶
Package rdms provides types for interacting with relational (SQL) databases.
A full explanation of Grantic's patterns for relational database access management system (RDBMS) access can be found at http://granitic.io/1.0/ref/rdbms-access A brief explanation follows:
Principles ¶
Granitic's RDBMS access types and components adhere to a number of principles:
1. Application developers should be given the option to keep query definitions separate from application code.
2. Boilerplate code for generating queries and mapping results should be minimised.
3. Transactional and non-transactional DB access should not require different coding patterns.
4. Code that is executing queries against a database should be readable and have obvious intent.
Facilities ¶
To use Granitic's RDBMS access, your application will need to enable both the QueryManager and RdbmsAccess facilities. See http://granitic.io/1.0/ref/facilities for more details.
Components and types ¶
Enabling these facilities creates the QueryManager and RDBMSClientManager components. Your application must provide a DatabaseProvider (see below)
DatabaseProvider A component able to provide connections to an RDBMS by creating and managing Go sql.DB objects. QueryManager A component that loads files containing template queries from a filesystem and can populate than with provided variables to create a complete SQL query. RDBMSClient A type providing methods to execute templated queries against an RDBMS. RDBMSClientManager A component able to create RDBMSClient objects. RowBinder A type able to map SQL query results into Go structs.
DatabaseProvider ¶
Because of the way Go applications are built (statically linked), drivers for individual RDBMSs cannot be dynamically loaded at runtime. To avoid the Granitic framework importing large numbers of third-party libraries, Granitic application developers must create a component that implements rdbms.DatabaseProvider and imports the driver for the database in use.
A simple implementation of DatabaseProvider for a MySQL database can be found in the granitic-examples repo on GitHub in the recordstore/database/provider.go file.
Once you have an implementation, you will need to create a component for it in your application's component definition file similar to:
{ "dbProvider": { "type": "database.DBProvider" } }
As long as you only have one implementation of DatabaseProvider registered as a component, it will automatically be injected into the RDBMSClientManager component.
QueryManager ¶
Refer to the dsquery package for more details on how QueryManagers work.5 ¶
RDBMSClientManager ¶
Granitic applications are discouraged from directly interacting with sql.DB objects (although of course they are free to do so). Instead, they use instances of RDBMSClient. RDBMSClient objects are not reusable across goroutines, instead your application will need to ask for a new one to be created for each new goroutine (e.g. for each request in a web services application).
The component that is able to provide these clients is RDBMSClientManager.
Auto-injection of an RDBMSClientManager ¶
Any component that needs an RDBMSClient should have a field:
DBClientManager rdbms.RDBMSClientManager
The name DBClientManager is a default. You can change the field that Granitic looks for by setting the following in your application configuration.
{ "RdbmsAccess":{ "InjectFieldNames": ["DBClientManager", "MyAlternateFieldName"] } }
Your code then obtains an RDBMSClient in a manner similar to:
var rc *rdbms.RDBMSClient var err error if rc, err = id.DBClientManager.Client(); err != nil { return err }
RDBMSClient ¶
Application code executes SQL (either directly or via a templated query) and interacts with transactions via an instance of RDBMSClient. Refer to the GoDoc for RDBMSClient for information on the methods available, but the general pattern for the methods available on RDBMSClient is:
SQLVerb[BindingType]QID[ParameterSource]
Where
SQLVerb Is Select, Delete, Update or Insert BindingType Is optional and can be Bind or BindSingle ParameterSource Is optional and can be either Param, Params or Tags
QID ¶
A QID is the ID of query stored in the QueryManager.
Parameter sources ¶
Parameters to populate template queries can either be supplied via a pair of values (Param), a map[string]interface{} (Params) or a struct whose fields are annotated with the `dbparam` tag (tags)
Binding ¶
RDBMSClient provides a mechanism for automatically copying result data into structs or slices of structs. If the RDBMSClient method name contains BindSingle, you will pass a pointer to a struct into the method and its fields will be populated:
ad := new(ArtistDetail)
if found, err := rc.SelectBindSingleQIDTags("ARTIST_DETAIL", rid, ad); found { return ad, err } else { return nil, err }
If the method contains the word Bind, you will supply an example 'template' instance of a struct and the method will return a slice of that type:
ar := new(ArtistSearchResult) if r, err := rc.SelectBindQIDParams("ARTIST_SEARCH_BASE", make(map[string]interface{}), ar); err != nil { return nil, err } else { return id.artistResults(r), nil }
Transactions ¶
To call start a transaction, invoke the StartTransaction method on the RDBMSCLient like:
db.StartTransaction() defer db.Rollback()
and end your method with:
db.CommitTransaction()
The deferred Rollback call will do nothing if the transaction has previously been commited.
Direct access to Go DB methods ¶
RDBMSClient provides pass-through access to sql.DB's Exec, Query and QueryRow methods. Note that these methods are compatible with Granitic's transation pattern as described above.
Multiple databases ¶
This iteration of Granitic is optimised for the most common use-case for RDBMS access, where a particular Granitic application will access a single logical database. It is fully acknowledged that there are many situations where an application needs to access mutiple logical databases.
Facility support for that use-case will be added in later versions of Granitic, but for now you have two options:
Option 1: use this facility to provide support for your application's 'main' database and manually add components of type rdbms.DefaultRDBMSClientManager to your component definition file to support your other database.
Option 2: disable this facility and manually add components of type rdbms.DefaultRDBMSClientManager to your component definition file to support all of your databases.
Index ¶
- Constants
- func DefaultInsertWithReturnedID(query string, client *RDBMSClient, target *int64) error
- func ParamsFromTags(sources ...interface{}) (map[string]interface{}, error)
- type DatabaseProvider
- type GraniticRDBMSClientManager
- func (cm *GraniticRDBMSClientManager) BlockAccess() (bool, error)
- func (cm *GraniticRDBMSClientManager) Client() (*RDBMSClient, error)
- func (cm *GraniticRDBMSClientManager) ClientFromContext(ctx context.Context) (*RDBMSClient, error)
- func (cm *GraniticRDBMSClientManager) PrepareToStop()
- func (cm *GraniticRDBMSClientManager) ReadyToStop() (bool, error)
- func (cm *GraniticRDBMSClientManager) RegisterProvider(p *ioc.Component)
- func (cm *GraniticRDBMSClientManager) StartComponent() error
- func (cm *GraniticRDBMSClientManager) Stop() error
- type InsertWithReturnedID
- type ProviderComponentReceiver
- type RDBMSClient
- func (rc *RDBMSClient) BuildQueryQIDParams(qid string, p map[string]interface{}) (string, error)
- func (rc *RDBMSClient) BuildQueryQIDTags(qid string, tagSource interface{}) (string, error)
- func (rc *RDBMSClient) CommitTransaction() error
- func (rc *RDBMSClient) DeleteQIDParam(qid string, name string, value interface{}) (sql.Result, error)
- func (rc *RDBMSClient) DeleteQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
- func (rc *RDBMSClient) DeleteQIDTags(qid string, tagSource interface{}) (sql.Result, error)
- func (rc *RDBMSClient) Exec(query string, args ...interface{}) (sql.Result, error)
- func (rc *RDBMSClient) ExistingIDOrInsertParams(checkQueryId, insertQueryId string, idTarget *int64, p map[string]interface{}) error
- func (rc *RDBMSClient) ExistingIDOrInsertTags(checkQueryId, insertQueryId string, idTarget *int64, tagSource ...interface{}) error
- func (rc *RDBMSClient) FindFragment(qid string) (string, error)
- func (rc *RDBMSClient) InsertCaptureQIDParams(qid string, params map[string]interface{}, target *int64) error
- func (rc *RDBMSClient) InsertCaptureQIDTags(qid string, tagSource interface{}, target *int64) error
- func (rc *RDBMSClient) InsertQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
- func (rc *RDBMSClient) InsertQIDTags(qid string, tagSource interface{}) (sql.Result, error)
- func (rc *RDBMSClient) Query(query string, args ...interface{}) (*sql.Rows, error)
- func (rc *RDBMSClient) QueryRow(query string, args ...interface{}) *sql.Row
- func (rc *RDBMSClient) RegisterTempQuery(qid string, query string)
- func (rc *RDBMSClient) Rollback()
- func (rc *RDBMSClient) SelectBindQID(qid string, template interface{}) ([]interface{}, error)
- func (rc *RDBMSClient) SelectBindQIDParam(qid string, name string, value interface{}, template interface{}) ([]interface{}, error)
- func (rc *RDBMSClient) SelectBindQIDParams(qid string, params map[string]interface{}, template interface{}) ([]interface{}, error)
- func (rc *RDBMSClient) SelectBindQIDTags(qid string, tagSource interface{}, template interface{}) ([]interface{}, error)
- func (rc *RDBMSClient) SelectBindSingleQID(qid string, target interface{}) (bool, error)
- func (rc *RDBMSClient) SelectBindSingleQIDParam(qid string, name string, value interface{}, target interface{}) (bool, error)
- func (rc *RDBMSClient) SelectBindSingleQIDParams(qid string, params map[string]interface{}, target interface{}) (bool, error)
- func (rc *RDBMSClient) SelectBindSingleQIDTags(qid string, tagSource interface{}, target interface{}) (bool, error)
- func (rc *RDBMSClient) SelectQID(qid string) (*sql.Rows, error)
- func (rc *RDBMSClient) SelectQIDParam(qid string, name string, value interface{}) (*sql.Rows, error)
- func (rc *RDBMSClient) SelectQIDParams(qid string, params map[string]interface{}) (*sql.Rows, error)
- func (rc *RDBMSClient) StartTransaction() error
- func (rc *RDBMSClient) UpdateQIDParam(qid string, name string, value interface{}) (sql.Result, error)
- func (rc *RDBMSClient) UpdateQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
- func (rc *RDBMSClient) UpdateQIDTags(qid string, tagSource interface{}) (sql.Result, error)
- type RDBMSClientManager
- type RowBinder
Constants ¶
const ( Unset = iota NilBool NilString NilInt NilFloat )
const (
// The name of a Go tag on struct fields that can be used to map that field to a parameter name
DBParamTag = "dbparam"
)
Variables ¶
This section is empty.
Functions ¶
func DefaultInsertWithReturnedID ¶
func DefaultInsertWithReturnedID(query string, client *RDBMSClient, target *int64) error
An implementation of InsertWithReturnedID that will work with any Go database driver that implements LastInsertId
func ParamsFromTags ¶
ParamsFromTags takes one or more structs whose fields might have the dbparam tag set. Those fields that do have the tag set are added to the the returned map, where the tag value is used as the map key and the field value is used as the map value.
Types ¶
type DatabaseProvider ¶
type DatabaseProvider interface { // Database returns a Go sql.DB object Database() (*sql.DB, error) // DatabaseFromContext returns a Go sql.DB object. Information in the context may affect the returned object // (e.g. a context might provide an alternative DB user or DB name). DatabaseFromContext(ctx context.Context) (*sql.DB, error) // InsertIDFunc returns an implementation of the InsertWithReturnedID function appropriate for the underlying RDBMS. InsertIDFunc() InsertWithReturnedID }
Implemented by an object able to create a sql.DB object to connect to an instance of an RDBMS. The implementation is expected to manage connection pooling and failover as required
type GraniticRDBMSClientManager ¶
type GraniticRDBMSClientManager struct { // Set to true if you are creating an instance of GraniticRDBMSClientManager manually DisableAutoInjection bool // The names of fields on a component (of type rdbms.RDBMSClientManager) that should have a reference to this component // automatically injected into them. InjectFieldNames []string // Directly set the DatabaseProvider to use when operating multiple RDBMSClientManagers Provider DatabaseProvider // If multiple DatabaseProviders are available, the name of the component to use. ProviderName string // Auto-injected if the QueryManager facility is enabled QueryManager dsquery.QueryManager // Do not allow the Granitic application to start become Accessible (see ioc pacakge) until a connection to the // underlying RDBMS is established. BlockUntilConnected bool // Injected by Granitic. FrameworkLogger logging.Logger // contains filtered or unexported fields }
Granitic's default implementation of RDBMSClientManager. An instance of this will be created when you enable the
RdbmsAccess access facility and will be injected into any component that needs database access - see the package documentation for facilty/rdbms for more details.
func (*GraniticRDBMSClientManager) BlockAccess ¶
func (cm *GraniticRDBMSClientManager) BlockAccess() (bool, error)
BlockAccess returns true if BlockUntilConnected is set to true and a connection to the underlying RDBMS has not yet been established.
func (*GraniticRDBMSClientManager) Client ¶
func (cm *GraniticRDBMSClientManager) Client() (*RDBMSClient, error)
See RDBMSClientManager.Client
func (*GraniticRDBMSClientManager) ClientFromContext ¶
func (cm *GraniticRDBMSClientManager) ClientFromContext(ctx context.Context) (*RDBMSClient, error)
See RDBMSClientManager.ClientFromContext
func (*GraniticRDBMSClientManager) PrepareToStop ¶
func (cm *GraniticRDBMSClientManager) PrepareToStop()
PrepareToStop transitions component to stopping state, prevent new Client objects from being created.
func (*GraniticRDBMSClientManager) ReadyToStop ¶
func (cm *GraniticRDBMSClientManager) ReadyToStop() (bool, error)
ReadyToStop always returns true, nil
func (*GraniticRDBMSClientManager) RegisterProvider ¶
func (cm *GraniticRDBMSClientManager) RegisterProvider(p *ioc.Component)
See ProviderComponentReceiver.RegisterProvider
func (*GraniticRDBMSClientManager) StartComponent ¶
func (cm *GraniticRDBMSClientManager) StartComponent() error
StartComponent selects a DatabaseProvider to use
func (*GraniticRDBMSClientManager) Stop ¶
func (cm *GraniticRDBMSClientManager) Stop() error
Stop always returns nil
type InsertWithReturnedID ¶
type InsertWithReturnedID func(string, *RDBMSClient, *int64) error
A function able execute an insert statement and return an RDBMS generated ID as an int64.
type ProviderComponentReceiver ¶
Implemented by components that are interested in having visibility of all DatabaseProvider implementations available to an application.
type RDBMSClient ¶
type RDBMSClient struct {
// contains filtered or unexported fields
}
The interface application code should use to execute SQL against a database. See the package overview for the rdbms package for usage.
func (*RDBMSClient) BuildQueryQIDParams ¶
func (rc *RDBMSClient) BuildQueryQIDParams(qid string, p map[string]interface{}) (string, error)
BuildQueryQIDParams returns a populated SQL query that can be manually executed later.
func (*RDBMSClient) BuildQueryQIDTags ¶
func (rc *RDBMSClient) BuildQueryQIDTags(qid string, tagSource interface{}) (string, error)
BuildQueryQIDTags returns a populated SQL query that can be manually executed later.
func (*RDBMSClient) CommitTransaction ¶
func (rc *RDBMSClient) CommitTransaction() error
CommitTransaction commits the open transaction - does nothing if no transaction is open.
func (*RDBMSClient) DeleteQIDParam ¶
func (rc *RDBMSClient) DeleteQIDParam(qid string, name string, value interface{}) (sql.Result, error)
DeleteQIDParam executes the supplied query with the expectation that it is a 'DELETE' query.
func (*RDBMSClient) DeleteQIDParams ¶
func (rc *RDBMSClient) DeleteQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
DeleteQIDParams executes the supplied query with the expectation that it is a 'DELETE' query.
func (*RDBMSClient) DeleteQIDTags ¶
func (rc *RDBMSClient) DeleteQIDTags(qid string, tagSource interface{}) (sql.Result, error)
DeleteQIDTags executes the supplied query with the expectation that it is a 'DELETE' query.
func (*RDBMSClient) Exec ¶
func (rc *RDBMSClient) Exec(query string, args ...interface{}) (sql.Result, error)
Exec is a pass-through to its sql.DB equivalent (or sql.Tx equivalent is a transaction is open)
func (*RDBMSClient) ExistingIDOrInsertParams ¶
func (rc *RDBMSClient) ExistingIDOrInsertParams(checkQueryId, insertQueryId string, idTarget *int64, p map[string]interface{}) error
ExistingIDOrInsertParams finds the ID of record or if the record does not exist, inserts a new record and retrieves the newly assigned ID
func (*RDBMSClient) ExistingIDOrInsertTags ¶
func (rc *RDBMSClient) ExistingIDOrInsertTags(checkQueryId, insertQueryId string, idTarget *int64, tagSource ...interface{}) error
ExistingIDOrInsertTags finds the ID of record or if the record does not exist, inserts a new record and retrieves the newly assigned ID
func (*RDBMSClient) FindFragment ¶
func (rc *RDBMSClient) FindFragment(qid string) (string, error)
FindFragment returns a partial query from the underlying QueryManager. Fragments are no different that ordinary template queries, except they are not expected to contain any variable placeholders.
func (*RDBMSClient) InsertCaptureQIDParams ¶
func (rc *RDBMSClient) InsertCaptureQIDParams(qid string, params map[string]interface{}, target *int64) error
InsertCaptureQIDParams executes the supplied query with the expectation that it is an 'INSERT' query and captures the new row's server generated ID in the target int64
func (*RDBMSClient) InsertCaptureQIDTags ¶
func (rc *RDBMSClient) InsertCaptureQIDTags(qid string, tagSource interface{}, target *int64) error
InsertCaptureQIDTags executes the supplied query with the expectation that it is an 'INSERT' query and captures the new row's server generated ID in the target int64
func (*RDBMSClient) InsertQIDParams ¶
func (rc *RDBMSClient) InsertQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
InsertQIDParams executes the supplied query with the expectation that it is an 'INSERT' query.
func (*RDBMSClient) InsertQIDTags ¶
func (rc *RDBMSClient) InsertQIDTags(qid string, tagSource interface{}) (sql.Result, error)
InsertQIDTags executes the supplied query with the expectation that it is an 'INSERT' query.
func (*RDBMSClient) Query ¶
func (rc *RDBMSClient) Query(query string, args ...interface{}) (*sql.Rows, error)
Query is a pass-through to its sql.DB equivalent (or sql.Tx equivalent is a transaction is open)
func (*RDBMSClient) QueryRow ¶
func (rc *RDBMSClient) QueryRow(query string, args ...interface{}) *sql.Row
QueryRow is a pass-through to its sql.DB equivalent (or sql.Tx equivalent is a transaction is open)
func (*RDBMSClient) RegisterTempQuery ¶
func (rc *RDBMSClient) RegisterTempQuery(qid string, query string)
RegisterTempQuery stores the supplied query in the RDBMSClient so that it can be used with methods that expect a QID. Note that the query is NOT stored in the underlying QueryManager.
func (*RDBMSClient) Rollback ¶
func (rc *RDBMSClient) Rollback()
Rollback rolls the open transaction back - does nothing if no transaction is open.
func (*RDBMSClient) SelectBindQID ¶
func (rc *RDBMSClient) SelectBindQID(qid string, template interface{}) ([]interface{}, error)
SelectBindQID executes the supplied query with the expectation that it is a 'SELECT' query. Results of the query are returned in a slice of the same type as the supplied template struct.
func (*RDBMSClient) SelectBindQIDParam ¶
func (rc *RDBMSClient) SelectBindQIDParam(qid string, name string, value interface{}, template interface{}) ([]interface{}, error)
SelectBindQIDParam executes the supplied query with the expectation that it is a 'SELECT' query. Results of the query are returned in a slice of the same type as the supplied template struct.
func (*RDBMSClient) SelectBindQIDParams ¶
func (rc *RDBMSClient) SelectBindQIDParams(qid string, params map[string]interface{}, template interface{}) ([]interface{}, error)
SelectBindQIDParams executes the supplied query with the expectation that it is a 'SELECT' query. Results of the query are returned in a slice of the same type as the supplied template struct.
func (*RDBMSClient) SelectBindQIDTags ¶
func (rc *RDBMSClient) SelectBindQIDTags(qid string, tagSource interface{}, template interface{}) ([]interface{}, error)
SelectBindQIDTags executes the supplied query with the expectation that it is a 'SELECT' query. Results of the query are returned in a slice of the same type as the supplied template struct.
func (*RDBMSClient) SelectBindSingleQID ¶
func (rc *RDBMSClient) SelectBindSingleQID(qid string, target interface{}) (bool, error)
SelectBindSingleQID executes the supplied query with the expectation that it is a 'SELECT' query that returns 0 or 1 rows. Results of the query are bound into the target struct. Returns false if no rows were found.
func (*RDBMSClient) SelectBindSingleQIDParam ¶
func (rc *RDBMSClient) SelectBindSingleQIDParam(qid string, name string, value interface{}, target interface{}) (bool, error)
SelectBindSingleQIDParam executes the supplied query with the expectation that it is a 'SELECT' query that returns 0 or 1 rows. Results of the query are bound into the target struct. Returns false if no rows were found.
func (*RDBMSClient) SelectBindSingleQIDParams ¶
func (rc *RDBMSClient) SelectBindSingleQIDParams(qid string, params map[string]interface{}, target interface{}) (bool, error)
SelectBindSingleQIDParams executes the supplied query with the expectation that it is a 'SELECT' query that returns 0 or 1 rows. Results of the query are bound into the target struct. Returns false if no rows were found.
func (*RDBMSClient) SelectBindSingleQIDTags ¶
func (rc *RDBMSClient) SelectBindSingleQIDTags(qid string, tagSource interface{}, target interface{}) (bool, error)
SelectBindSingleQIDTags executes the supplied query with the expectation that it is a 'SELECT' query that returns 0 or 1 rows. Results of the query are bound into the target struct. Returns false if no rows were found.
func (*RDBMSClient) SelectQID ¶
func (rc *RDBMSClient) SelectQID(qid string) (*sql.Rows, error)
SelectQID executes the supplied query with the expectation that it is a 'SELECT' query.
func (*RDBMSClient) SelectQIDParam ¶
func (rc *RDBMSClient) SelectQIDParam(qid string, name string, value interface{}) (*sql.Rows, error)
SelectQIDParam executes the supplied query with the expectation that it is a 'SELECT' query.
func (*RDBMSClient) SelectQIDParams ¶
func (rc *RDBMSClient) SelectQIDParams(qid string, params map[string]interface{}) (*sql.Rows, error)
SelectQIDParams executes the supplied query with the expectation that it is a 'SELECT' query.
func (*RDBMSClient) StartTransaction ¶
func (rc *RDBMSClient) StartTransaction() error
StartTransaction opens a transaction on the underlying sql.DB object and re-maps all calls to non-transactional methods to their transactional equivalents.
func (*RDBMSClient) UpdateQIDParam ¶
func (rc *RDBMSClient) UpdateQIDParam(qid string, name string, value interface{}) (sql.Result, error)
UpdateQIDParam executes the supplied query with the expectation that it is an 'UPDATE' query.
func (*RDBMSClient) UpdateQIDParams ¶
func (rc *RDBMSClient) UpdateQIDParams(qid string, params map[string]interface{}) (sql.Result, error)
UpdateQIDParams executes the supplied query with the expectation that it is an 'UPDATE' query.
func (*RDBMSClient) UpdateQIDTags ¶
func (rc *RDBMSClient) UpdateQIDTags(qid string, tagSource interface{}) (sql.Result, error)
UpdateQIDTags executes the supplied query with the expectation that it is an 'UPDATE' query.
type RDBMSClientManager ¶
type RDBMSClientManager interface { // Client returns an RDBMSClient that is ready to use. Client() (*RDBMSClient, error) // ClientFromContext returns an RDBMSClient that is ready to use. Providing a context allows the underlying DatabaseProvider // to modify the connection to the RDBMS. ClientFromContext(ctx context.Context) (*RDBMSClient, error) }
Implemented by a component that can create RDBMSClient objects that application code will use to execute SQL statements.
type RowBinder ¶
type RowBinder struct { }
Used to extract the data from the results of a SQL query and inject the data into a target data structure.
func (*RowBinder) BindRow ¶
BindRow takes results from a SQL query that has return zero rows or one row and maps the data into the target interface, which must be a pointer to a struct.
If the query results contain zero rows, BindRow returns false, nil.
If the query results contain one row, it is populated. See the GoDoc for BindRows for more detail.
func (*RowBinder) BindRows ¶
BindRow takes results from a SQL query that has return zero rows or one row and maps the data into the instances of the target interface, which must be a pointer to a struct.
If the query results contain zero rows, BindRow returns an empty slice of the target type ¶
If the query results contain one or more rows, an instance of the target type is created for each row. Each column in a row is mapped to a field in the target type by either:
a) Finding a field whose name exactly matches the column name or alias.
b) Finding a field with the 'column' struct tag with a value that exactly matches the column name or alias.
A target field may be a bool, any native int/uint type, any native float type, a string or any of the Granitic nilable types.