1{-# LANGUAGE FlexibleInstances, FlexibleContexts, TypeOperators, UndecidableInstances, ScopedTypeVariables, DefaultSignatures #-}
2module ProjectM36.Tupleable where
6import ProjectM36.TupleSet
7import ProjectM36.Atomable
8import ProjectM36.DataTypes.Primitive
9import ProjectM36.Attribute hiding (null)
11import qualified Data.Vector as V
12import qualified Data.Text as T
20 deriving (Generic, Show)
22data Test2T a b = Test2C {
26 deriving (Generic, Show)
28instance (Atomable a, Atomable b, Show a, Show b) => Tupleable (Test2T a b)
30instance Tupleable Test1T
32data TestUnnamed1 = TestUnnamed1 Int Double T.Text
33 deriving (Show,Eq, Generic)
35instance Tupleable TestUnnamed1
38-- | Convert a 'Traverseable' of 'Tupleable's to an 'Insert' 'DatabaseContextExpr'. This is useful for converting, for example, a list of data values to a set of Insert expressions which can be used to add the values to the database.
39toInsertExpr :: (Tupleable a, Traversable t) => t a -> RelVarName -> Either RelationalError DatabaseContextExpr
40toInsertExpr vals rvName = do
41 let attrs = toAttributes (head (toList vals))
42 tuples <- mkTupleSet attrs $ toList (fmap toTuple vals)
43 let rel = MakeStaticRelation attrs tuples
44 pure (Insert rvName rel)
46-- | Convert a 'Tupleable' to a create a 'Define' expression which can be used to create an empty relation variable. Use 'toInsertExpr' to insert the actual tuple data. This function is typically used with 'undefined'.
47toDefineExpr :: Tupleable a => a -> RelVarName -> DatabaseContextExpr
48toDefineExpr val rvName = Define rvName (map NakedAttributeExpr (V.toList attrs))
50 attrs = toAttributes val
54class Tupleable a where
55 toTuple :: a -> RelationTuple
57 fromTuple :: RelationTuple -> Either RelationalError a
59 toAttributes :: a -> Attributes
61 default toTuple :: (Generic a, TupleableG (Rep a)) => a -> RelationTuple
62 toTuple v = toTupleG (from v)
64 default fromTuple :: (Generic a, TupleableG (Rep a)) => RelationTuple -> Either RelationalError a
65 fromTuple tup = to <$> fromTupleG tup
67 default toAttributes :: (Generic a, TupleableG (Rep a)) => a -> Attributes
68 toAttributes v = toAttributesG (from v)
70class TupleableG g where
71 toTupleG :: g a -> RelationTuple
72 toAttributesG :: g a -> Attributes
73 fromTupleG :: RelationTuple -> Either RelationalError (g a)
76instance (Datatype c, TupleableG a) => TupleableG (M1 D c a) where
77 toTupleG (M1 v) = toTupleG v
78 toAttributesG (M1 v) = toAttributesG v
79 fromTupleG v = M1 <$> fromTupleG v
82instance (Constructor c, TupleableG a, AtomableG a) => TupleableG (M1 C c a) where
83 toTupleG (M1 v) = RelationTuple attrs atoms
85 attrsToCheck = toAttributesG v
86 counter = V.generate (V.length attrsToCheck) id
87 attrs = V.zipWith (\num attr@(Attribute name typ) -> if T.null name then
88 Attribute ("attr" <> T.pack (show (num + 1))) typ
90 attr) counter attrsToCheck
91 atoms = V.fromList (toAtomsG v)
92 toAttributesG (M1 v) = toAttributesG v
93 fromTupleG tup = M1 <$> fromTupleG tup
96instance (TupleableG a, TupleableG b) => TupleableG (a :*: b) where
97 toTupleG = error "toTupleG"
98 toAttributesG ~(x :*: y) = toAttributesG x V.++ toAttributesG y --a bit of extra laziness prevents whnf so that we can use toAttributes (undefined :: Test2T Int Int) without throwing an exception
99 fromTupleG tup = (:*:) <$> fromTupleG tup <*> fromTupleG (trimTuple 1 tup)
102instance (Selector c, AtomableG a) => TupleableG (M1 S c a) where
103 toTupleG = error "toTupleG"
104 toAttributesG m@(M1 v) = V.singleton (Attribute name aType)
106 name = T.pack (selName m)
107 aType = toAtomTypeG v
108 fromTupleG tup = if null name then -- non-record type, just pull off the first tuple item
109 M1 <$> atomv (V.head (tupleAtoms tup))
111 atom <- atomForAttributeName (T.pack name) tup
115 expectedAtomType = atomType (V.head (toAttributesG (undefined :: M1 S c a x)))
116 atomv atom = maybe (Left (AtomTypeMismatchError
118 (atomTypeForAtom atom)
119 )) Right (fromAtomG atom [atom])
120 name = selName (undefined :: M1 S c a x)
122--constructors with no arguments
123--basically useless but orthoganal to relationTrue
124instance TupleableG U1 where
125 toTupleG _= emptyTuple
126 toAttributesG _ = emptyAttributes
127 fromTupleG _ = pure U1
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list