| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Hmssql.Encoding
Description
Turning Haskell values into parameters.
ToSqlField encodes one value as one parameter, with a fixed wire type
per Haskell type (Hmssql.Types has the table); ToSqlRow encodes a
value as a list of parameters: a tuple, a record with a derived
instance, a list, Only, or NamedParams. A new ToSqlField
instance is usually contramap over an existing encoder; one that
must choose the wire type itself builds a FieldEncoder, or the
caller sends a RawParam. A large value can be read as it is sent, rather
than held in memory; see Hmssql.Encoding.
Synopsis
- data FieldEncoder a = FieldEncoder {
- encodeParam :: TdsContext -> a -> Either String EncodedParam
- nullParamType :: TdsContext -> TypeInfo
- class ToSqlField a where
- fieldEncoder :: FieldEncoder a
- newtype RawParam = RawParam (TypeInfo, RawBytes)
- data SqlParam = ToSqlField a => SqlParam a
- type EncodedParam = (TypeInfo, ParamValue)
- data ParamValue
- newtype Source a = Source (forall r. (Stream (Of a) IO () -> IO r) -> IO r)
- sourceOf :: Stream (Of a) IO () -> Source a
- sourceIO :: IO (Stream (Of a) IO ()) -> Source a
- data StreamParam = StreamParam !TypeInfo !ParamValue
- binaryStream :: Source ByteString -> StreamParam
- textStream :: Source Text -> StreamParam
- streamAs :: TypeInfo -> Source ByteString -> StreamParam
- lazyAs :: TypeInfo -> ByteString -> StreamParam
- newtype RowEncoder a = RowEncoder {
- encodeParams :: a -> [(Text, TdsContext -> Either String EncodedParam)]
- class ToSqlRow a where
- rowEncoder :: RowEncoder a
- divideRow :: (a -> (b, c)) -> RowEncoder b -> RowEncoder c -> RowEncoder a
- singleParam :: FieldEncoder a -> RowEncoder a
- genericToSqlRow :: (Generic a, GRowEncoder (Rep a)) => RowEncoder a
- type NamedParam = (Text, SqlParam)
- newtype NamedParams = NamedParams [NamedParam]
Field encoders
data FieldEncoder a Source #
How a value of a type becomes one parameter: its wire type and bytes,
or why it can't be sent (what the query functions throw as
EncodeError). The TdsContext is the connection's,
for an encoding that depends on the negotiated protocol.
Constructors
| FieldEncoder | |
Fields
| |
Instances
| Contravariant FieldEncoder Source # | An encoder of import Data.Functor.Contravariant (contramap) instance ToSqlField Status where fieldEncoder = contramap statusText fieldEncoder |
Defined in Hmssql.Encoding Methods contramap :: (a' -> a) -> FieldEncoder a -> FieldEncoder a' # (>$) :: b -> FieldEncoder b -> FieldEncoder a # | |
class ToSqlField a where Source #
Types that can be sent as one parameter, through param
or as a field of a ToSqlRow value. The usual Haskell types have
instances, and Hmssql.Types has the table of which SQL type each is
sent as. An instance of your own defines fieldEncoder, usually with
contramap over a built-in type's encoder.
Methods
fieldEncoder :: FieldEncoder a Source #
Instances
| ToSqlField Decimal Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder Decimal Source # fieldParam :: Decimal -> FieldParams -> FieldParams | |
| ToSqlField ByteString Source # | Any length of bytes. A value of up to 8000 bytes is declared
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder ByteString Source # fieldParam :: ByteString -> FieldParams -> FieldParams | |
| ToSqlField ByteString Source # | Declared as a strict |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder ByteString Source # fieldParam :: ByteString -> FieldParams -> FieldParams | |
| ToSqlField Int16 Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Int32 Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Int64 Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Int8 Source # |
|
Defined in Hmssql.Encoding | |
| ToSqlField Word8 Source # |
|
Defined in Hmssql.Encoding | |
| ToSqlField RawParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder RawParam Source # fieldParam :: RawParam -> FieldParams -> FieldParams | |
| ToSqlField SqlParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder SqlParam Source # fieldParam :: SqlParam -> FieldParams -> FieldParams | |
| ToSqlField StreamParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder StreamParam Source # fieldParam :: StreamParam -> FieldParams -> FieldParams | |
| ToSqlField SqlValue Source # | Each constructor is sent as the wire type |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder SqlValue Source # fieldParam :: SqlValue -> FieldParams -> FieldParams | |
| ToSqlField DateTimeOffset Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder DateTimeOffset Source # fieldParam :: DateTimeOffset -> FieldParams -> FieldParams | |
| ToSqlField Money Source # |
|
Defined in Hmssql.Encoding | |
| ToSqlField Text Source # | Any length of string. A value of up to 4000 UTF-16 code units is declared
|
Defined in Hmssql.Encoding | |
| ToSqlField Text Source # | Declared as |
Defined in Hmssql.Encoding | |
| ToSqlField Day Source # |
|
Defined in Hmssql.Encoding | |
| ToSqlField UTCTime Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder UTCTime Source # fieldParam :: UTCTime -> FieldParams -> FieldParams | |
| ToSqlField LocalTime Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder LocalTime Source # fieldParam :: LocalTime -> FieldParams -> FieldParams | |
| ToSqlField TimeOfDay Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder TimeOfDay Source # fieldParam :: TimeOfDay -> FieldParams -> FieldParams | |
| ToSqlField ZonedTime Source # | As |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder ZonedTime Source # fieldParam :: ZonedTime -> FieldParams -> FieldParams | |
| ToSqlField UUID Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Integer Source # |
|
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder Integer Source # fieldParam :: Integer -> FieldParams -> FieldParams | |
| ToSqlField String Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder String Source # fieldParam :: String -> FieldParams -> FieldParams | |
| ToSqlField Bool Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Double Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder Double Source # fieldParam :: Double -> FieldParams -> FieldParams | |
| ToSqlField Float Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField Int Source # | |
Defined in Hmssql.Encoding | |
| ToSqlField a => ToSqlField (Maybe a) Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder (Maybe a) Source # fieldParam :: Maybe a -> FieldParams -> FieldParams | |
Send a value with an explicit wire type.
Instances
| ToSqlField RawParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder RawParam Source # fieldParam :: RawParam -> FieldParams -> FieldParams | |
Any value with a ToSqlField instance, so a parameter list can mix types.
Constructors
| ToSqlField a => SqlParam a |
Instances
| ToSqlField SqlParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder SqlParam Source # fieldParam :: SqlParam -> FieldParams -> FieldParams | |
type EncodedParam = (TypeInfo, ParamValue) Source #
A parameter's wire type and value.
Sending a large value
A parameter is normally encoded into memory before it is sent. binaryStream
and textStream instead read the value as it is sent, so a value of any size can
come from a file or a socket without being held in memory:
import qualified Data.ByteString as B
import Control.Monad (unless)
import Streaming (lift)
import qualified Streaming.Prelude as S
import System.IO (IOMode (..), withBinaryFile)
fileSource :: FilePath -> Source B.ByteString
fileSource path = Source $ \use -> withBinaryFile path ReadMode (use . chunks)
where
chunks h = do
chunk <- lift (B.hGetSome h 65536)
unless (B.null chunk) (S.yield chunk >> chunks h)
insertDocument :: Connection -> FilePath -> IO Int64
insertDocument conn path = execute conn $
"INSERT INTO dbo.documents (payload) VALUES (" <> param (binaryStream (fileSource path)) <> ")"A Source opens what it needs when sending starts and closes it when sending ends,
so a Query built on this one can be sent again. sourceOf wraps a
stream you already have, which can be sent only once. These rules come with it:
- A source must not make a request on its own connection, which throws
ReentrantSource. On a MARS connection it may read a stream that was opened earlier. - If a source throws, the request is abandoned, the exception reaches the caller, and the connection stays usable.
- An output parameter can't be streamed.
A lazy ByteString or Text parameter is read as it is sent too, without
any of this. To stream a large value in a result instead, see
Hmssql.Decoding.
data ParamValue Source #
An in-memory value (Nothing is NULL), lazy bytes read as they are sent,
or a source run as it is sent. A request holding either of the last two can
be sent only once; a query builds a new request each time it is sent.
The constructors are public so that libraries can inspect and build values.
Constructors
| ParamBytes !RawBytes | |
| ParamLazy ByteString | |
| ParamStream !(Source ByteString) |
Instances
| Show ParamValue Source # | |
Defined in Hmssql.Tds.Parameter Methods showsPrec :: Int -> ParamValue -> ShowS # show :: ParamValue -> String # showList :: [ParamValue] -> ShowS # | |
Where a streamed parameter's bytes come from. It is a function of what
consumes the stream, so a resource can be scoped to exactly the send, for
example with withBinaryFile. A bare stream couldn't scope one, and a second
send would run it from wherever it had got to.
sourceOf :: Stream (Of a) IO () -> Source a Source #
Use an existing stream. Holding on to the stream yourself keeps whatever it has produced alive, and a stream can be sent only once.
sourceIO :: IO (Stream (Of a) IO ()) -> Source a Source #
A stream made by this action when sending starts. For a resource to release
after the send, use the Source constructor.
data StreamParam Source #
A parameter read as it is sent, so a large value needn't be in memory. Its
type is a (max) type or xml; any other is an EncodeError
before anything is sent.
Constructors
| StreamParam !TypeInfo !ParamValue |
Instances
| ToSqlField StreamParam Source # | |
Defined in Hmssql.Encoding Methods fieldEncoder :: FieldEncoder StreamParam Source # fieldParam :: StreamParam -> FieldParams -> FieldParams | |
binaryStream :: Source ByteString -> StreamParam Source #
A varbinary(max) parameter, read from the source as it is sent.
textStream :: Source Text -> StreamParam Source #
An nvarchar(max) parameter, read from the source as it is sent.
streamAs :: TypeInfo -> Source ByteString -> StreamParam Source #
A parameter of the given (max) or xml type, read from the source as it
is sent. The bytes are the caller's to encode for that type. For UTF-16,
their total must be an even number of bytes.
lazyAs :: TypeInfo -> ByteString -> StreamParam Source #
streamAs for lazy bytes, forced as they are sent.
Row encoders
newtype RowEncoder a Source #
Produces each parameter with its name ("" means positional, @pN
by position among the positional ones; otherwise the name with its
leading @) and its encoding for a connection. The parameters, their
number and their names never depend on the connection; only the encoded
values may.
Constructors
| RowEncoder | |
Fields
| |
Instances
| Contravariant RowEncoder Source # | An encoder of |
Defined in Hmssql.Encoding Methods contramap :: (a' -> a) -> RowEncoder a -> RowEncoder a' # (>$) :: b -> RowEncoder b -> RowEncoder a # | |
class ToSqlRow a where Source #
Types that can be sent as a list of parameters: the @p1, @p2,
... of mkQuery, or a row of executeMany or
bulkInsert. Derive it for a record whose fields are
ToSqlField types, one parameter per field in order:
data NewCustomer = NewCustomer { newName :: Text, newBirthDate :: Maybe Day }
deriving stock (Generic)
deriving anyclass (ToSqlRow)Tuples of up to ten fields, (), Only, a list of one ToSqlField
type, a list of SqlParam to mix types, and NamedParams have
instances.
Minimal complete definition
Nothing
Methods
rowEncoder :: RowEncoder a Source #
default rowEncoder :: (Generic a, GRowEncoder (Rep a)) => RowEncoder a Source #
Instances
divideRow :: (a -> (b, c)) -> RowEncoder b -> RowEncoder c -> RowEncoder a Source #
Combine two encoders over a product: the parameters of the first, then
those of the second. For a ToSqlRow written by hand, e.g. a record
with a field that is sent as two parameters.
singleParam :: FieldEncoder a -> RowEncoder a Source #
A row of one positional parameter.
genericToSqlRow :: (Generic a, GRowEncoder (Rep a)) => RowEncoder a Source #
The encoder a derived ToSqlRow instance uses: one positional
parameter per field of a record (or product constructor), in order.
Named parameters
type NamedParam = (Text, SqlParam) Source #
A parameter's name and its value.
newtype NamedParams Source #
Parameters that the SQL text refers to by name. The leading @ is
optional. A name must be a T-SQL variable name, and not of the form
@pN, which is reserved for the positional parameters; the query
functions check both before sending anything. Bulk copy matches the
names, with that one @ removed, against the table's columns
(Hmssql.BulkCopy).
mkQuery "UPDATE dbo.customer SET email = @email WHERE id = @id"
(NamedParams [("email", SqlParam newEmail), ("id", SqlParam customerId)])Constructors
| NamedParams [NamedParam] |
Instances
| ToSqlRow NamedParams Source # | |
Defined in Hmssql.Encoding Methods | |