Skip to content

Latest commit

 

History

History
104 lines (70 loc) · 4.38 KB

README.rst

File metadata and controls

104 lines (70 loc) · 4.38 KB

Massalia

Massalia is a framework for designing GraphQL APIs on top of Morpheus-graphql and Hasql.

It draws most of its inspiration from join-monster, and -to a lesser extent- from hasura.

Main ideas and opinions

  • A GraphQL query/subscription/mutation contains enough information to build an SQL query if needed.
  • The data should be normalized on the input and denormalized on the output.
  • The SQL queries should maximize the filtering joins/where and minimize the data-fetching ones. That is, the data shaping should happen at the select stage as much as possible.

What's the difference with join-monster and hasura then ?

  • Join monster uses a join-heavy approach where data fetching is mixed with data shaping (joins are used for both) which is not needed. Besides join monster lacks a number of important features such as parametrized queries and support for user-defined types at the sql level.
  • Hasura is made/optimized towards JSON rendering in the database. Massalia is geared towards postgresql rows/arrays rendering in the the datatabase. The result is that massalia is more haskell oriented, whereas hasura really shines any situation where you want to write business logic separatly from the query engine. Under heavy loads, using hasura along with a distributed architecture, is probably a better bet.

Is it an ORM or Type-Relational mapping ?

Yes and no. It could be used as an ORM or as a Type-Relational mapping, no doubt. But it lacks a good definition for "this field is not needed", we rely on defining a default value for now. (id est, we define default values for all the records we map to the database). Which is pretty shitty, but it's mostly a non concern when using massalia with GraphQL, because we constructively use the fields sent in the graphQL query, and all the others are ignored at the graphQL level. For a more widespread ORM/TRM, the issue is not at the library level, it lies in Haskell's lack of a proper extensible record system. Thus, for now (and almost certainly until haskell gets proper dependent types and/or extensible records), the library is not meant for out-of-graphQL usage.

Quick exemple

The main function of massalia is to implement this workflow:

  • assuming you defined this:
data Plant = Plant {
  id :: UUID,
  name :: Text
} deriving (Show, Generic, GQLType, SQLRecord ())

instance SQLSelect () Plant where
  toSelectQuery = basicQueryAndDecoder (basicEntityNoFilter "plant")
  • assuming it receives this graphql query:
query { plantList { id name } }
SELECT row(plant.name, plant.id)
FROM plant
  • then hasql decode it into this value
resultValue = [Plant {id="d2630f2b-fa27-4d3e-9d99-2c3c66c98483", name="Some example plant name"}]
  • and eventually (if nothing else is done at the haskell level) into this JSON:
{ plantList:
    [
        { "name": "okokok"
        , "id": "d2630f2b-fa27-4d3e-9d99-2c3c66c98483"
        }
    ]
}

More details

At a lower level massalia is a simple function meant to transform a tree of names to an SQLQuery alongside its Hasql database interpreter. Forgetting the database driver for now, the sql query part is, as an example taken from the unit tests :

-- everything inlined :
truckQuery = "truckList" `node` ["id"]
res = selectStructToQueryFormat (query (toSelectQuery truckQuery (defaultPaginated @TruckFilter)))

Which is basically the way to go from a :code:` truckList { id }` to :code:` truckList { id } ` Note that QueryFormat is polymorphic because we can represent an SQL query through many concrete types (Text, of course, is one of them).

todo, explain why session (hasql etc) queryAndDecoderToQueryFormatAndResult queryAndDecoderToQueryFormatAndResultVect $ toSelectQuery validSel queryArgs