{-|
Module: Squeal.PostgreSQL.UUID.OSSP
Description: uuid-ossp
Copyright: (c) Eitan Chatav, 2020
Maintainer: eitan@morphism.tech
Stability: experimental

This module provides functions to generate universally
unique identifiers (UUIDs) using one of several standard algorithms.
There are also functions to produce certain special UUID constants.
-}

{-# LANGUAGE
    DataKinds
  , OverloadedStrings
  , TypeOperators
#-}

module Squeal.PostgreSQL.UUID.OSSP
  ( -- * Definition
    createUuidOssp
    -- * Generation
  , uuidGenerateV1
  , uuidGenerateV1mc
  , uuidGenerateV3
  , uuidGenerateV4
  , uuidGenerateV5
    -- * Constants
  , uuidNil
  , uuidNSUrl
  , uuidNSDns
  , uuidNSOid
  , uuidNSX500
  ) where

import Squeal.PostgreSQL

-- | Loads ltree extension into the current database.
createUuidOssp :: Definition db db
createUuidOssp :: Definition db db
createUuidOssp = ByteString -> Definition db db
forall (db0 :: SchemasType) (db1 :: SchemasType).
ByteString -> Definition db0 db1
UnsafeDefinition ByteString
"CREATE EXTENSION \"uuid-ossp\";"

-- | This function generates a version 1 UUID.
-- This involves the MAC address of the computer and a time stamp.
-- Note that UUIDs of this kind reveal the identity of the computer
-- that created the identifier and the time at which it did so,
-- which might make it unsuitable for certain security-sensitive applications.
uuidGenerateV1 :: Expr (null 'PGuuid)
uuidGenerateV1 :: Expression grp lat with db params from (null 'PGuuid)
uuidGenerateV1 = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_generate_v1()"

-- | This function generates a version 1 UUID but uses a random multicast
-- MAC address instead of the real MAC address of the computer.
uuidGenerateV1mc :: Expr (null 'PGuuid)
uuidGenerateV1mc :: Expression grp lat with db params from (null 'PGuuid)
uuidGenerateV1mc = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_generate_v1mc()"

{- | This function generates a version 3 UUID in the given namespace
using the specified input name. The namespace should be one of the
special constants produced by the uuidNS* functions.
(It could be any UUID in theory.)
The name is an identifier in the selected namespace.
For example:
@
uuidGenerateV3 (uuidNSUrl *: "http://www.postgresql.org")
@

The name parameter will be MD5-hashed,
so the cleartext cannot be derived from the generated UUID.
The generation of UUIDs by this method has no random or
environment-dependent element and is therefore reproducible.
-}
uuidGenerateV3 :: '[null 'PGuuid, null 'PGtext] ---> null 'PGuuid
uuidGenerateV3 :: NP
  (Expression grp lat with db params from)
  '[null 'PGuuid, null 'PGtext]
-> Expression grp lat with db params from (null 'PGuuid)
uuidGenerateV3 = ByteString -> '[null 'PGuuid, null 'PGtext] ---> null 'PGuuid
forall (xs :: [NullType]) (y :: NullType).
SListI xs =>
ByteString -> xs ---> y
unsafeFunctionN ByteString
"uuid_generate_v3"

{- | This function generates a version 4 UUID,
which is derived entirely from random numbers.
-}
uuidGenerateV4 :: Expr (null 'PGuuid)
uuidGenerateV4 :: Expression grp lat with db params from (null 'PGuuid)
uuidGenerateV4 = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_generate_v4()"

{- | This function generates a version 5 UUID,
which works like a version 3 UUID except that
SHA-1 is used as a hashing method.
Version 5 should be preferred over version 3 because
SHA-1 is thought to be more secure than MD5.
-}
uuidGenerateV5 :: '[null 'PGuuid, null 'PGtext] ---> null 'PGuuid
uuidGenerateV5 :: NP
  (Expression grp lat with db params from)
  '[null 'PGuuid, null 'PGtext]
-> Expression grp lat with db params from (null 'PGuuid)
uuidGenerateV5 = ByteString -> '[null 'PGuuid, null 'PGtext] ---> null 'PGuuid
forall (xs :: [NullType]) (y :: NullType).
SListI xs =>
ByteString -> xs ---> y
unsafeFunctionN ByteString
"uuid_generate_v5"

-- | A "nil" UUID constant, which does not occur as a real UUID.
uuidNil :: Expr (null 'PGuuid)
uuidNil :: Expression grp lat with db params from (null 'PGuuid)
uuidNil = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_nil()"

-- | Constant designating the DNS namespace for UUIDs.
uuidNSDns :: Expr (null 'PGuuid)
uuidNSDns :: Expression grp lat with db params from (null 'PGuuid)
uuidNSDns = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_ns_dns()"

-- | Constant designating the URL namespace for UUIDs.
uuidNSUrl :: Expr (null 'PGuuid)
uuidNSUrl :: Expression grp lat with db params from (null 'PGuuid)
uuidNSUrl = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_ns_url()"

-- | Constant designating the ISO object identifier (OID) namespace for UUIDs.
-- (This pertains to ASN.1 OIDs,
-- which are unrelated to the OIDs used in PostgreSQL.)
uuidNSOid :: Expr (null 'PGuuid)
uuidNSOid :: Expression grp lat with db params from (null 'PGuuid)
uuidNSOid = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_ns_oid()"

-- | Constant designating the X.500 distinguished
-- name (DN) namespace for UUIDs.
uuidNSX500 :: Expr (null 'PGuuid)
uuidNSX500 :: Expression grp lat with db params from (null 'PGuuid)
uuidNSX500 = ByteString -> Expression grp lat with db params from (null 'PGuuid)
forall (grp :: Grouping) (lat :: FromType) (with :: FromType)
       (db :: SchemasType) (params :: [NullType]) (from :: FromType)
       (ty :: NullType).
ByteString -> Expression grp lat with db params from ty
UnsafeExpression ByteString
"uuid_ns_x500()"