40 |
40 |
41 /* columns */ |
41 /* columns */ |
42 |
42 |
43 object Column |
43 object Column |
44 { |
44 { |
45 def int(name: String, strict: Boolean = true): Column[Int] = new Column_Int(name, strict) |
45 def int(name: String, strict: Boolean = true, primary_key: Boolean = false): Column[Int] = |
46 def long(name: String, strict: Boolean = true): Column[Long] = new Column_Long(name, strict) |
46 new Column_Int(name, strict, primary_key) |
47 def double(name: String, strict: Boolean = true): Column[Double] = new Column_Double(name, strict) |
47 def long(name: String, strict: Boolean = true, primary_key: Boolean = false): Column[Long] = |
48 def string(name: String, strict: Boolean = true): Column[String] = new Column_String(name, strict) |
48 new Column_Long(name, strict, primary_key) |
49 def bytes(name: String, strict: Boolean = true): Column[Bytes] = new Column_Bytes(name, strict) |
49 def double(name: String, strict: Boolean = true, primary_key: Boolean = false): Column[Double] = |
|
50 new Column_Double(name, strict, primary_key) |
|
51 def string(name: String, strict: Boolean = true, primary_key: Boolean = false): Column[String] = |
|
52 new Column_String(name, strict, primary_key) |
|
53 def bytes(name: String, strict: Boolean = true, primary_key: Boolean = false): Column[Bytes] = |
|
54 new Column_Bytes(name, strict, primary_key) |
50 } |
55 } |
51 |
56 |
52 abstract class Column[+A] private[SQL](val name: String, val strict: Boolean) |
57 abstract class Column[+A] private[SQL]( |
|
58 val name: String, val strict: Boolean, val primary_key: Boolean) |
53 { |
59 { |
54 def sql_name: String = quote_ident(name) |
60 def sql_name: String = quote_ident(name) |
55 def sql_type: String |
61 def sql_type: String |
56 def sql_decl: String = sql_name + " " + sql_type + (if (strict) " NOT NULL" else "") |
62 def sql_decl: String = |
|
63 sql_name + " " + sql_type + |
|
64 (if (strict) " NOT NULL" else "") + |
|
65 (if (primary_key) " PRIMARY KEY" else "") |
|
66 |
57 def string(rs: ResultSet): String = |
67 def string(rs: ResultSet): String = |
58 { |
68 { |
59 val s = rs.getString(name) |
69 val s = rs.getString(name) |
60 if (s == null) "" else s |
70 if (s == null) "" else s |
61 } |
71 } |
67 } |
77 } |
68 |
78 |
69 override def toString: String = sql_decl |
79 override def toString: String = sql_decl |
70 } |
80 } |
71 |
81 |
72 class Column_Int private[SQL](name: String, strict: Boolean) |
82 class Column_Int private[SQL](name: String, strict: Boolean, primary_key: Boolean) |
73 extends Column[Int](name, strict) |
83 extends Column[Int](name, strict, primary_key) |
74 { |
84 { |
75 def sql_type: String = "INTEGER" |
85 def sql_type: String = "INTEGER" |
76 def apply(rs: ResultSet): Int = rs.getInt(name) |
86 def apply(rs: ResultSet): Int = rs.getInt(name) |
77 } |
87 } |
78 |
88 |
79 class Column_Long private[SQL](name: String, strict: Boolean) |
89 class Column_Long private[SQL](name: String, strict: Boolean, primary_key: Boolean) |
80 extends Column[Long](name, strict) |
90 extends Column[Long](name, strict, primary_key) |
81 { |
91 { |
82 def sql_type: String = "INTEGER" |
92 def sql_type: String = "INTEGER" |
83 def apply(rs: ResultSet): Long = rs.getLong(name) |
93 def apply(rs: ResultSet): Long = rs.getLong(name) |
84 } |
94 } |
85 |
95 |
86 class Column_Double private[SQL](name: String, strict: Boolean) |
96 class Column_Double private[SQL](name: String, strict: Boolean, primary_key: Boolean) |
87 extends Column[Double](name, strict) |
97 extends Column[Double](name, strict, primary_key) |
88 { |
98 { |
89 def sql_type: String = "REAL" |
99 def sql_type: String = "REAL" |
90 def apply(rs: ResultSet): Double = rs.getDouble(name) |
100 def apply(rs: ResultSet): Double = rs.getDouble(name) |
91 } |
101 } |
92 |
102 |
93 class Column_String private[SQL](name: String, strict: Boolean) |
103 class Column_String private[SQL](name: String, strict: Boolean, primary_key: Boolean) |
94 extends Column[String](name, strict) |
104 extends Column[String](name, strict, primary_key) |
95 { |
105 { |
96 def sql_type: String = "TEXT" |
106 def sql_type: String = "TEXT" |
97 def apply(rs: ResultSet): String = |
107 def apply(rs: ResultSet): String = |
98 { |
108 { |
99 val s = rs.getString(name) |
109 val s = rs.getString(name) |
100 if (s == null) "" else s |
110 if (s == null) "" else s |
101 } |
111 } |
102 } |
112 } |
103 |
113 |
104 class Column_Bytes private[SQL](name: String, strict: Boolean) |
114 class Column_Bytes private[SQL](name: String, strict: Boolean, primary_key: Boolean) |
105 extends Column[Bytes](name, strict) |
115 extends Column[Bytes](name, strict, primary_key) |
106 { |
116 { |
107 def sql_type: String = "BLOB" |
117 def sql_type: String = "BLOB" |
108 def apply(rs: ResultSet): Bytes = |
118 def apply(rs: ResultSet): Bytes = |
109 { |
119 { |
110 val bs = rs.getBytes(name) |
120 val bs = rs.getBytes(name) |
113 } |
123 } |
114 |
124 |
115 |
125 |
116 /* tables */ |
126 /* tables */ |
117 |
127 |
118 sealed case class Table(name: String, columns: Column[Any]*) |
128 sealed case class Table(name: String, columns: List[Column[Any]]) |
119 { |
129 { |
|
130 Library.duplicates(columns.map(_.name)) match { |
|
131 case Nil => |
|
132 case bad => error("Duplicate column names " + commas_quote(bad) + " for table " + quote(name)) |
|
133 } |
|
134 |
|
135 columns.filter(_.primary_key) match { |
|
136 case bad if bad.length > 1 => |
|
137 error("Multiple primary keys " + commas_quote(bad.map(_.name)) + " for table " + quote(name)) |
|
138 case _ => |
|
139 } |
|
140 |
120 def sql_create(strict: Boolean, rowid: Boolean): String = |
141 def sql_create(strict: Boolean, rowid: Boolean): String = |
121 "CREATE TABLE " + (if (strict) "" else " IF NOT EXISTS ") + |
142 "CREATE TABLE " + (if (strict) "" else " IF NOT EXISTS ") + |
122 quote_ident(name) + " " + columns.map(_.sql_decl).mkString("(", ", ", ")") + |
143 quote_ident(name) + " " + columns.map(_.sql_decl).mkString("(", ", ", ")") + |
123 (if (rowid) "" else " WITHOUT ROWID") |
144 (if (rowid) "" else " WITHOUT ROWID") |
124 |
145 |