packages feed

airgql 0.7.1.2 → 0.7.1.3

raw patch · 9 files changed

+176/−105 lines, 9 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- AirGQL.Utils: mainServerDb :: FilePath
- AirGQL.GraphQL: getMutationResponse :: Text -> [ColumnEntry] -> Type IO
+ AirGQL.GraphQL: getMutationResponse :: AccessMode -> Text -> [ColumnEntry] -> Type IO

Files

airgql.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           airgql-version:        0.7.1.2+version:        0.7.1.3 synopsis:       Automatically generate a GraphQL API for an SQLite database description:    AirGQL automatically generates a GraphQL API for SQLite databases.                 It analyses the database schema
readme.md view
@@ -51,6 +51,15 @@   - … ``` +Also set the `lib-only` flag in your `stack.yaml` file+to avoid irrelevant errors:++```yaml+flags:+  airgql:+    lib-only: true+```+  ## Usage 
source/AirGQL/Config.hs view
@@ -9,7 +9,7 @@ import Data.Int (Int)  --- | The maximum number of results allowed for the graphql playground+-- | The maximum number of results allowed for the GraphiQL playground maxGraphqlResultCount :: Int maxGraphqlResultCount = 10000 @@ -27,7 +27,6 @@   }  --- | Configuration for Airsequel's Pro Plan defaultConfig :: Config defaultConfig =   Config
source/AirGQL/ExternalAppContext.hs view
@@ -60,8 +60,8 @@ getExternalAppContext :: Text -> IO ExternalAppContext getExternalAppContext baseUrl = do   sqlite <- lookupBinaryPath "sqlite3"-  sqliteEnv <- lookupEnv "AIRSEQUEL_SQLITE_BIN"-  sqliteLib <- lookupEnv "AIRSEQUEL_SQLITE_LIB"+  sqliteEnv <- lookupEnv "AIRGQL_SQLITE_BIN"+  sqliteLib <- lookupEnv "AIRGQL_SQLITE_LIB"    pure $     ExternalAppContext
source/AirGQL/GraphQL.hs view
@@ -840,10 +840,11 @@   getMutationResponse-  :: Text+  :: AccessMode+  -> Text   -> [ColumnEntry]   -> Out.Type IO-getMutationResponse tableName columnEntries =+getMutationResponse accessMode tableName columnEntries =   Out.NamedObjectType $     outObjectTypeToObjectType $       OutObjectType@@ -853,7 +854,7 @@               tableName <> " mutation response description"         , interfaceTypes = []         , fields =-            HashMap.fromList+            HashMap.fromList $               [                 ( "affected_rows"                 , let@@ -878,43 +879,47 @@                   in                     ValueResolver field value                 )-              ,-                ( "returning"-                , let-                    field :: Out.Field IO-                    field =-                      outFieldToField $-                        OutField-                          { descriptionMb =-                              Just-                                "Non null returning description"-                          , fieldType =-                              Out.NonNullListType $-                                Out.NamedObjectType $-                                  Out.ObjectType-                                    "returning"-                                    (Just "short desc")-                                    []-                                    ( HashMap.fromList $-                                        colNamesWithValResolver columnEntries-                                    )-                          , arguments = HashMap.empty-                          }--                    value :: ReaderT Out.Context IO Value-                    value = do-                      context <- ask-                      case context & Out.values of-                        Object obj ->-                          pure $-                            fromMaybe (Object P.mempty) $-                              HashMap.lookup "returning" obj-                        _ -> pure $ Object P.mempty-                  in-                    ValueResolver field value-                )               , mutationTypeNameField tableName               ]+                <> case accessMode of+                  WriteOnly -> []+                  _ ->+                    [+                      ( "returning"+                      , let+                          field :: Out.Field IO+                          field =+                            outFieldToField $+                              OutField+                                { descriptionMb =+                                    Just+                                      "Non null seturning description"+                                , fieldType =+                                    Out.NonNullListType $+                                      Out.NamedObjectType $+                                        Out.ObjectType+                                          "returning"+                                          (Just "short desc")+                                          []+                                          ( HashMap.fromList $+                                              colNamesWithValResolver columnEntries+                                          )+                                , arguments = HashMap.empty+                                }++                          value :: ReaderT Out.Context IO Value+                          value = do+                            context <- ask+                            case context & Out.values of+                              Object obj ->+                                pure $+                                  fromMaybe (Object P.mempty) $+                                    HashMap.lookup "returning" obj+                              _ -> pure $ Object P.mempty+                        in+                          ValueResolver field value+                      )+                    ]         }  @@ -1085,10 +1090,11 @@ mutationType   :: Connection   -> Integer+  -> AccessMode   -> Text   -> [TableEntryRaw]   -> IO (Maybe (Out.ObjectType IO))-mutationType connection maxRowsPerTable dbId tables = do+mutationType connection maxRowsPerTable accessMode dbId tables = do   let     documentation =       "Available queries for database \"" <> dbId <> "\""@@ -1206,7 +1212,7 @@         outFieldToField $           OutField             { descriptionMb = Just "description"-            , fieldType = getMutationResponse tableName columnEntries+            , fieldType = getMutationResponse accessMode tableName columnEntries             , arguments =                 HashMap.fromList                   [ ("objects", objectsType)@@ -1520,7 +1526,7 @@         outFieldToField $           OutField             { descriptionMb = Just $ "Provides entries from " <> tableName-            , fieldType = getMutationResponse tableName columnEntries+            , fieldType = getMutationResponse accessMode tableName columnEntries             , arguments =                 HashMap.fromList                   [@@ -1559,7 +1565,7 @@         outFieldToField $           OutField             { descriptionMb = Just $ "Provides entries from " <> tableName-            , fieldType = getMutationResponse tableName columnEntries+            , fieldType = getMutationResponse accessMode tableName columnEntries             , arguments =                 HashMap.fromList                   [@@ -1659,6 +1665,7 @@     mutationType       connection       schemaConf.maxRowsPerTable+      schemaConf.accessMode       dbId       tables 
source/AirGQL/Introspection.hs view
@@ -27,6 +27,7 @@   not,   ($),   (&),+  (&&),   (<&>),   (>>=),  )@@ -73,6 +74,7 @@   column_name_gql,   datatype_gql,   getColumns,+  isOmittable,   notnull,   select_options,  )@@ -1217,7 +1219,7 @@           colName           "" -- TODO: Reactivate description when user can specify it           [] -- No arguments-          ( if columnEntry.notnull+          ( if columnEntry.notnull && not columnEntry.isOmittable               then ["NON_NULL", "SCALAR"]               else ["SCALAR"]           )@@ -1326,6 +1328,10 @@         ReadOnly -> Null         WriteOnly -> obj         ReadAndWrite -> obj+      requiresRead obj = case accessMode of+        ReadOnly -> Null+        WriteOnly -> obj+        ReadAndWrite -> obj      pure $       customRowTypes@@ -1379,42 +1385,43 @@                                       ]                                 )                               ]-                        , Object $-                            HashMap.fromList-                              [ ("name", "returning")-                              ,-                                ( "type"-                                , Object $-                                    HashMap.fromList-                                      [ ("kind", "NON_NULL")-                                      ,-                                        ( "ofType"-                                        , Object $-                                            HashMap.fromList-                                              [ ("kind", "LIST")-                                              ,-                                                ( "ofType"-                                                , Object $-                                                    HashMap.fromList-                                                      [ ("kind", "NON_NULL")-                                                      ,-                                                        ( "ofType"-                                                        , Object $-                                                            HashMap.fromList-                                                              [ ("kind", "OBJECT")-                                                              ,-                                                                ( "name"-                                                                , String $ doubleXEncodeGql table.name <> "_row"-                                                                )-                                                              ]-                                                        )-                                                      ]-                                                )-                                              ]-                                        )-                                      ]-                                )-                              ]+                        , requiresRead $+                            Object $+                              HashMap.fromList+                                [ ("name", "returning")+                                ,+                                  ( "type"+                                  , Object $+                                      HashMap.fromList+                                        [ ("kind", "NON_NULL")+                                        ,+                                          ( "ofType"+                                          , Object $+                                              HashMap.fromList+                                                [ ("kind", "LIST")+                                                ,+                                                  ( "ofType"+                                                  , Object $+                                                      HashMap.fromList+                                                        [ ("kind", "NON_NULL")+                                                        ,+                                                          ( "ofType"+                                                          , Object $+                                                              HashMap.fromList+                                                                [ ("kind", "OBJECT")+                                                                ,+                                                                  ( "name"+                                                                  , String $ doubleXEncodeGql table.name <> "_row"+                                                                  )+                                                                ]+                                                          )+                                                        ]+                                                  )+                                                ]+                                          )+                                        ]+                                  )+                                ]                         ]                     )                   ]@@ -1578,7 +1585,7 @@                   )                 ,                   ( "subscriptionType"-                  , -- Airsequel does not yet support Subscriptions+                  , -- AirGQL doesn't support Subscriptions yet                     ValueResolver subscriptionTypeType $ pure Null                   )                 ,
source/AirGQL/Lib.hs view
@@ -135,7 +135,7 @@               { errSQLType = "Object Type"               , errHaskellType = "String"               , errMessage =-                  "\"" <> show sqlData <> "\" is not a vaild object type"+                  "\"" <> show sqlData <> "\" is not a valid object type"               }         ] @@ -337,6 +337,13 @@         { name = getFirstName names         , columns = [col_name]         }+  -- Primary keys are unique by default, even though they do not have an unique index+  SQL.ColConstraintDef names (SQL.ColPrimaryKeyConstraint _) ->+    Just $+      UniqueConstraint+        { name = getFirstName names+        , columns = [col_name]+        }   _ -> Nothing  @@ -348,6 +355,13 @@         , columns = P.fmap nameAsText columns         }     ]+  -- Primary keys are unique by default, even though they do not have an unique index+  SQL.TableConstraintDef names (SQL.TablePrimaryKeyConstraint columns) ->+    [ UniqueConstraint+        { name = getFirstName names+        , columns = P.fmap nameAsText columns+        }+    ]   SQL.TableColumnDef (SQL.ColumnDef col_name _ _ constraints) ->     P.mapMaybe (getColumnUniqueConstraint (nameAsText col_name)) constraints   _ -> []@@ -779,12 +793,8 @@         , datatype = "INTEGER"         , datatype_gql = Just $ stringToGqlTypeName "Int"         , select_options = P.Nothing-        , -- While the rowid is actually NOT NULL,-          -- it must be set to false here-          -- to show in the GraphQL docs that it can be omitted-          -- since it will be set automatically.-          notnull = False-        , isUnique = False+        , notnull = True+        , isUnique = True         , isOmittable = True         , isGenerated = False         , dflt_value = P.Nothing@@ -989,7 +999,7 @@     -- TODO: Remove after     --       https://github.com/JakeWheat/simple-sql-parser/issues/27     & replaceWithSpace "if not exists" ""-    -- TOOD: Remove after+    -- TODO: Remove after     --       https://github.com/JakeWheat/simple-sql-parser/issues/37     & replaceCaseInsensitive "insert or abort " "insert "     & replaceCaseInsensitive "insert or fail " "insert "@@ -1188,7 +1198,7 @@         , "nothing"         , "notnull"         , -- although "null" is on the official list of keywords, adding it here-          --  seems to break "select NULL as ..." statemenets+          --  seems to break "select NULL as ..." statements           -- , "null"           "nulls"         , "of"
source/AirGQL/Utils.hs view
@@ -22,7 +22,6 @@   getSqliteBinaryVersion,   getSqliteEmbeddedVersion,   headerJsonContent,-  mainServerDb,   quoteKeyword,   quoteText,   removeIfExists,@@ -93,10 +92,6 @@  )  import AirGQL.ExternalAppContext (ExternalAppContext (sqlite))---mainServerDb :: FilePath-mainServerDb = "data" </> "airsequel.sqlite"   getDbDir :: Text -> FilePath
tests/Spec.hs view
@@ -115,7 +115,6 @@ import AirGQL.Types.Utils (encodeToText) import AirGQL.Utils (   getOrderOfLinkedList,-  mainServerDb,   removeIfExists,   withRetryConn,  )@@ -272,8 +271,8 @@                 , datatype = "INTEGER"                 , datatype_gql = Just $ stringToGqlTypeName "Int"                 , select_options = Nothing-                , notnull = False-                , isUnique = False+                , notnull = True+                , isUnique = True                 , isOmittable = True                 , isGenerated = False                 , dflt_value = Nothing@@ -478,7 +477,7 @@                 , datatype_gql = Just $ stringToGqlTypeName "Int"                 , select_options = Nothing                 , notnull = False-                , isUnique = False+                , isUnique = True                 , isOmittable = True                 , isGenerated = False                 , dflt_value = Nothing@@ -3373,7 +3372,54 @@        Ae.encode result `shouldBe` rmSpaces expected +    it "doesn't allow writeonly tokens to return data" $ do+      let dbName = "no-writeonly-return.db"+      withTestDbConn shouldSaveDbs dbName $ \conn -> do+        execute_+          conn+          [sql|+            CREATE TABLE items (+              id INTEGER PRIMARY KEY+            )+          |] +      let+        query :: Text+        query =+          [gql|+              mutation items {+                update_items(filter: { id: { eq: 0 }}, set: { id: 0 }) {+                  returning { id }+                }+              }+            |]++        expected =+          rmSpaces+            [raw|+              {+                "data": null,+                "errors": [{+                  "locations": [{ "column":3, "line":2 }],+                  "message": "Cannot query field \"update_items\" on type \"Mutation\"."+                }]+              }+            |]++      schema <- withRetryConn (unpack dbPath) $ \conn -> do+        tables <- getTables conn+        getDerivedSchema+          defaultSchemaConf{accessMode = WriteOnly}+          conn+          dbPath+          tables++      Right response <-+        graphql schema Nothing mempty query++      Ae.encode response `shouldBe` expected++ deleteDbEntries :: Text -> IO () deleteDbEntries databasePath = do   conn <- open $ unpack databasePath@@ -3386,8 +3432,6 @@   cwd <- getWorkingDirectory   createDirectoryIfMissing True (".." </> "data" </> "TEST" </> "data")   changeWorkingDirectory (cwd </> ".." </> "data" </> "TEST")--  removeIfExists mainServerDb    removeIfExists $ unpack dbPath