-
Notifications
You must be signed in to change notification settings - Fork 3
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:
- Using nested object structures to group API behaviors rather than using longer method names.
- See the
entity
,attribute
, andattributegroup
sub-APIs on datapath.
- 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.)
- 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.
- Assuming Python-like semantics for sets, lists, tuples. Might need to adapt for Javascript.
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.
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.
- server = Server(url)
- .session.client
- .session.attributes
- .session.expires
- .session.login()... only when currently logged out
- .session.logout()... only when currently logged in
- .session.extend()... only when currently logged in
- .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
- TODO: owner, ACLs?
- schema
- .catalog
- .name
- .delete()
- .tables.create( tableParams ) -> table
- .tables.length() -> count
- .tables.names() -> sequence of tableName
- .tables.get( tableName ) -> table
- .annotations.create( annotationParams ) -> annotation
- .annotations.length() -> count
- .annotations.names() -> sequence of uri
- .annotations.get( uri ) -> annotation
- table
- .schema
- .name
- .delete()
- .columns.create ( columnParams ) -> column
- .columns.length() -> count
- .columns.names() -> sequence of columnName ordered by position
- .columns.get( columnName ) : column
- .columns.getByPosition( index ) -> column
- .keys.create( keyParams ) -> key
- .keys.length() -> count
- .keys.columnsets() -> sequence of colset
- .keys.get( colset ) -> key
- .foreignkeys.create( fkeyParams ) -> foreignkeyref
- .foreignkeys.length() -> count
- .foreignkeys.mappings() -> sequence of mapping
- .foreignkeys.get( mapping ) -> foreignkeyref
- .annotations.create( annotationParams ) -> annotation
- .annotations.length() -> count
- .annotations.names() -> sequence of uri
- .annotations.get( uri ) -> annotation
- column
- .table
- .name
- .type
- .delete()
- .annotations.create( annotationParams ) -> annotation
- .annotations.length() -> count
- .annotations.names() -> sequence of uri
- .annotations.get( uri ) -> annotation
- type
- .name
- .is_array : boolean
- .base_type
- key
- .columns : colset
- .annotations.create( annotationParams ) -> annotation
- .annotations.length() -> count
- .annotations.names() -> sequence of uri
- .annotations.get( uri ) -> annotation
- 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
- .columns : colset of referencing columns
- .key : key being referenced
- .mapping
- .delete()
- .annotations.create( annotationParams ) -> annotation
- .annotations.length() -> count
- .annotations.names() -> sequence of uri
- .annotation.get( uri ) -> annotation
- annotation
- .subject : schema|table|column|key|foreignkeyref
- .uri
- .content
- .delete()
The objects above are relatively static, corresponding to server,
database, and model resources. 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. A filterpath
adds
data constraints as filter expressions. This dataset has sub-APIs to
manipulate whole entities, attributes, or attribute-groups in the
entity context of the path.
- datapath = Datapath(table)
- .catalog
- .context : pathtable
- .extend(table, context=null, link=null) -> pathtable
- .entity.get() -> rowSet
- .entity.post( rowSet ) -> rowSet
- .entity.put( rowSet ) -> rowSet
- .attribute( projection ).get() -> rowSet
- .attributegroup( grouping )( projection ).get() -> rowSet
- .attributegroup( grouping )( projection ).put( rowSet ) -> rowSet
- .aggregate( projection ).get() -> rowSet
- .filter( filter ) -> filterpath
- 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
- pathtable
- .datapath
- .table
- .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 ) -> predicate
- filter = Negation(filter)
- .filter
- filter = Conjunction([ filter, ... ])
- .filters : list of filters
- filter = Disjunction([ filter, ... ])
- .filters : list of filters
- filter = UnaryPredicate(pathcolumn, operator)
- .column : pathcolumn
- .operator : operatorName
- filter = BinaryPredicate(pathcolumn, operator, rvalue)
- .column : pathcolumn
- .operator : operatorName
- .rvalue : literal
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
- .filter( filter ) -> filterpath
- 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