Skip to content

Projections

The core concept of a projection involves dynamically transforming and combining data from various sources, such as materialized views and user inputs, to generate specialized views in real-time. Projections facilitate tasks like aggregating multiple materialized views, applying advanced filters based on user criteria, and performing calculations using both user-provided data and precomputed views. This dynamic approach enables responsive and flexible querying, ensuring that applications can deliver tailored data views efficiently without relying solely on precomputed results.

API Configuration

To configure a projection, several key elements must be defined:

Projection Name

A unique identifier for the projection, which helps in managing and referencing the projection.

GraphQL Namespace

The namespace under which the projection's GraphQL queries will be bundled. This helps in organizing queries logically.

GraphQL Method Name

The method name used to invoke the projection via GraphQL. This name should be unique within the specified namespace.

Authorization Method

Specifies the access control for the projection. The following methods are supported:

  • anonymous: Requires an API key that can be configured in the client. This key may be publicly available, and the API may rate limit these requests to prevent DDOS attacks.
  • authenticated: Requires a user token to access the data.
  • role based: Requires the user to have a specific role to access the data.

Return Object

References a view model that defines the structure of the data returned by the projection.

Return Type

Specifies whether the projection returns a single item or a result set. The possible values are:

  • item: Returns a single instance of the view.
  • result_set: Returns a list of instances.

Arguments

Projections can accept various query variables, which are specified as follows:

Name

The name of the query variable.

Type

The data type of the query variable. Supported types include:

  • String
  • Int
  • Float
  • Boolean
  • StringList

Required

Specifies whether the query variable is mandatory for the projection to execute. The possible values are:

  • true
  • false

Data Preparation Logic

The core logic for preparing data in a projection is written in Python. This logic involves accessing materialized views, applying filters, and transforming data as needed. The following example demonstrates how to implement the data preparation logic:

from draftsman.ViewStoreApi import Query


def transform(arguments, username):
    # You have access to the username of the requestor and the arguments.
    print(f"Handle graph request [{arguments}/{username}]")

    # You have access to a fluent API to access materialized views
    # Here are some examples:

    # Access a specific object (most efficient method cost-wise)
    data = Query('ViewName').get_item("key").run()

    # Get a list of all objects of a specific type
    data = Query('ViewName').get_items().run()

    # Filter a list of objects based on type and key, part of the canonical key Concept
    data = Query('ViewName').get_items("key_starts_with_this_value").run()

    # Filter on content for a specific type (performs a scan on all views of type 'ViewName')
    data = Query('ViewName').get_items().equals('key', 'value').between('key', 0, 100).run()

    # Combine the two filter methods to filter within a subset
    data = Query('ViewName').get_items("key_starts_with_this_value").equals('key', 'value').between('key', 0, 100).run()

    # Switch to an "or" operator for filters (default is "and")
    data = Query('ViewName').get_items(key="key_starts_with_this_value", filter_chain_method="or").equals('key',
                                                                                                          'value').between(
        'key', 0, 100).run()

    # Program data transformations with Python
    # Ensure you add all fields that are defined in the return view object definition
    return {"field_name": "value"}

Fluent API

The Fluent API, which allows you to query and filter data from the DynamoDB view store in a flexible and efficient manner.

The Fluent API provides a convenient way to construct and execute queries against the DynamoDB view-store-table. It supports various filtering methods and allows for the retrieval of individual items or sets of items based on specified criteria.

Initialization

To start using the Fluent API, you need to initialize the Query class with the type of view you want to query.

from draftsman.ViewStoreApi import Query

# Initialize a query for a specific view name
query = Query("YourViewName")

Methods

Retrieving Items

get_item

Retrieve a single item based on its key.

query.get_item("your_item_key")
get_items

Retrieve a set of items, optionally filtered by a key prefix.

query.get_items(key="key_prefix", filter_chain_method="and")
  • key (optional): A prefix to filter items by their keys.
  • filter_chain_method (optional): Determines how multiple filters are combined. Can be "and" or "or". Default is " and".

Adding Filters

Filters can be applied to the query to narrow down the results. The following filter methods are available:

equals

Filter items where the attribute equals a specified value.

query.equals("attribute_name", "value")
less_than

Filter items where the attribute is less than a specified value.

query.less_than("attribute_name", value)
less_than_equals

Filter items where the attribute is less than or equal to a specified value.

query.less_than_equals("attribute_name", value)
greater_than

Filter items where the attribute is greater than a specified value.

query.greater_than("attribute_name", value)
greater_than_equals

Filter items where the attribute is greater than or equal to a specified value.

query.greater_than_equals("attribute_name", value)
begins_with

Filter items where the attribute begins with a specified value.

query.begins_with("attribute_name", "value_prefix")
between

Filter items where the attribute is between two specified values.

query.between("attribute_name", low_value, high_value)
not_equals

Filter items where the attribute does not equal a specified value.

query.not_equals("attribute_name", "value")
exists

Filter items where the attribute exists.

query.exists("attribute_name")
not_exists

Filter items where the attribute does not exist.

query.not_exists("attribute_name")
contains

Filter items where the attribute contains a specified value.

query.contains("attribute_name", "value")
attribute_type

Filter items where the attribute is of a specified type.

query.attribute_type("attribute_name", "type")
is_in

Filter items where the attribute is in a specified list of values.

query.is_in("attribute_name", ["value1", "value2", "value3"])

Running the Query

Once the query is constructed with the necessary filters, it can be executed using the run method.

result = query.run()
  • If get_item was used, run returns a single item.
  • If get_items was used, run returns a list of items matching the query.

Method chaining

The Fluent API supports method chaining, allowing you to construct complex queries in a readable and concise manner by chaining multiple method calls together. Method chaining enhances the clarity of query construction and reduces the need for intermediate variables.

resultset = query.get_items("key_prefix").equals("status", "active").greater_than("priority", 1).equals("user","j.doe").run()