@@ -0,0 +1,183 @@
1+module Supabase.Supabase
37+import Control.Promise (Promise)
38+import Control.Promise as Promise
39+import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
40+import Data.Maybe (Maybe)
41+import Data.Nullable (Nullable)
42+import Data.Nullable as Nullable
43+import Data.Tuple (Tuple(..))
44+import Effect (Effect)
45+import Effect.Aff (Aff, Error)
46+import Effect.Uncurried (EffectFn1, mkEffectFn1)
48+import Fetch.Core.Response as YogaJson.Core
49+import Fetch.Internal.Response as FetchInternalResponse
50+import Foreign (Foreign)
51+import Supabase.Types (Client)
52+import Type.Function (type ($))
53+import Type.Row (type (+))
54+import Supabase.Util as Util
55+import Yoga.JSON (class ReadForeign, class WriteForeign, write) as YogaJson
56+import Yoga.JSON (class ReadForeign, class WriteForeign, writeImpl)
58+foreign import data QueryBuilder :: Type
59+foreign import data FilterBuilder :: Type
61+data Count = Exact | Planned | Estimated
63+countToString ∷ Count → String
64+countToString Exact = "exact"
65+countToString Planned = "planned"
66+countToString Estimated = "estimated"
68+foreign import deleteImpl :: QueryBuilder -> FilterBuilder
70+delete ∷ QueryBuilder -> FilterBuilder
73+foreign import updateImpl :: QueryBuilder -> Foreign -> FilterBuilder
75+update ∷ forall d. YogaJson.WriteForeign d => d -> QueryBuilder -> FilterBuilder
76+update d builder = updateImpl builder $ YogaJson.write d
78+foreign import fromImpl :: Client -> String -> QueryBuilder
80+from ∷ String → Client -> QueryBuilder
81+from s c = fromImpl c s
83+foreign import upsertImpl :: QueryBuilder -> Foreign -> FilterBuilder
85+upsert ∷ ∀ (values ∷ Type). WriteForeign values => values → QueryBuilder → FilterBuilder
86+upsert v q = upsertImpl q $ writeImpl v
88+foreign import selectRunImpl :: forall input. FilterBuilder -> input -> Effect (Promise Foreign)
90+foreign import selectQueryImpl :: QueryBuilder -> String -> FilterBuilder
92+foreign import selectQueryWithCountImpl :: QueryBuilder -> String -> String -> FilterBuilder
94+class Select input builder output where
95+ select :: input -> builder -> output
97+instance (YogaJson.ReadForeign output) => Select Unit FilterBuilder (Aff output) where
98+ select input builder = selectRunImpl builder (input) # Promise.toAffE >>= Util.fromJSON
99+else instance (YogaJson.ReadForeign output) => Select String FilterBuilder (Aff output) where
100+ select input builder = selectRunImpl builder input # Promise.toAffE >>= Util.fromJSON
101+else instance Select (Tuple String Count) QueryBuilder FilterBuilder where
102+ select (Tuple input count) builder = selectQueryWithCountImpl builder input $ countToString count
103+else instance Select String QueryBuilder FilterBuilder where
104+ select = flip selectQueryImpl
106+foreign import eqRunImpl :: FilterBuilder -> Fn2 String String $ Effect (Promise Foreign)
108+foreign import eqImpl :: forall builderIn builderOut. builderIn -> Fn2 String String builderOut
110+class Equals builder output | output -> builder where
111+ equals :: String -> String -> builder -> output
113+instance Equals FilterBuilder FilterBuilder where
114+ equals :: String -> String -> FilterBuilder -> FilterBuilder
115+ equals k v fb = runFn2 (eqImpl fb) k v
116+else instance Equals QueryBuilder FilterBuilder where
117+ equals :: String -> String -> QueryBuilder -> FilterBuilder
118+ equals k v fb = runFn2 (eqImpl fb) k v
119+else instance (YogaJson.ReadForeign output) => Equals FilterBuilder (Aff output) where
120+ equals :: String -> String -> FilterBuilder -> Aff output
121+ equals l r builder = runFn2 (eqRunImpl builder) l r # Promise.toAffE >>= Util.fromJSON
123+foreign import singleImpl :: FilterBuilder -> Effect (Promise Foreign)
125+--type ResultResponse d = { "data" :: Maybe d, status :: Int, error :: Maybe ResultError }
127+single :: forall t. YogaJson.ReadForeign t => FilterBuilder -> Aff (Response t)
128+single = singleImpl >>> Promise.toAffE >=> Util.fromJSON
130+foreign import rangeImpl :: forall i. i -> i -> FilterBuilder -> Effect (Promise Foreign)
132+type CountResponse t = { | DataR t + ErrorR + CountR + StatusR + () }
134+range :: forall response. YogaJson.ReadForeign response => { from :: Int, to :: Int } -> FilterBuilder -> Aff response
135+range { from: f, to } = rangeImpl f to >>> Promise.toAffE >=> Util.fromJSON
137+type InternalAuthResponse = { error :: Nullable Error }
139+foreign import signInWithOtpImpl :: Client -> String -> Effect (Promise InternalAuthResponse)
141+type AuthResponse = { error :: Maybe Error }
143+signInWithOtp :: Client -> String -> Aff AuthResponse
144+signInWithOtp client email = signInWithOtpImpl client email # Promise.toAffE <#> \{ error } -> { error: Nullable.toMaybe error }
146+foreign import signOutImpl :: Client -> Effect (Promise Unit)
148+signOut ∷ Client → Aff Unit
149+signOut client = signOutImpl client # Promise.toAffE
151+foreign import onAuthStateChangeImpl :: Client -> (EffectFn1 (Nullable Session) Unit) -> Effect Unit
153+onAuthStateChange ∷ Client → (Maybe Session → Effect Unit) → Effect Unit
154+onAuthStateChange client handler = onAuthStateChangeImpl client $ mkEffectFn1 (Nullable.toMaybe >>> handler)
156+type User = { id :: String, email :: String }
157+type Session = { user :: User }
158+type SessionData = { session :: Maybe Session }
160+type ResultError = { code :: Maybe String, details :: Maybe String, message :: String }
162+type DataR d r = (data :: Maybe d | r)
163+type ErrorR r = (error ∷ Maybe ResultError | r)
164+type CountR r = (count :: Int | r)
165+type StatusR r = (status ∷ Maybe Int)
166+type Response d = { data :: Maybe d, error ∷ Maybe ResultError, status ∷ Maybe Int }
168+foreign import getSessionImpl :: Client -> Effect (Promise Foreign)
170+getSession :: Client -> Aff (Response SessionData)
171+getSession client = getSessionImpl client # Promise.toAffE >>= Util.fromJSON
173+type InternalFunctionResponse d = { "data" :: Nullable d, error :: Nullable { message :: String, context :: YogaJson.Core.Response}}
174+foreign import invokeImpl :: forall body headers t. Client -> Fn3 String body headers (Effect $ Promise $ InternalFunctionResponse t)
176+type FunctionResponse d = { "data" :: Maybe d, error :: Maybe { message :: String, context :: Fetch.Response}}
179+invoke ∷ forall t body headers. ReadForeign t ⇒ Client → String → body → headers → Aff (FunctionResponse t)
180+invoke client fn body headers = runFn3 (invokeImpl client) fn body headers # Promise.toAffE <#> convert
182+ convertError { message, context } = { message, context: FetchInternalResponse.convert context}
183+ convert { "data": d, error } = { "data": Nullable.toMaybe d, error: Nullable.toMaybe error <#> convertError}