Skip to content

ERMrest Programmatic API Sketch

Jennifer Chen edited this page Jun 9, 2016 · 21 revisions

ERMrest Programmatic API Sketch

This outline focuses on the application-side APIs, e.g. those used by a data or model-consuming client application. It ignores internal APIs needed to help implement the behaviors.

Some idioms assumed in this sketch:

  1. Using nested object structures to group API behaviors rather than using longer method names.
  • See the entity, attribute, and attributegroup sub-APIs on datapath.
  1. Using container-like objects at branching points in the object tree with common signatures.
  • See schemas, tables, columns, etc.
  • Having .by_position and .by_name member access mechanisms, etc.
  • Assuming idioms for checking length, iterating, etc. (Implied rather than sketched out.)
  1. Putting management methods on the object being managed.
  • Having .delete() on the object itself
  • Having .create() on the container-like object where new members are being added.
  1. Assuming Python-like semantics for sets, lists, tuples. Might need to adapt for Javascript.

Catalog and Model Access Object Signatures

A server is bound to a URL, and session credentials are established. Catalogs can be managed or bound to then work in a particular dataset.

A table object from the schema exposes both model access features and basic data access for the single table on the server.

The Dataquery() constructor instantiates a logical data access object. Many such objects can be instantiated from the same catalog to manage different data access tasks concurrently.

  • ermrestFactory
    • .getServer(url) -> returns a new or cached instance of a server
  • server = Server(url)
    • .uri
    • .catalogs.create( catalogParams ) -> catalog
    • .catalogs.length() -> count
    • .catalogs.names() -> sequence of id
    • .catalogs.get( id ) -> catalog
  • catalog
    • .server
    • .id
    • .delete()
    • .schemas.create( schemaParams ) -> schema
    • .schemas.length() -> count
    • .schemas.names() -> sequence of schemaName
    • .schemas.get( schemaName ) -> schema
    • .schemas.all()
    • TODO: owner, ACLs?
  • schema
    • .catalog
    • .name
    • .displayname
    • .ignore
    • .delete()
    • .tables.create( tableParams ) -> table
    • .tables.length() -> count
    • .tables.names() -> sequence of tableName
    • .tables.get( tableName ) -> table
    • .tables.all()
    • .annotations.create( annotationParams ) -> annotation
    • .annotations.length() -> count
    • .annotations.names() -> sequence of uri
    • .annotations.get( uri ) -> annotation
    • .annotations.all()
  • table
    • .schema
    • .name
    • .displayname
    • .ignore
    • .delete()
    • .columns.create ( columnParams ) -> column
    • .columns.length() -> count
    • .columns.names() -> sequence of columnName ordered by position
    • .columns.get( columnName ) : column
    • .columns.getByPosition( index ) -> column
    • .columns.all()
    • .keys.create( keyParams ) -> key
    • .keys.length() -> count
    • .keys.colsets() -> sequence of colset
    • .keys.get( colset ) -> key
    • .keys.all()
    • .foreignkeys.create( fkeyParams ) -> foreignkeyref
    • .foreignkeys.length() -> count
    • .foreignkeys.colsets()
    • .foreignkeys.mappings() -> sequence of mapping
    • .foreignkeys.get( mapping ) -> foreignkeyref
    • .foreignkeys.get( colset ) -> foreignkeyref
    • .foreignkeys.all()
    • .annotations.create( annotationParams ) -> annotation
    • .annotations.length() -> count
    • .annotations.names() -> sequence of uri
    • .annotations.get( uri ) -> annotation
    • .annotations.all()
    • .entity.get( filter=null, limit=null, columns=null, sortby=null ) -> rowSet
    • .entity.getBefore( filter=null, limit, columns=null, sortby=null, row ) -> rowSet
    • .entity.getAfter( filter=null, limit, columns=null, sortby=null, row ) -> rowSet
    • .entity.count( filter=null ) -> count
    • .entity.delete( filter=null ) : void
    • .entity.put( rowSet ) -> rowSet
    • .entity.post( rowSet ) -> rowSet
    • .attribute.get( projection, filter=null ) -> rowSet
    • .attribute.delete( projection, filter=null ) : void
    • .attributegroup.get( grouping, projection, filter=null ) -> rowSet
    • .attributegroup.put( grouping, projection, rowSet ) -> rowSet
  • rowSet
    • .length()
    • .before() -> rowSet
    • .after() -> rowSet
  • column
    • .table
    • .name
    • .displayname
    • .type
    • .nullok
    • .default
    • .comment
    • .ignore
    • .memberOfKeys -> []
    • .memberOfForeignKeys -> []
    • .delete()
    • .annotations.create( annotationParams ) -> annotation
    • .annotations.length() -> count
    • .annotations.names() -> sequence of uri
    • .annotations.get( uri ) -> annotation
    • .annotations.all()
  • type
    • .name
    • .is_array : boolean
    • .base_type
  • key
    • .table
    • .colset
    • .annotations.create( annotationParams ) -> annotation
    • .annotations.length() -> count
    • .annotations.names() -> sequence of uri
    • .annotations.get( uri ) -> annotation
    • .annotations.all()
  • colset: is a mathematical set of columns, i.e. all colsets containing the same N columns are equivalent
    • .length() -> count
    • .columns -> sequence of columns
  • mapping: is a mathematical functional map, i.e. a mathematical set of (from -> to) column pairings
    • .length() -> count
    • .domain() -> sequence of fromColumn
    • .get( fromColumn ) -> toColumn
  • foreignkeyref
    • .colset : colset of referencing columns
    • .key : key being referenced
    • .mapping
    • .ignore
    • .delete()
    • .simple()
    • .getDomainValues( limit=null ) -> rowset from the referenced key's table
    • .annotations.create( annotationParams ) -> annotation
    • .annotations.length() -> count
    • .annotations.names() -> sequence of uri
    • .annotation.get( uri ) -> annotation
    • .annotation.all()
  • annotation
    • .subject : schema|table|column|key|foreignkeyref
    • .uri
    • .content
    • .delete()

Data Access Object Signatures

The objects above are relatively static, corresponding to server, database, and model resources. The table objects include basic data access methods already outlined above and operate on one server-side table at a time.

The objects below are dynamic views/wrappers over the database. A pathtable is a table instance in a particular query while table is an element of the database schema. A pathcolumn is a column from one table instance, while a column is an element of the database schema.

A datapath represents a particular dataset in an ERMrest catalog. It combines one or more pathtable instances linked into a relational join and denoting a particular entity context. The datapath.copy() method creates a shallow copy of a datapath such that further extension of either copy will happen independently while they share the pathtable instances and relationships they both held at the time of copy. The datapath.filter() method also produces a shallow copy but introduces a new filter constraint on the returned copy.

  • datapath = Datapath(table)
    • .catalog
    • .context : pathtable
    • .copy() -> datapath shallow copy
    • .filter( filter ) -> datapath shallow copy with filter
    • .extend(table, context=null, link=null) -> pathtable
    • .entity.get( filter=null ) -> rowSet
    • .entity.delete( filter=null ) : void
    • .attribute.get( projection, filter=null ) -> rowSet
    • .attribute.delete( projection, filter=null ) : void
    • .attributegroup.get( grouping, projection, filter=null ) -> rowSet
    • .aggregate.get( projection, filter=null ) -> rowSet
  • pathtable
    • .datapath
    • .table
    • .alias
    • .columns.length() -> count
    • .columns.names() -> sequence of names ordered by position
    • .columns.get( columnName ) -> pathcolumn
    • .columns.getByPosition( index ) -> pathcolumn
  • pathcolumn
    • .pathtable
    • .column
    • .operators.length() -> count
    • .operators.names() -> sequence of operatorName
    • .operators.get( operatorName )( rvalue=null ) -> filter
  • filter = Negation(filter)
    • .filter
    • .toUri()
  • filter = Conjunction([ filter, ... ])
    • .filters : list of filters
    • .toUri()
  • filter = Disjunction([ filter, ... ])
    • .filters : list of filters
    • .toUri()
  • filter = UnaryPredicate(pathcolumn | column, operator)
    • .column : pathcolumn | column
    • .operator : operatorName
    • .toUri()
  • filter = BinaryPredicate(pathcolumn | column, operator, rvalue)
    • .column : pathcolumn | column
    • .operator : operatorName
    • .rvalue : literal
    • .toUri()

Facet-based Abstract Data Access Object Signatures

This is a variant or wrapper for datapath that discovers facets automatically and handles the linkage of facet source tables to the main context table rather than the client building up the path structure.

  • facetpath = Facetpath(table)
    • .catalog
    • .context : pathtable
    • .facets.length() -> count
    • .facets.names() -> sequence of facetName
    • .facets.get( facetName ) : pathcolumn
    • .facets.getByPosition( index ) : pathcolumn
    • .entity.get() -> rowSet
    • .attribute( projection ).get() -> rowSet
    • .attributegroup( grouping )( projection ).get() -> rowSet
    • .aggregate( projection ).get() -> rowSet
  • filterpath
    • .datapath
    • .filter
    • .entity.get() -> rowSet
    • .entity.delete() : void
    • .attribute( projection ).get() -> rowSet
    • .attribute( projection ).delete() : void
    • .attributegroup( group )( projection ).get() -> rowSet
    • .aggregate( projection ).get() -> rowSet