forked from zio/zio-sql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
table.scala
190 lines (147 loc) · 6.96 KB
/
table.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package zio.sql
import java.time._
import java.util.UUID
import zio.Chunk
trait TableModule { self: ExprModule with SelectModule =>
sealed case class ColumnSchema[A](value: A)
sealed trait ColumnSet {
type ColumnsRepr[T]
type Append[That <: ColumnSet] <: ColumnSet
def ++[That <: ColumnSet](that: That): Append[That]
def columnsUntyped: List[Column.Untyped]
protected def mkColumns[T](name: TableName): ColumnsRepr[T]
}
object ColumnSet {
type ConsAux[Head, Tail <: ColumnSet, TableType, ColumnsRepr0[TableType]] = ColumnSet.Cons[Head, Tail] { type ColumnsRepr = ColumnsRepr0[TableType] }
type Empty = Empty.type
type :*:[A, B <: ColumnSet] = Cons[A, B]
type Singleton[A] = Cons[A, Empty]
case object Empty extends ColumnSet {
type ColumnsRepr[_] = Unit
type Append[That <: ColumnSet] = That
override def ++[That <: ColumnSet](that: That): Append[That] = that
override def columnsUntyped: List[Column.Untyped] = Nil
override protected def mkColumns[T](name: TableName): ColumnsRepr[T] = ()
}
sealed case class Cons[A, B <: ColumnSet](head: Column[A], tail: B) extends ColumnSet { self =>
type ColumnsRepr[T] = (Expr[Features.Source, T, A], tail.ColumnsRepr[T])
type Append[That <: ColumnSet] = Cons[A, tail.Append[That]]
type TableSource = Table.Source.Aux_[ColumnsRepr, A :*: B]
override def ++[That <: ColumnSet](that: That): Append[That] = Cons(head, tail ++ that)
override def columnsUntyped: List[Column.Untyped] = head :: tail.columnsUntyped
def table(name0: TableName): Table.Source.Aux_[ColumnsRepr, A :*: B] =
new Table.Source {
type Repr[C] = ColumnsRepr[C]
type Cols = A :*: B
val name: TableName = name0
val columnSchema: ColumnSchema[A :*: B] = ColumnSchema(self)
val columns: ColumnsRepr[TableType] = mkColumns[TableType](name0)
val columnsUntyped: List[Column.Untyped] = self.columnsUntyped
}
override protected def mkColumns[T](name: TableName): ColumnsRepr[T] =
(Expr.Source(name, head), tail.mkColumns(name))
}
def bigDecimal(name: String): Singleton[BigDecimal] = singleton[BigDecimal](name)
def boolean(name: String): Singleton[Boolean] = singleton[Boolean](name)
def byteArray(name: String): Singleton[Chunk[Byte]] = singleton[Chunk[Byte]](name)
def char(name: String): Singleton[Char] = singleton[Char](name)
def double(name: String): Singleton[Double] = singleton[Double](name)
def float(name: String): Singleton[Float] = singleton[Float](name)
def instant(name: String): Singleton[Instant] = singleton[Instant](name)
def int(name: String): Singleton[Int] = singleton[Int](name)
def localDate(name: String): Singleton[LocalDate] = singleton[LocalDate](name)
def localDateTime(name: String): Singleton[LocalDateTime] = singleton[LocalDateTime](name)
def localTime(name: String): Singleton[LocalTime] = singleton[LocalTime](name)
def long(name: String): Singleton[Long] = singleton[Long](name)
def offsetDateTime(name: String): Singleton[OffsetDateTime] = singleton[OffsetDateTime](name)
def offsetTime(name: String): Singleton[OffsetTime] = singleton[OffsetTime](name)
def short(name: String): Singleton[Short] = singleton[Short](name)
def singleton[A: TypeTag](name: String): Singleton[A] = Cons(Column.Named[A](name), Empty)
def string(name: String): Singleton[String] = singleton[String](name)
def uuid(name: String): Singleton[UUID] = singleton[UUID](name)
def zonedDateTime(name: String): Singleton[ZonedDateTime] = singleton[ZonedDateTime](name)
}
object :*: {
def unapply[A, B](tuple: (A, B)): Some[(A, B)] = Some(tuple)
}
sealed trait Column[+A]{
def typeTag: TypeTag[A]
}
object Column {
sealed case class Named[A: TypeTag](columnName: String) extends Column[A] {
def typeTag: TypeTag[A] = implicitly[TypeTag[A]]
}
sealed case class Indexed[A: TypeTag](index: Int) extends Column[A] {
def typeTag: TypeTag[A] = implicitly[TypeTag[A]]
}
type Untyped = Column[_]
}
sealed trait JoinType
object JoinType {
case object Inner extends JoinType
case object LeftOuter extends JoinType
case object RightOuter extends JoinType
case object FullOuter extends JoinType
}
/**
* (left join right) on (...)
*/
sealed trait Table { self =>
type TableType
final def fullOuter[That](that: Table.Aux[That]): Table.JoinBuilder[self.TableType, That] =
new Table.JoinBuilder[self.TableType, That](JoinType.FullOuter, self, that)
final def join[That](that: Table.Aux[That]): Table.JoinBuilder[self.TableType, That] =
new Table.JoinBuilder[self.TableType, That](JoinType.Inner, self, that)
final def leftOuter[That](that: Table.Aux[That]): Table.JoinBuilder[self.TableType, That] =
new Table.JoinBuilder[self.TableType, That](JoinType.LeftOuter, self, that)
final def rightOuter[That](that: Table.Aux[That]): Table.JoinBuilder[self.TableType, That] =
new Table.JoinBuilder[self.TableType, That](JoinType.RightOuter, self, that)
val columnsUntyped: List[Column.Untyped]
}
type TableExtension[+A] <: Table.TableEx
object Table {
trait TableEx {
def columnsUntyped: List[Column.Untyped]
}
class JoinBuilder[A, B](joinType: JoinType, left: Table.Aux[A], right: Table.Aux[B]) {
def on[F](expr: Expr[F, A with B, Boolean]): Table.Aux[A with B] =
Joined(joinType, left, right, expr)
}
type Aux[A] = Table { type TableType = A }
//you need insanity in your life
trait Insanity {
def ahhhhhhhhhhhhh[A]: A
}
sealed trait Source extends Table with Insanity {
type Repr[_]
type Cols
val name: TableName
val columnSchema: ColumnSchema[Cols]
val columns: Repr[TableType]
override def ahhhhhhhhhhhhh[A]: A = ??? //don't remove or it'll break
}
object Source {
type Aux_[F[_], B] = Table.Source {
type Repr[X] = F[X]
type Cols = B
}
type Aux[F[_], A, B] = Table.Source {
type Repr[X] = F[X]
type TableType = A
type Cols = B
}
}
sealed case class Joined[F, A, B](
joinType: JoinType,
left: Table.Aux[A],
right: Table.Aux[B],
on: Expr[F, A with B, Boolean]
) extends Table {
type TableType = left.TableType with right.TableType
val columnsUntyped: List[Column.Untyped] = left.columnsUntyped ++ right.columnsUntyped
}
sealed case class DialectSpecificTable[A](tableExtension: TableExtension[A]) extends Table {
val columnsUntyped: List[Column.Untyped] = tableExtension.columnsUntyped
}
}
}