Package io.inversion

Class Collection

  • All Implemented Interfaces:
    java.io.Serializable, java.lang.Comparable<Collection>

    public class Collection
    extends Rule<Collection>
    implements java.io.Serializable
    Represents a REST Collection and maps JSON properties property names and logical cross Collection data relationships to underlying Db tables and column names.

    Api users interact with Collections and their JSON representation while Inversion abstracts the details of of the storage implementations.

    Collections can remap ugly legacy column names to pretty JSON friendly camelCase names, and Collection Relationships can be used to create logical traversable foreign keys between Collections with the same underlying Db or even between Collections with different backend storage systems.

    Generally it is the job of a Db to reflect on its underlying data source and automatically configure Collections and the associated Relationships that will be accessed and manipulated by Api caller.

    The Engine inspects the inbound Request path and attempts to match a Collection to the call.

    The default mapping would be: /${endpointPath}/[${collection}]/[${resource}]/[${relationship}]

    Querying "/${endpointPath}/${collection}" would typically result an a paginated list of resources ie. rows from your underlying Db translated into JSON speak.

    Querying "/${endpointPath}/${collection}/${resource}" will fetch a single resource or row.

    Querying "/${endpointPath}/${collection}/${resource}/${relationship}" will fetch all members from the relationship target Collection that are related to resource.

    RestGet/Post/Put/Patch/DeleteAction are responsible for handling basic Rest semantics for interacting with Dbs via Collections.

    TODO: check on test cases related to hasName and path matching TODO: need tests for resource keys with commas

    See Also:
    Serialized Form
    • Field Detail

      • aliases

        protected final java.util.Set<java.lang.String> aliases
        Additional names that should cause this Collection to match to a Request.

        For example, in an e-commerce environment, you may overload the "orders" collection with aliases "cart", "basket", and "bag".

      • properties

        protected final java.util.ArrayList<Property> properties
        Properties map database column names to JSON property names.
      • indexes

        protected final java.util.ArrayList<Index> indexes
        Representation of underlying Db datasource indexes.
      • relationships

        protected final java.util.ArrayList<Relationship> relationships
        Relationships like resources in one collection to the resources in another collection.
      • db

        protected transient Db db
        The backend storage adapter that probably generated this Collection and associated Indexes and Relationships.
      • tableName

        protected java.lang.String tableName
        The backend datasource name that this Collection operates on.

        The tableName might be "ORDER_DETAIL" but the Collection might be named "orderDetails".

      • pluralDisplayName

        protected java.lang.String pluralDisplayName
      • singularDisplayName

        protected java.lang.String singularDisplayName
      • schemaRef

        protected java.lang.String schemaRef
        A reference to an externa OpenAPI schema that will be used in OpenAPI/documentation generation.
      • exclude

        protected boolean exclude
        Set this to true to prevent it from being automatically exposed through your Api.
    • Constructor Detail

      • Collection

        public Collection()
      • Collection

        public Collection​(java.lang.String defaultName)
    • Method Detail

      • isLinkTbl

        public boolean isLinkTbl()
        Returns true if all columns are foreign keys.

        In an RDBMS system, this would indicate that the table is used to link both sides of a many-to-many relationship and it should NOT be a public REST Collection.

        Returns:
        the true if all columns are foreign keys.
      • getProperty

        public Property getProperty​(java.lang.String jsonOrColumnName)
        Convenience overload of findProperty(String).
        Parameters:
        jsonOrColumnName - the property to get
        Returns:
        the Property with a case insensitive json name or column name match.
        See Also:
        findProperty(String)
      • findProperty

        public Property findProperty​(java.lang.String jsonOrColumnName)
        Finds the property with case insensitive jsonOrColumnName.

        The algo tries to find a matching json property name first before relooping over the props looking of a column name match.

        Parameters:
        jsonOrColumnName - the property to find
        Returns:
        the Property with a case insensitive json name or column name match.
      • getPropertyByJsonName

        public Property getPropertyByJsonName​(java.lang.String jsonName)
        Find the property with case insensitive jsonName
        Parameters:
        jsonName - the name of the property to get
        Returns:
        the property with jsonName
      • getPropertyByColumnName

        public Property getPropertyByColumnName​(java.lang.String columnName)
        Find the property with case insensitive columnName
        Parameters:
        columnName - the name of the property to get
        Returns:
        the property with columnName
      • getColumnName

        public java.lang.String getColumnName​(java.lang.String jsonName)
      • equals

        public boolean equals​(java.lang.Object object)
        Overrides:
        equals in class java.lang.Object
        Returns:
        true if object has the same Db and name as this Collection
      • getDb

        public Db getDb()
        Returns:
        the underlying Db
      • withDb

        public Collection withDb​(Db db)
        Parameters:
        db - the db to set
        Returns:
        this
      • getTableName

        public java.lang.String getTableName()
        Returns:
        the tableName backing this Collection in the Db.
      • withTableName

        public Collection withTableName​(java.lang.String name)
        Parameters:
        name - the name to set
        Returns:
        this
      • getName

        public java.lang.String getName()
        Overrides:
        getName in class Rule<Collection>
        Returns:
        the name of the Collection defaulting to tableName if name is null.
      • withSingularDispalyName

        public Collection withSingularDispalyName​(java.lang.String singularName)
      • getSingularDisplayName

        public java.lang.String getSingularDisplayName()
      • withPluralDisplayName

        public Collection withPluralDisplayName​(java.lang.String pluralName)
      • getPluralDisplayName

        public java.lang.String getPluralDisplayName()
      • getProperties

        public java.util.List<Property> getProperties()
        Returns:
        a shallow copy of properties
      • withProperties

        public Collection withProperties​(Property... props)
        Adds the property definitions to this Collection.

        If there is an existing prop with a json name to json name match or a column name to column name match, the new prop will not be added as it conflicts with the existing one.

        Parameters:
        props - the properties to add
        Returns:
        this
      • withProperty

        public Collection withProperty​(java.lang.String name,
                                       java.lang.String type)
        Fluent utility method for constructing a new Property and adding it to the Collection.
        Parameters:
        name - the name of the Property to add
        type - the type of the Property to add
        Returns:
        this
        See Also:
        Property(String, String, boolean)
      • withProperty

        public Collection withProperty​(java.lang.String name,
                                       java.lang.String type,
                                       boolean nullable)
        Fluent utility method for constructing a new Property and adding it to the Collection.
        Parameters:
        name - the name of the Property to add
        type - the type of the Property to add
        nullable - is the Property nullable
        Returns:
        this
        See Also:
        Property(String, String, boolean)
      • removeProperty

        public void removeProperty​(Property prop)
      • getResourceIndex

        public Index getResourceIndex()
        Finds best index to be used to uniquely identify the resource. Priority is given to Indexes in this order
        1. Index.TYPE_RESOURCE_KEY
        2. Index.TYPE_PRIMARY_KEY
        3. The first unique index found in iteration order with size = 1
        4. The unique index with the fewest columns
        Returns:
        the Index that should be treated as the resource key for the Collection
        See Also:
        Index.isUnique()
      • getIndexByType

        public Index getIndexByType​(java.lang.String indexType)
        Parameters:
        indexType - the case insensative index type identifier
        Returns:
        the first index with type = indexType
      • getIndex

        public Index getIndex​(java.lang.String indexName)
        Gets an index by case insensitive name.
        Parameters:
        indexName - the name of the Index to get
        Returns:
        the requested Index
      • getIndexes

        public java.util.ArrayList<Index> getIndexes()
        Returns:
        a shallow copy of indexes
      • withIndex

        public Collection withIndex​(java.lang.String name,
                                    java.lang.String type,
                                    boolean unique,
                                    java.lang.String... propertyNames)
        Fluent utility method for constructing and adding a new Index.

        If an Index with name exists it will be updated with the new information.

        All of the Properties in propertyNames must already exist.

        Parameters:
        name - the name of the Index to create/add
        type - the type of the Index to create/add
        unique - specifics if Index to create/add is unique
        propertyNames - the Properties that make up the index
        Returns:
        this
        See Also:
        Index(String, String, boolean, Property...)
      • withIndex

        public Collection withIndex​(java.lang.String name,
                                    java.lang.String type,
                                    boolean unique,
                                    int sequence,
                                    java.lang.String propertyName)
      • withForeignKey

        public Collection withForeignKey​(Collection related,
                                         java.lang.String... myProperties)
      • removeIndex

        public void removeIndex​(Index index)
      • isExclude

        public boolean isExclude()
      • withExclude

        public Collection withExclude​(boolean exclude)
      • getRelationship

        public Relationship getRelationship​(java.lang.String name)
        Parameters:
        name - the name of the Relationship to get
        Returns:
        the Relationship with a case insensitve name match
      • getRelationships

        public java.util.List<Relationship> getRelationships()
        Returns:
        a shallow copy of relationships.
      • removeRelationship

        public void removeRelationship​(Relationship relationship)
      • withRelationships

        public Collection withRelationships​(Relationship... relationships)
        Parameters:
        relationships - the relationships to set
        Returns:
        this
      • withRelationship

        public Collection withRelationship​(Relationship relationship)
        Add a new Relationship if a Relationship with the same name does not already exist.
        Parameters:
        relationship - the Relationship to add
        Returns:
        this
      • withManyToOneRelationship

        public Collection withManyToOneRelationship​(java.lang.String thisCollectionsRelationshipJsonPropertyName,
                                                    Collection parentCollection,
                                                    java.lang.String... thisCollectionsForeignKeyProps)
        Fluent utility method to construct a Relationship and associated Indexes.

        In addition to the new Relationship a new foreign key Index will be created from childFkProps to parentCollection's primary Index.

        Parameters:
        thisCollectionsRelationshipJsonPropertyName - what to call this relationship in the json representation of this Collection's resources.
        parentCollection - the related parent Collection
        thisCollectionsForeignKeyProps - the Collections Properties that make up the foreign key
        Returns:
        this
      • withOneToManyRelationship

        public Collection withOneToManyRelationship​(java.lang.String thisCollectionsRelationshipJsonPropertyName,
                                                    Collection childCollection,
                                                    java.lang.String... childCollectionsForeignKeyProps)
        Fluent utility method to construct a Relationship and associated Indexes.

        In addition to the new Relationship a new foreign key Index will be created from childFkProps to this Collection's primary Index.

        Parameters:
        thisCollectionsRelationshipJsonPropertyName - the name of the json property for the parent that references the child
        childCollection - the target child collection
        childCollectionsForeignKeyProps - Properties that make up the foreign key
        Returns:
        this
      • hasName

        public boolean hasName​(java.lang.String nameOrAlias)
        Parameters:
        nameOrAlias - the name or alias to check for
        Returns:
        true if the name or aliases match
      • getAliases

        public java.util.Set<java.lang.String> getAliases()
        Returns:
        a shallow clone of aliases
      • withAliases

        public Collection withAliases​(java.lang.String... aliases)
      • getSchemaRef

        public java.lang.String getSchemaRef()
      • withSchemaRef

        public Collection withSchemaRef​(java.lang.String schemaRef)
      • copy

        public Collection copy()
        Performs a deep clone operation via object serialization/deserialization.

        It is useful when you want to manually wire up numerous copies of a collection but tweak each one a bit differently.

        For example, if you were connecting to a DynamoDb or CosmosDb where a single table is overloaded to support different domain objects.

        This feature requires Collection, Relationship and Index to be Serializable.

        The Db reference here is transient and reconnected to the clone so that this instance and the copy reference the same Db.

        Returns:
        a deep copy of this Collection referencing the same underlying Db instance.
      • encodeKeyFromColumnNames

        public java.lang.String encodeKeyFromColumnNames​(java.util.Map<java.lang.String,​java.lang.Object> values)
        Encodes the resourceKey from the values using column names from the primary index.
        Parameters:
        values - a map containing key value pairs for the Collection's primary index using column names not json names.
        Returns:
        a url safe encoding of the resources primary index values
        See Also:
        encodeKey(Map, Index, boolean)
      • encodeKeyFromJsonNames

        public java.lang.String encodeKeyFromJsonNames​(java.util.Map<java.lang.String,​java.lang.Object> values)
        Encodes the resourceKey from the values using json names from the primary index.
        Parameters:
        values - the key value pairs to encode
        Returns:
        a url safe encoding of the resources primary index values
        See Also:
        encodeKey(Map, Index, boolean)
      • encodeKeyFromJsonNames

        public java.lang.String encodeKeyFromJsonNames​(java.util.Map<java.lang.String,​java.lang.Object> values,
                                                       Index index)
      • encodeKey

        public static java.lang.String encodeKey​(java.util.Map<java.lang.String,​java.lang.Object> values,
                                                 Index index,
                                                 boolean useJsonPropertyNames)
        Encodes the potentially multiple values of an index into a url path and query string safe single value.

        In a typical REST Api configuration where you url paths might map to something like "${endpoint}/${collection}/[${resource}][?{querystring}]", ${resource} is the primary index of the resource that has been encoded here.

        That might look like "/bookstore/books/12345" or in the case of a compound primary index It might look like "/bookstore/orders/4567~abcde" where the "~" character is used to separate parts of the key.

        The names of the index fields are not encoded, only the values, relying on index property order to remain consistent.

        This methods is used by various actions when constructing hypermedia urls that allow you to uniquely identify individual resources (records in a Db) or to traverse Relationships.

        The inverse of this method is decodeKey(Index, String, boolean) which is used to decode inbound Url path and query params to determine which resource is being referenced.

        Parameters:
        values - column name to Property value mapping for a resource
        index - the index identifying the values that should be encoded
        useJsonPropertyNames - use json prop names vs db col names
        Returns:
        a url safe encoding of the index values separated by "~" characters or null if any of the values for an index key is null.
        See Also:
        encodeStr(String), decodeKey(Index, String, boolean)
      • encodeKey

        public static java.lang.String encodeKey​(java.util.List pieces)
        Creates a "~" separated url safe concatenation of pieces
        Parameters:
        pieces - key parts to be encoded
        Returns:
        a url safe encoding of the pieces separated by "~" characters
        See Also:
        encodeStr(String), encodeKey(Map, Index, boolean)
      • decodeKeyToColumnNames

        public java.util.Map<java.lang.String,​java.lang.Object> decodeKeyToColumnNames​(Index index,
                                                                                             java.lang.String inKey)
        Decodes a resource key into its columnName / value parts.
        Parameters:
        index - identifies the columnNames by position
        inKey - the encoded string to decode
        Returns:
        the decoded columnName / value pairs.
        See Also:
        decodeKey(Index, String, boolean), encodeKey(Map, Index, boolean)
      • decodeKeyToJsonNames

        public java.util.Map<java.lang.String,​java.lang.Object> decodeKeyToJsonNames​(java.lang.String inKeys)
        Decodes a resource key into its columnName / value parts.
        Parameters:
        inKeys - the resource key to decode
        Returns:
        the decoded columnName / value pairs.
        See Also:
        decodeKey(Index, String, boolean), encodeKey(Map, Index, boolean)
      • decodeKey

        public java.util.Map<java.lang.String,​java.lang.Object> decodeKey​(Index index,
                                                                                java.lang.String key,
                                                                                boolean useJsonPropertyNames)
        Decodes a resource key.
        Parameters:
        index - identifies the columnNames to decode
        key - a comma separated list of encoded resource keys
        useJsonPropertyNames - indicates to preserve json prop names/types and not convert to db column name/types
        Returns:
        a list of decoded name value pairs
        See Also:
        encodeKey(Map, Index, boolean), encodeStr(String), decodeStr(String)