1 /**
2  * DStruct - Object-Relation Mapping for D programming language, with interface similar to Hibernate. 
3  * 
4  * Source file dstruct/dialects/sqlitedialect.d.
5  *
6  * This module contains implementation of SQLiteDialect class which provides implementation specific SQL syntax information.
7  * 
8  * Copyright: Copyright 2013
9  * License:   $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
10  * Author:   Vadim Lopatin
11  */
12 module dstruct.dialects.sqlitedialect;
13 
14 import std.conv;
15 
16 import dstruct.dialect;
17 import dstruct.metadata;
18 import dstruct.type;
19 import dstruct.ddbc.core;
20 
21 
22 string[] SQLITE_RESERVED_WORDS = 
23     [
24      "ABORT",
25      "ACTION",
26      "ADD",
27      "AFTER",
28      "ALL",
29      "ALTER",
30      "ANALYZE",
31      "AND",
32      "AS",
33      "ASC",
34      "ATTACH",
35      "AUTOINCREMENT",
36      "BEFORE",
37      "BEGIN",
38      "BETWEEN",
39      "BY",
40      "CASCADE",
41      "CASE",
42      "CAST",
43      "CHECK",
44      "COLLATE",
45      "COLUMN",
46      "COMMIT",
47      "CONFLICT",
48      "CONSTRAINT",
49      "CREATE",
50      "CROSS",
51      "CURRENT_DATE",
52      "CURRENT_TIME",
53      "CURRENT_TIMESTAMP",
54      "DATABASE",
55      "DEFAULT",
56      "DEFERRABLE",
57      "DEFERRED",
58      "DELETE",
59      "DESC",
60      "DETACH",
61      "DISTINCT",
62      "DROP",
63      "EACH",
64      "ELSE",
65      "END",
66      "ESCAPE",
67      "EXCEPT",
68      "EXCLUSIVE",
69      "EXISTS",
70      "EXPLAIN",
71      "FAIL",
72      "FOR",
73      "FOREIGN",
74      "FROM",
75      "FULL",
76      "GLOB",
77      "GROUP",
78      "HAVING",
79      "IF",
80      "IGNORE",
81      "IMMEDIATE",
82      "IN",
83      "INDEX",
84      "INDEXED",
85      "INITIALLY",
86      "INNER",
87      "INSERT",
88      "INSTEAD",
89      "INTERSECT",
90      "INTO",
91      "IS",
92      "ISNULL",
93      "JOIN",
94      "KEY",
95      "LEFT",
96      "LIKE",
97      "LIMIT",
98      "MATCH",
99      "NATURAL",
100      "NO",
101      "NOT",
102      "NOTNULL",
103      "NULL",
104      "OF",
105      "OFFSET",
106      "ON",
107      "OR",
108      "ORDER",
109      "OUTER",
110      "PLAN",
111      "PRAGMA",
112      "PRIMARY",
113      "QUERY",
114      "RAISE",
115      "REFERENCES",
116      "REGEXP",
117      "REINDEX",
118      "RELEASE",
119      "RENAME",
120      "REPLACE",
121      "RESTRICT",
122      "RIGHT",
123      "ROLLBACK",
124      "ROW",
125      "SAVEPOINT",
126      "SELECT",
127      "SET",
128      "TABLE",
129      "TEMP",
130      "TEMPORARY",
131      "THEN",
132      "TO",
133      "TRANSACTION",
134      "TRIGGER",
135      "UNION",
136      "UNIQUE",
137      "UPDATE",
138      "USING",
139      "VACUUM",
140      "VALUES",
141      "VIEW",
142      "VIRTUAL",
143      "WHEN",
144      "WHERE",
145      ];
146 
147 
148 class SQLiteDialect : Dialect {
149     ///The character specific to this dialect used to close a quoted identifier.
150     override char closeQuote() const { return '`'; }
151     ///The character specific to this dialect used to begin a quoted identifier.
152     override char  openQuote() const { return '`'; }
153     
154     // returns string like "BIGINT(20) NOT NULL" or "VARCHAR(255) NULL"
155     override string getColumnTypeDefinition(const PropertyInfo pi, const PropertyInfo overrideTypeFrom = null) {
156         immutable Type type = overrideTypeFrom !is null ? overrideTypeFrom.columnType : pi.columnType;
157         immutable SqlType sqlType = type.getSqlType();
158         bool fk = pi is null;
159         string nullablility = !fk && pi.nullable ? " NULL" : " NOT NULL";
160         string pk = !fk && pi.key ? " PRIMARY KEY" : "";
161         string autoinc = !fk && pi.generated ? " AUTO_INCREMENT" : "";
162         if (!fk && pi.generated)
163             return "INTEGER PRIMARY KEY";
164         string def = "";
165         int len = 0;
166         string unsigned = "";
167         if (cast(NumberType)type !is null) {
168             len = (cast(NumberType)type).length;
169             unsigned = (cast(NumberType)type).unsigned ? " UNSIGNED" : "";
170         }
171         if (cast(StringType)type !is null) {
172             len = (cast(StringType)type).length;
173         }
174         string modifiers = unsigned ~ nullablility ~ def ~ pk ~ autoinc;
175         string lenmodifiers = "(" ~ to!string(len > 0 ? len : 255) ~ ")" ~ modifiers;
176         switch (sqlType) {
177             case SqlType.BIGINT:
178             case SqlType.BIT:
179             case SqlType.BOOLEAN:
180             case SqlType.INTEGER:
181             case SqlType.NUMERIC:
182             case SqlType.SMALLINT:
183             case SqlType.TINYINT:
184                 return "INT" ~ modifiers;
185             case SqlType.FLOAT:
186             case SqlType.DOUBLE:
187             case SqlType.DECIMAL:
188                 return "REAL" ~ modifiers;
189             case SqlType.DATE:
190             case SqlType.DATETIME:
191             case SqlType.TIME:
192             case SqlType.CHAR:
193             case SqlType.CLOB:
194             case SqlType.LONGNVARCHAR:
195             case SqlType.LONGVARBINARY:
196             case SqlType.LONGVARCHAR:
197             case SqlType.NCHAR:
198             case SqlType.NCLOB:
199             case SqlType.VARBINARY:
200             case SqlType.VARCHAR:
201             case SqlType.NVARCHAR:
202                 return "TEXT" ~ modifiers;
203             case SqlType.BLOB:
204                 return "BLOB";
205             default:
206                 return "TEXT";
207         }
208     }
209     
210     override string getCheckTableExistsSQL(string tableName) {
211         return "SELECT name FROM sqlite_master WHERE type='table' AND name=" ~ quoteSqlString(tableName);
212     }
213 
214     override string getUniqueIndexItemSQL(string indexName, string[] columnNames) {
215         return "UNIQUE " ~ createFieldListSQL(columnNames);
216     }
217 
218 
219     this() {
220         addKeywords(SQLITE_RESERVED_WORDS);
221     }
222 }
223