Skip to content

Commit 7479c56

Browse files
committed
Schema DDL: separate redshift-specific code from standard SQL (Closes #372)
1 parent d66ffea commit 7479c56

37 files changed

+901
-524
lines changed

0-common/schema-ddl/src/main/scala/com.snowplowanalytics/iglu.schemaddl/redshift/AlterTable.scala

+9-44
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212
*/
1313
package com.snowplowanalytics.iglu.schemaddl.redshift
1414

15+
import com.snowplowanalytics.iglu.schemaddl.sql.{AlterTableStatement, ColumnAttribute, DataType, Ddl, Default, Nullability}
16+
1517
/**
1618
* Class holding data to alter some table with single [[AlterTableStatement]]
19+
*
1720
* @see http://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html
1821
*
1922
* ALTER TABLE table_name
@@ -37,56 +40,18 @@ package com.snowplowanalytics.iglu.schemaddl.redshift
3740
* FOREIGN KEY (column_name [, ... ] )
3841
* REFERENCES reftable [ ( refcolumn ) ]}
3942
*/
40-
case class AlterTable(tableName: String, statement: AlterTableStatement) extends Statement {
41-
def toDdl = s"ALTER TABLE $tableName ${statement.toDdl}"
42-
}
43-
44-
/**
45-
* Sum-type to represent some statement
46-
*/
47-
sealed trait AlterTableStatement extends Ddl
48-
49-
sealed trait DropModeValue extends Ddl
50-
case object CascadeDrop extends DropModeValue { def toDdl = "CASCADE" }
51-
case object RestrictDrop extends DropModeValue { def toDdl = "RESTRICT" }
43+
sealed trait RedShiftAlterTableStatement extends RedShiftDdl
5244

53-
case class DropMode(value: DropModeValue) extends Ddl {
54-
def toDdl = value.toDdl
55-
}
56-
57-
case class AddConstraint(tableConstraint: TableConstraint) extends AlterTableStatement {
58-
def toDdl = s"ADD ${tableConstraint.toDdl}"
59-
}
6045

61-
case class DropConstraint(constraintName: String, mode: Option[DropMode]) extends AlterTableStatement {
62-
def toDdl = s"DROP $constraintName${mode.map(" " + _.toDdl).getOrElse("")}"
63-
}
64-
65-
case class OwnerTo(newOwner: String) extends AlterTableStatement {
66-
def toDdl = s"OWNER TO $newOwner"
67-
}
68-
69-
case class RenameTo(newName: String) extends AlterTableStatement {
70-
def toDdl = s"RENAME TO $newName"
71-
}
72-
73-
case class RenameColumn(columnName: String, newName: String) extends AlterTableStatement {
74-
def toDdl = s"RENAME COLUMN $columnName TO $newName"
75-
}
76-
77-
case class AddColumn(
46+
private[redshift] case class AddColumn[T <: RedShiftDdl](
7847
columnName: String,
79-
columnType: DataType,
80-
default: Option[Default],
81-
encode: Option[CompressionEncoding],
82-
nullability: Option[Nullability]
48+
columnType: DataType[Ddl],
49+
default: Option[Default[T]],
50+
encode: Option[ColumnAttribute[T]],
51+
nullability: Option[Nullability[T]]
8352
) extends AlterTableStatement {
8453
def toDdl = {
8554
val attrs = List(nullability, encode, default).flatten.map(_.toDdl).mkString(" ")
8655
s"""ADD COLUMN "$columnName" ${columnType.toDdl} $attrs"""
8756
}
8857
}
89-
90-
case class DropColumn(columnName: String, mode: Option[DropMode]) extends Ddl {
91-
def toDdl = s"DROP COLUMN $columnName${mode.map(" " + _.toDdl).getOrElse("")}"
92-
}

0-common/schema-ddl/src/main/scala/com.snowplowanalytics/iglu.schemaddl/redshift/Column.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
*/
1313
package com.snowplowanalytics.iglu.schemaddl.redshift
1414

15+
import com.snowplowanalytics.iglu.schemaddl.sql.{ColumnAttribute, ColumnConstraint, DataType, Ddl}
16+
1517
/**
1618
* Class holding all information about Redshift's column
1719
*
@@ -20,12 +22,12 @@ package com.snowplowanalytics.iglu.schemaddl.redshift
2022
* @param columnAttributes set of column_attributes such as ENCODE
2123
* @param columnConstraints set of column_constraints such as NOT NULL
2224
*/
23-
case class Column(
25+
private[redshift] case class Column[T <: RedShiftDdl](
2426
columnName: String,
25-
dataType: DataType,
26-
columnAttributes: Set[ColumnAttribute] = Set.empty[ColumnAttribute],
27-
columnConstraints: Set[ColumnConstraint] = Set.empty[ColumnConstraint]
28-
) extends Ddl {
27+
dataType: DataType[Ddl],
28+
columnAttributes: Set[ColumnAttribute[T]] = Set.empty[ColumnAttribute[T]],
29+
columnConstraints: Set[ColumnConstraint[T]] = Set.empty[ColumnConstraint[T]]
30+
) extends RedShiftDdl {
2931

3032
/**
3133
* Formatted column's DDL
@@ -46,7 +48,7 @@ case class Column(
4648
*
4749
* @return string representing column without formatting
4850
*/
49-
def toDdl = toFormattedDdl((1, 1, 1, 1, 1))
51+
override def toDdl = toFormattedDdl((1, 1, 1, 1, 1))
5052

5153
// Get warnings only from data types suggestions
5254
override val warnings = dataType.warnings

0-common/schema-ddl/src/main/scala/com.snowplowanalytics/iglu.schemaddl/redshift/ColumnAttribute.scala

+8-19
Original file line numberDiff line numberDiff line change
@@ -10,43 +10,32 @@
1010
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
13-
package com.snowplowanalytics.iglu.schemaddl.redshift
13+
package com.snowplowanalytics.iglu.schemaddl
14+
package redshift
1415

15-
/**
16-
* column_attributes are:
17-
* [ DEFAULT default_expr ]
18-
* [ IDENTITY ( seed, step ) ]
19-
* [ ENCODE encoding ]
20-
* [ DISTKEY ]
21-
* [ SORTKEY ]
22-
*/
23-
sealed trait ColumnAttribute extends Ddl
24-
25-
case class Default(value: String) extends ColumnAttribute {
26-
def toDdl = s"DEFAULT $value"
27-
}
16+
import com.snowplowanalytics.iglu.schemaddl.sql.ColumnAttribute
2817

29-
case class Identity(seed: Int, step: Int) extends ColumnAttribute {
18+
case class Identity(seed: Int, step: Int) extends ColumnAttribute[RedShiftDdl] {
3019
def toDdl = s"IDENTITY ($seed, $step)"
3120
}
3221

33-
case object DistKey extends ColumnAttribute {
22+
case object DistKey extends ColumnAttribute[RedShiftDdl] {
3423
def toDdl = "DISTKEY"
3524
}
3625

37-
case object SortKey extends ColumnAttribute {
26+
case object SortKey extends ColumnAttribute[RedShiftDdl] {
3827
def toDdl = "SORTKEY"
3928
}
4029

4130
/**
4231
* Compression encodings
4332
* http://docs.aws.amazon.com/redshift/latest/dg/c_Compression_encodings.html
4433
*/
45-
case class CompressionEncoding(value: CompressionEncodingValue) extends ColumnAttribute {
34+
case class CompressionEncoding(value: CompressionEncodingValue) extends ColumnAttribute[RedShiftDdl] {
4635
def toDdl = s"ENCODE ${value.toDdl}"
4736
}
4837

49-
sealed trait CompressionEncodingValue extends Ddl
38+
sealed trait CompressionEncodingValue extends RedShiftDdl
5039

5140
case object RawEncoding extends CompressionEncodingValue { def toDdl = "RAW" }
5241

0-common/schema-ddl/src/main/scala/com.snowplowanalytics/iglu.schemaddl/redshift/CreateTable.scala

+22-20
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1111
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
1212
*/
13-
package com.snowplowanalytics.iglu.schemaddl.redshift
13+
package com.snowplowanalytics.iglu.schemaddl
14+
package redshift
15+
16+
import com.snowplowanalytics.iglu.schemaddl.sql.{Statement, TableAttribute, TableConstraint}
1417

1518
/**
1619
* Class holding all information about Redshift's table
@@ -20,28 +23,28 @@ package com.snowplowanalytics.iglu.schemaddl.redshift
2023
* @param tableConstraints set of table_constraints such as PRIMARY KEY
2124
* @param tableAttributes set of table_attributes such as DISTSTYLE
2225
*/
23-
case class CreateTable(
24-
tableName: String,
25-
columns: List[Column],
26-
tableConstraints: Set[TableConstraint] = Set.empty[TableConstraint],
27-
tableAttributes: Set[TableAttribute] = Set.empty[TableAttribute]
28-
) extends Statement {
26+
private[redshift] case class CreateTable[T <: RedShiftDdl](
27+
tableName: String,
28+
columns: List[Column[T]],
29+
tableConstraints: Set[TableConstraint] = Set.empty[TableConstraint],
30+
tableAttributes: Set[TableAttribute[T]] = Set.empty[TableAttribute[T]]
31+
) extends Statement {
2932

3033
def toDdl = {
3134
val columnsDdl = columns.map(_.toFormattedDdl(tabulation)
3235
.replaceAll("\\s+$", ""))
3336
.mkString(",\n")
3437
s"""CREATE TABLE IF NOT EXISTS $tableName (
35-
|$columnsDdl$getConstraints
36-
|)$getAttributes""".stripMargin
38+
|$columnsDdl$getConstraints
39+
|)$getAttributes""".stripMargin
3740
}
3841

3942
// Collect warnings from every column
4043
override val warnings = columns.flatMap(_.warnings)
4144

4245
// Tuple with lengths of each column in formatted DDL file
4346
private val tabulation = {
44-
def getLength(f: Column => Int): Int =
47+
def getLength(f: Column[T] => Int): Int =
4548
columns.foldLeft(0)((acc, b) => if (acc > f(b)) acc else f(b))
4649

4750
val prepend = 4
@@ -54,26 +57,25 @@ case class CreateTable(
5457
}
5558

5659
/**
57-
* Format constraints for table
58-
*
59-
* @return string with formatted table_constaints
60-
*/
60+
* Format constraints for table
61+
*
62+
* @return string with formatted table_constaints
63+
*/
6164
private def getConstraints: String = {
6265
if (tableConstraints.isEmpty) ""
6366
else ",\n" + tableConstraints.map(c => withTabs(tabulation._1, " ") + c.toDdl).
6467

6568
mkString("\n")
6669
}
6770
/**
68-
* Format attributes for table
69-
*
70-
* @return string with formatted table_attributes
71-
*/
71+
* Format attributes for table
72+
*
73+
* @return string with formatted table_attributes
74+
*/
7275
private def getAttributes: String = {
7376
if (tableConstraints.isEmpty) ""
7477
else "\n" + tableAttributes.map(_.toDdl).
7578

7679
mkString("\n")
7780
}
78-
}
79-
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright (c) 2014-2016 Snowplow Analytics Ltd. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
package com.snowplowanalytics.iglu.schemaddl.redshift
14+
15+
import com.snowplowanalytics.iglu.schemaddl.sql.Ddl
16+
17+
/**
18+
* Base class for everything that can be represented as Redshift DDL
19+
*/
20+
trait RedShiftDdl extends Ddl

0-common/schema-ddl/src/main/scala/com.snowplowanalytics/iglu.schemaddl/redshift/TableAttribute.scala

+8-6
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,22 @@ package com.snowplowanalytics.iglu.schemaddl.redshift
1515
// Scalaz
1616
import scalaz.NonEmptyList
1717

18+
// This project
19+
import com.snowplowanalytics.iglu.schemaddl.sql.TableAttribute
20+
1821
/**
1922
* table_attributes are:
2023
* [ DISTSTYLE { EVEN | KEY | ALL } ]
2124
* [ DISTKEY ( column_name ) ]
2225
* [ [COMPOUND | INTERLEAVED ] SORTKEY ( column_name [, ...] ) ]
2326
*/
24-
sealed trait TableAttribute extends Ddl
2527

26-
sealed trait DiststyleValue extends Ddl
28+
sealed trait DiststyleValue extends RedShiftDdl
2729
case object Even extends DiststyleValue { def toDdl = "EVEN" }
2830
case object Key extends DiststyleValue { def toDdl = "KEY" }
2931
case object All extends DiststyleValue { def toDdl = "ALL" }
3032

31-
sealed trait Sortstyle extends Ddl
33+
sealed trait Sortstyle extends RedShiftDdl
3234

3335
case object CompoundSortstyle extends Sortstyle {
3436
def toDdl = "COMPOUND"
@@ -38,16 +40,16 @@ case object InterleavedSortstyle extends Sortstyle {
3840
def toDdl = "INTERLEAVED"
3941
}
4042

41-
case class Diststyle(diststyle: DiststyleValue) extends TableAttribute {
43+
case class Diststyle(diststyle: DiststyleValue) extends TableAttribute[RedShiftDdl] {
4244
def toDdl = "DISTSTYLE " + diststyle.toDdl
4345
}
4446

4547
// Don't confuse with redshift.DistKey which is applicable for columns
46-
case class DistKeyTable(columnName: String) extends TableAttribute {
48+
case class DistKeyTable(columnName: String) extends TableAttribute[RedShiftDdl] {
4749
def toDdl = s"DISTKEY ($columnName)"
4850
}
4951

5052
// Don't confuse with redshift.SortKey which is applicable for columns
51-
case class SortKeyTable(sortstyle: Option[Sortstyle], columns: NonEmptyList[String]) extends TableAttribute {
53+
case class SortKeyTable(sortstyle: Option[Sortstyle], columns: NonEmptyList[String]) extends TableAttribute[RedShiftDdl] {
5254
def toDdl = sortstyle.map(_.toDdl + " ").getOrElse("") + "SORTKEY (" + columns.list.mkString(",") + ")"
5355
}

0 commit comments

Comments
 (0)