Read Model - query for Map Field

How do I write a read-model/postgraphile query for a Map field in a protocol?

e.g.

protocol[admin, customer] Project() {
...
    var projectLog: Map<ProjectLog, Set<ProjectLogEntry>> = mapOf<ProjectLog, Set<ProjectLogEntry>>();
...
}

where ProjectLog is an enum and ProjectLogEntry is a Struct.

What kind of query are you trying to write? Query by the key (enum) and get back the struct?

I’ll attach my latest query and response. I’m trying to see the contents of projectLog.

It seems I can attach a picture but not a file :frowning:

Graphql request:

{
  protocolStates(
    filter: {
      protoRefId: { equalTo: "/inv-2.0.1?/investerra/Project" }
      protocolId: { in: ["914915ef-dac5-4c37-9c10-c727781ce36b"] }
    }
  ) {
    totalCount
    nodes {
      protocolId
      currentState
      protocolFieldsProtocolsByProtocolId {
        nodes {
          field
          value
        }
      }
      protocolFieldsStructsByProtocolId {
        nodes {
          field
          value
        }
      }
      protocolFieldsCollectionsProtocolsByProtocolId {
        nodes {
          field
          value
          collectionType
        }
      }
      protocolFieldsCollectionsProtocolsByValue {
        nodes {
          field
          value
          collectionType
        }
      }
      protocolFieldsCollectionsTextsByProtocolId {
        nodes {
          field
          value
          collectionType
        }
      }
      protocolFieldsCollectionsEnumsByProtocolId {
        nodes {
          field
          value
          collectionType
        }
      }
      # frame
    }
  }
}

GraphQL response:

{
  "data": {
    "protocolStates": {
      "totalCount": 1,
      "nodes": [
        {
          "protocolId": "914915ef...",
          "currentState": "questionaireSubmitted",
          "protocolFieldsProtocolsByProtocolId": {
            "nodes": [
              {
                "field": "creditCheck",
                "value": "eec0b865..."
              },
              {
                "field": "user",
                "value": "e1a95ad3..."
              }
            ]
          },
          "protocolFieldsStructsByProtocolId": {
            "nodes": [
              {
                "field": "fourEyeCheck",
                "value": "c9441f38..."
              },
              {
                "field": "offerUrl",
                "value": "39b7f68d..."
              }
            ]
          },
          "protocolFieldsCollectionsProtocolsByProtocolId": {
            "nodes": []
          },
          "protocolFieldsCollectionsTextsByProtocolId": {
            "nodes": []
          },
          "protocolFieldsCollectionsEnumsByProtocolId": {
            "nodes": [
              {
                "field": "productTypes",
                "value": "INVESTERRA_ELECTRICITY_SALES",
                "collectionType": "List</inv-2.0.1?/support/ProductType>"
              },
              {
                "field": "productTypes",
                "value": "STORAGE_SOLUTION",
                "collectionType": "List</inv-2.0.1?/support/ProductType>"
              }
            ]
          }
        }
      ]
    }
  }
}

Hi @Stuart_Shannon
For now the read model supports only selected types, and complex types such as nested structs or nested collection are not supported.

We post about this on the Read Model > Known Shortcoming page:

Similarly, it is not possible to query nested collections. We only support querying collection elements on the top level of protocols (hence collections that are nested within structs or other collections are not queryable)

Here are two alternative solutions I can suggest:

  1. the modification the NPL modelling in your application, such that the Set< ProjectLogEntry> is stored in a protocol AND ProjectLogEntry is transformed from a struct to a protocol, or
  2. using the NPL API to retrieve that complex data structure protocol by protocol

I understand the additional complexity in both cases and hope it is suitable for your use-case.

I will ensure this use-case is taken into roadmap discussions and will come back to you down the road when we have a better solution.

Thanks @jean , I thought it would be something like this. A Map is typically not considered a collection type - but I guess it applies to Maps too.

Then my question changes slightly to - How can I query for the contents of a simple Map via the read-model?

e.g. say the Map was:

protocol[admin, customer] Project() {
...
    var projectLog: Map<Text, Text> = mapOf<Text, Text>();
...
}

Is the query this?

{
  protocolStates(
    filter: {
      protoRefId: { equalTo: "/inv-2.0.1?/investerra/Project" }
      protocolId: { in: ["1284hrnf9-dac5-4c37-9c10-c727738ehdk45"] }
    }
  ) {
    totalCount
    nodes {
      protocolId
      currentState
      protocolFieldsCollectionsTextsByProtocolId {
        nodes {
          field
          value
          collectionType
        }
      }
    }
  }
}

There is no protocolFieldsMaps... term as far as I can see.

Hi @Stuart_Shannon

I modified the IOU protocol to have two maps:

protocol[issuer, payee] Iou(var description: Text, var forAmount: Number) {

    var myTextMap: Map<Text, Text> = mapOf<Text, Text>(Pair("foo", "bar"));
    var myNumberMap: Map<Text, Number> = mapOf<Text, Number>(Pair("toto", 42));

The query to retrieve the maps is:

{
  protocolStates{
    totalCount
    nodes {
      protocolId
      protocolFieldsCollectionsTextsByProtocolId {
        nodes {
          key
          value
          field
        }
      }
      protocolFieldsCollectionsNumbersByProtocolId {
        nodes {
          key
          value
          field
        }
      }
      protoRefId
    }
  }
}

with the answer looking like

{
  "data": {
    "protocolStates": {
      "totalCount": 1,
      "nodes": [
        {
          "protocolId": "cb244cd3-f61a-4dfb-a09d-e6bde5b8d3b4",
          "protocolFieldsCollectionsTextsByProtocolId": {
            "nodes": [
              {
                "key": "foo",
                "value": "bar",
                "field": "myTextMap"
              }
            ]
          },
          "protocolFieldsCollectionsNumbersByProtocolId": {
            "nodes": [
              {
                "key": "toto",
                "value": "42",
                "field": "myNumberMap"
              }
            ]
          },
          "protoRefId": "/nplintegrations-1.0?/iou/Iou"
        }
      ]
    }
  }
}

Hope this helps!

1 Like

Thanks @jean

To summarise, to query a Map you need to use:

protocolFieldsCollections<ValueType>ByProtocolId

where ValueType is the type of the value in your Map.

Unfortunately, I think you will also get back Sets and Lists of this type, so parsing is gonna be a bit tricky.

The collectionType identifier will indicate the original NPL type

{
  protocolStates{
    totalCount
    nodes {
      protocolId
      protocolFieldsCollectionsTextsByProtocolId {
        nodes {
          key
          value
          field
          collectionType
        }
      }
      protocolFieldsCollectionsNumbersByProtocolId {
        nodes {
          key
          value
          field
          collectionType
        }
      }
      protoRefId
    }
  }
}