first commit
This commit is contained in:
@@ -0,0 +1,723 @@
|
||||
/*
|
||||
* Copyright (C)2005-2016 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
import Reflect;
|
||||
import sys.db.Connection;
|
||||
import sys.db.RecordInfos;
|
||||
|
||||
/**
|
||||
Record Manager : the persistent object database manager. See the tutorial on
|
||||
Haxe website to learn how to use Record.
|
||||
**/
|
||||
#if !macro @:build(sys.db.RecordMacros.addRtti()) #end
|
||||
class Manager<T : Object> {
|
||||
|
||||
/* ----------------------------- STATICS ------------------------------ */
|
||||
public static var cnx(default, set) : Connection;
|
||||
public static var lockMode : String;
|
||||
|
||||
private static inline var cache_field = "__cache__";
|
||||
|
||||
private static var object_cache : haxe.ds.StringMap<Object> = new haxe.ds.StringMap();
|
||||
private static var init_list : List<Manager<Dynamic>> = new List();
|
||||
|
||||
private static var KEYWORDS = {
|
||||
var h = new haxe.ds.StringMap();
|
||||
for( k in "ADD|ALL|ALTER|ANALYZE|AND|AS|ASC|ASENSITIVE|BEFORE|BETWEEN|BIGINT|BINARY|BLOB|BOTH|BY|CALL|CASCADE|CASE|CHANGE|CHAR|CHARACTER|CHECK|COLLATE|COLUMN|CONDITION|CONSTRAINT|CONTINUE|CONVERT|CREATE|CROSS|CURRENT_DATE|CURRENT_TIME|CURRENT_TIMESTAMP|CURRENT_USER|CURSOR|DATABASE|DATABASES|DAY_HOUR|DAY_MICROSECOND|DAY_MINUTE|DAY_SECOND|DEC|DECIMAL|DECLARE|DEFAULT|DELAYED|DELETE|DESC|DESCRIBE|DETERMINISTIC|DISTINCT|DISTINCTROW|DIV|DOUBLE|DROP|DUAL|EACH|ELSE|ELSEIF|ENCLOSED|ESCAPED|EXISTS|EXIT|EXPLAIN|FALSE|FETCH|FLOAT|FLOAT4|FLOAT8|FOR|FORCE|FOREIGN|FROM|FULLTEXT|GRANT|GROUP|HAVING|HIGH_PRIORITY|HOUR_MICROSECOND|HOUR_MINUTE|HOUR_SECOND|IF|IGNORE|IN|INDEX|INFILE|INNER|INOUT|INSENSITIVE|INSERT|INT|INT1|INT2|INT3|INT4|INT8|INTEGER|INTERVAL|INTO|IS|ITERATE|JOIN|KEY|KEYS|KILL|LEADING|LEAVE|LEFT|LIKE|LIMIT|LINES|LOAD|LOCALTIME|LOCALTIMESTAMP|LOCK|LONG|LONGBLOB|LONGTEXT|LOOP|LOW_PRIORITY|MATCH|MEDIUMBLOB|MEDIUMINT|MEDIUMTEXT|MIDDLEINT|MINUTE_MICROSECOND|MINUTE_SECOND|MOD|MODIFIES|NATURAL|NOT|NO_WRITE_TO_BINLOG|NULL|NUMERIC|ON|OPTIMIZE|OPTION|OPTIONALLY|OR|ORDER|OUT|OUTER|OUTFILE|PRECISION|PRIMARY|PROCEDURE|PURGE|READ|READS|REAL|REFERENCES|REGEXP|RELEASE|RENAME|REPEAT|REPLACE|REQUIRE|RESTRICT|RETURN|REVOKE|RIGHT|RLIKE|SCHEMA|SCHEMAS|SECOND_MICROSECOND|SELECT|SENSITIVE|SEPARATOR|SET|SHOW|SMALLINT|SONAME|SPATIAL|SPECIFIC|SQL|SQLEXCEPTION|SQLSTATE|SQLWARNING|SQL_BIG_RESULT|SQL_CALC_FOUND_ROWS|SQL_SMALL_RESULT|SSL|STARTING|STRAIGHT_JOIN|TABLE|TERMINATED|THEN|TINYBLOB|TINYINT|TINYTEXT|TO|TRAILING|TRIGGER|TRUE|UNDO|UNION|UNIQUE|UNLOCK|UNSIGNED|UPDATE|USAGE|USE|USING|UTC_DATE|UTC_TIME|UTC_TIMESTAMP|VALUES|VARBINARY|VARCHAR|VARCHARACTER|VARYING|WHEN|WHERE|WHILE|WITH|WRITE|XOR|YEAR_MONTH|ZEROFILL|ASENSITIVE|CALL|CONDITION|CONNECTION|CONTINUE|CURSOR|DECLARE|DETERMINISTIC|EACH|ELSEIF|EXIT|FETCH|GOTO|INOUT|INSENSITIVE|ITERATE|LABEL|LEAVE|LOOP|MODIFIES|OUT|READS|RELEASE|REPEAT|RETURN|SCHEMA|SCHEMAS|SENSITIVE|SPECIFIC|SQL|SQLEXCEPTION|SQLSTATE|SQLWARNING|TRIGGER|UNDO|UPGRADE|WHILE".split("|") )
|
||||
h.set(k.toLowerCase(),true);
|
||||
h;
|
||||
}
|
||||
|
||||
private static function set_cnx( c : Connection ) {
|
||||
cnx = c;
|
||||
lockMode = (c != null && c.dbName() == "MySQL") ? " FOR UPDATE" : "";
|
||||
return c;
|
||||
}
|
||||
|
||||
/* ---------------------------- BASIC API ----------------------------- */
|
||||
|
||||
var table_infos : RecordInfos;
|
||||
var table_name : String;
|
||||
var table_keys : Array<String>;
|
||||
var class_proto : { prototype : Dynamic };
|
||||
|
||||
public function new( classval : Class<T> ) {
|
||||
var m : Array<Dynamic> = haxe.rtti.Meta.getType(classval).rtti;
|
||||
if( m == null ) throw "Missing @rtti for class " + Type.getClassName(classval);
|
||||
table_infos = haxe.Unserializer.run(m[0]);
|
||||
table_name = quoteField(table_infos.name);
|
||||
table_keys = table_infos.key;
|
||||
// set the manager and ready for further init
|
||||
class_proto = cast classval;
|
||||
#if neko
|
||||
class_proto.prototype._manager = this;
|
||||
init_list.add(this);
|
||||
#end
|
||||
}
|
||||
|
||||
public function all( ?lock: Bool ) : List<T> {
|
||||
return unsafeObjects("SELECT * FROM " + table_name,lock);
|
||||
}
|
||||
|
||||
public macro function get(ethis,id,?lock:haxe.macro.Expr.ExprOf<Bool>) : #if macro haxe.macro.Expr #else haxe.macro.Expr.ExprOf<T> #end {
|
||||
return RecordMacros.macroGet(ethis,id,lock);
|
||||
}
|
||||
|
||||
public macro function select(ethis, cond, ?options, ?lock:haxe.macro.Expr.ExprOf<Bool>) : #if macro haxe.macro.Expr #else haxe.macro.Expr.ExprOf<T> #end {
|
||||
return RecordMacros.macroSearch(ethis, cond, options, lock, true);
|
||||
}
|
||||
|
||||
public macro function search(ethis, cond, ?options, ?lock:haxe.macro.Expr.ExprOf<Bool>) : #if macro haxe.macro.Expr #else haxe.macro.Expr.ExprOf<List<T>> #end {
|
||||
return RecordMacros.macroSearch(ethis, cond, options, lock);
|
||||
}
|
||||
|
||||
public macro function count(ethis, cond) : #if macro haxe.macro.Expr #else haxe.macro.Expr.ExprOf<Int> #end {
|
||||
return RecordMacros.macroCount(ethis, cond);
|
||||
}
|
||||
|
||||
public macro function delete(ethis, cond, ?options) : #if macro haxe.macro.Expr #else haxe.macro.Expr.ExprOf<Void> #end {
|
||||
return RecordMacros.macroDelete(ethis, cond, options);
|
||||
}
|
||||
|
||||
public function dynamicSearch( x : {}, ?lock : Bool ) : List<T> {
|
||||
var s = new StringBuf();
|
||||
s.add("SELECT * FROM ");
|
||||
s.add(table_name);
|
||||
s.add(" WHERE ");
|
||||
addCondition(s,x);
|
||||
return unsafeObjects(s.toString(),lock);
|
||||
}
|
||||
|
||||
function quote( s : String ) : String {
|
||||
return getCnx().quote( s );
|
||||
}
|
||||
|
||||
/* -------------------------- RECORDOBJECT API -------------------------- */
|
||||
|
||||
function doUpdateCache( x : T, name : String, v : Dynamic ) {
|
||||
var cache : { v : Dynamic } = Reflect.field(x, "cache_" + name);
|
||||
// if the cache has not been fetched (for instance if the field was set by reflection)
|
||||
// then we directly use the new value
|
||||
if( cache == null )
|
||||
return v;
|
||||
var v = doSerialize(name, cache.v);
|
||||
// don't set it since the value might change again later
|
||||
// Reflect.setField(x, name, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
static function getFieldName(field:RecordField):String
|
||||
{
|
||||
return switch (field.t) {
|
||||
case DData | DEnum(_):
|
||||
"data_" + field.name;
|
||||
case _:
|
||||
field.name;
|
||||
}
|
||||
}
|
||||
|
||||
function doInsert( x : T ) {
|
||||
unmake(x);
|
||||
var s = new StringBuf();
|
||||
var fields = new List();
|
||||
var values = new List();
|
||||
var cache = Reflect.field(x,cache_field);
|
||||
if (cache == null)
|
||||
{
|
||||
Reflect.setField(x,cache_field,cache = {});
|
||||
}
|
||||
|
||||
for( f in table_infos.fields ) {
|
||||
var name = f.name,
|
||||
fieldName = getFieldName(f);
|
||||
var v:Dynamic = Reflect.field(x,fieldName);
|
||||
if( v != null ) {
|
||||
fields.add(quoteField(name));
|
||||
switch( f.t ) {
|
||||
case DData: v = doUpdateCache(x, name, v);
|
||||
default:
|
||||
}
|
||||
values.add(v);
|
||||
} else if( !f.isNull ) {
|
||||
// if the field is not defined, give it a default value on insert
|
||||
switch( f.t ) {
|
||||
case DUInt, DTinyInt, DInt, DSingle, DFloat, DFlags(_), DBigInt, DTinyUInt, DSmallInt, DSmallUInt, DMediumInt, DMediumUInt, DEnum(_):
|
||||
Reflect.setField(x, fieldName, 0);
|
||||
case DBool:
|
||||
Reflect.setField(x, fieldName, false);
|
||||
case DTinyText, DText, DString(_), DSmallText, DSerialized:
|
||||
Reflect.setField(x, fieldName, "");
|
||||
case DSmallBinary, DNekoSerialized, DLongBinary, DBytes(_), DBinary:
|
||||
Reflect.setField(x, fieldName, haxe.io.Bytes.alloc(0));
|
||||
case DDate, DDateTime, DTimeStamp:
|
||||
// default date might depend on database
|
||||
case DId, DUId, DBigId, DNull, DInterval, DEncoded, DData:
|
||||
// no default value for these
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.setField(cache, name, v);
|
||||
}
|
||||
s.add("INSERT INTO ");
|
||||
s.add(table_name);
|
||||
if (fields.length > 0 || cnx.dbName() != "SQLite")
|
||||
{
|
||||
s.add(" (");
|
||||
s.add(fields.join(","));
|
||||
s.add(") VALUES (");
|
||||
var first = true;
|
||||
for( v in values ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
s.add(", ");
|
||||
getCnx().addValue(s,v);
|
||||
}
|
||||
s.add(")");
|
||||
} else {
|
||||
s.add(" DEFAULT VALUES");
|
||||
}
|
||||
unsafeExecute(s.toString());
|
||||
untyped x._lock = true;
|
||||
// table with one key not defined : suppose autoincrement
|
||||
if( table_keys.length == 1 && Reflect.field(x,table_keys[0]) == null )
|
||||
Reflect.setField(x,table_keys[0],getCnx().lastInsertId());
|
||||
addToCache(x);
|
||||
}
|
||||
|
||||
inline function isBinary( t : RecordInfos.RecordType ) {
|
||||
return switch( t ) {
|
||||
case DSmallBinary, DNekoSerialized, DLongBinary, DBytes(_), DBinary: true;
|
||||
//case DData: true // -- disabled for implementation purposes
|
||||
default: false;
|
||||
};
|
||||
}
|
||||
|
||||
inline function hasBinaryChanged( a : haxe.io.Bytes, b : haxe.io.Bytes ) {
|
||||
return a != b && (a == null || b == null || a.compare(b) != 0);
|
||||
}
|
||||
|
||||
function doUpdate( x : T ) {
|
||||
if( untyped !x._lock )
|
||||
throw "Cannot update a not locked object";
|
||||
var upd = getUpdateStatement(x);
|
||||
if (upd == null) return;
|
||||
unsafeExecute(upd);
|
||||
}
|
||||
|
||||
function getUpdateStatement( x : T ):Null<String>
|
||||
{
|
||||
unmake(x);
|
||||
var s = new StringBuf();
|
||||
s.add("UPDATE ");
|
||||
s.add(table_name);
|
||||
s.add(" SET ");
|
||||
var cache = Reflect.field(x,cache_field);
|
||||
var mod = false;
|
||||
for( f in table_infos.fields ) {
|
||||
if (table_keys.indexOf(f.name) >= 0)
|
||||
continue;
|
||||
var name = f.name,
|
||||
fieldName = getFieldName(f);
|
||||
var v : Dynamic = Reflect.field(x,fieldName);
|
||||
var vc : Dynamic = Reflect.field(cache,name);
|
||||
if( cache == null || v != vc ) {
|
||||
switch( f.t ) {
|
||||
case DSmallBinary, DNekoSerialized, DLongBinary, DBytes(_), DBinary:
|
||||
if ( !hasBinaryChanged(v,vc) )
|
||||
continue;
|
||||
case DData:
|
||||
v = doUpdateCache(x, name, v);
|
||||
if( !hasBinaryChanged(v,vc) )
|
||||
continue;
|
||||
default:
|
||||
}
|
||||
if( mod )
|
||||
s.add(", ");
|
||||
else
|
||||
mod = true;
|
||||
s.add(quoteField(name));
|
||||
s.add(" = ");
|
||||
getCnx().addValue(s,v);
|
||||
if ( cache != null )
|
||||
Reflect.setField(cache,name,v);
|
||||
}
|
||||
}
|
||||
if( !mod )
|
||||
return null;
|
||||
s.add(" WHERE ");
|
||||
addKeys(s,x);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
function doDelete( x : T ) {
|
||||
var s = new StringBuf();
|
||||
s.add("DELETE FROM ");
|
||||
s.add(table_name);
|
||||
s.add(" WHERE ");
|
||||
addKeys(s,x);
|
||||
unsafeExecute(s.toString());
|
||||
removeFromCache(x);
|
||||
}
|
||||
|
||||
function doLock( i : T ) {
|
||||
if( untyped i._lock )
|
||||
return;
|
||||
var s = new StringBuf();
|
||||
s.add("SELECT * FROM ");
|
||||
s.add(table_name);
|
||||
s.add(" WHERE ");
|
||||
addKeys(s, i);
|
||||
// will force sync
|
||||
if( unsafeObject(s.toString(),true) != i )
|
||||
throw "Could not lock object (was deleted ?); try restarting transaction";
|
||||
}
|
||||
|
||||
function objectToString( it : T ) : String {
|
||||
var s = new StringBuf();
|
||||
s.add(table_name);
|
||||
if( table_keys.length == 1 ) {
|
||||
s.add("#");
|
||||
s.add(Reflect.field(it,table_keys[0]));
|
||||
} else {
|
||||
s.add("(");
|
||||
var first = true;
|
||||
for( f in table_keys ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
s.add(",");
|
||||
s.add(quoteField(f));
|
||||
s.add(":");
|
||||
s.add(Reflect.field(it,f));
|
||||
}
|
||||
s.add(")");
|
||||
}
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
function doSerialize( field : String, v : Dynamic ) : haxe.io.Bytes {
|
||||
var s = new haxe.Serializer();
|
||||
s.useEnumIndex = true;
|
||||
s.serialize(v);
|
||||
var str = s.toString();
|
||||
#if neko
|
||||
return neko.Lib.bytesReference(str);
|
||||
#else
|
||||
return haxe.io.Bytes.ofString(str);
|
||||
#end
|
||||
}
|
||||
|
||||
function doUnserialize( field : String, b : haxe.io.Bytes ) : Dynamic {
|
||||
if( b == null )
|
||||
return null;
|
||||
var str;
|
||||
#if neko
|
||||
str = neko.Lib.stringReference(b);
|
||||
#else
|
||||
str = b.toString();
|
||||
#end
|
||||
if( str == "" )
|
||||
return null;
|
||||
return haxe.Unserializer.run(str);
|
||||
}
|
||||
|
||||
/* ---------------------------- INTERNAL API -------------------------- */
|
||||
|
||||
function normalizeCache(x:CacheType<T>)
|
||||
{
|
||||
for (f in Reflect.fields(x) )
|
||||
{
|
||||
var val:Dynamic = Reflect.field(x,f), info = table_infos.hfields.get(f);
|
||||
if (info != null)
|
||||
{
|
||||
if (val != null) switch (info.t) {
|
||||
case DDate, DDateTime if (!Std.is(val,Date)):
|
||||
if (Std.is(val,Float))
|
||||
{
|
||||
val = Date.fromTime(val);
|
||||
} else {
|
||||
var v = val + "";
|
||||
var index = v.indexOf('.');
|
||||
if (index >= 0)
|
||||
v = v.substr(0,index);
|
||||
val = Date.fromString(v);
|
||||
}
|
||||
case DSmallBinary, DLongBinary, DBinary, DBytes(_), DData if (Std.is(val, String)):
|
||||
val = haxe.io.Bytes.ofString(val);
|
||||
case DString(_) | DTinyText | DSmallText | DText if(!Std.is(val,String)):
|
||||
val = val + "";
|
||||
#if (cs && erase_generics)
|
||||
// on C#, SQLite Ints are returned as Int64
|
||||
case DInt if (!Std.is(val,Int)):
|
||||
val = cast(val,Int);
|
||||
#end
|
||||
case DBool if (!Std.is(val,Bool)):
|
||||
if (Std.is(val,Int))
|
||||
val = val != 0;
|
||||
else if (Std.is(val, String)) switch (val.toLowerCase()) {
|
||||
case "1", "true": val = true;
|
||||
case "0", "false": val = false;
|
||||
}
|
||||
case DFloat if (Std.is(val,String)):
|
||||
val = Std.parseFloat(val);
|
||||
case _:
|
||||
}
|
||||
Reflect.setField(x, f, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cacheObject( x : T, lock : Bool ) {
|
||||
#if neko
|
||||
var o = untyped __dollar__new(x);
|
||||
untyped __dollar__objsetproto(o, class_proto.prototype);
|
||||
#else
|
||||
var o : T = Type.createEmptyInstance(cast class_proto);
|
||||
untyped o._manager = this;
|
||||
#end
|
||||
normalizeCache(x);
|
||||
for (f in Reflect.fields(x) )
|
||||
{
|
||||
var val:Dynamic = Reflect.field(x,f), info = table_infos.hfields.get(f);
|
||||
if (info != null)
|
||||
{
|
||||
var fieldName = getFieldName(info);
|
||||
Reflect.setField(o, fieldName, val);
|
||||
}
|
||||
}
|
||||
Reflect.setField(o,cache_field,x);
|
||||
addToCache(o);
|
||||
untyped o._lock = lock;
|
||||
return o;
|
||||
}
|
||||
|
||||
function make( x : T ) {
|
||||
}
|
||||
|
||||
function unmake( x : T ) {
|
||||
}
|
||||
|
||||
function quoteField(f : String) {
|
||||
return KEYWORDS.exists(f.toLowerCase()) ? "`"+f+"`" : f;
|
||||
}
|
||||
|
||||
function addKeys( s : StringBuf, x : {} ) {
|
||||
var first = true;
|
||||
for( k in table_keys ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
s.add(" AND ");
|
||||
s.add(quoteField(k));
|
||||
s.add(" = ");
|
||||
var f = Reflect.field(x,k);
|
||||
if( f == null )
|
||||
throw ("Missing key "+k);
|
||||
getCnx().addValue(s,f);
|
||||
}
|
||||
}
|
||||
|
||||
function unsafeExecute( sql : String ) {
|
||||
return getCnx().request(sql);
|
||||
}
|
||||
|
||||
public function unsafeObject( sql : String, lock : Bool ) : T {
|
||||
if( lock != false ) {
|
||||
lock = true;
|
||||
sql += getLockMode();
|
||||
}
|
||||
var r = unsafeExecute(sql);
|
||||
var r = r.hasNext() ? r.next() : null;
|
||||
if( r == null )
|
||||
return null;
|
||||
normalizeCache(r);
|
||||
var c = getFromCache(r,lock);
|
||||
if( c != null )
|
||||
return c;
|
||||
r = cacheObject(r,lock);
|
||||
make(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public function unsafeObjects( sql : String, lock : Bool ) : List<T> {
|
||||
if( lock != false ) {
|
||||
lock = true;
|
||||
sql += getLockMode();
|
||||
}
|
||||
var l = unsafeExecute(sql).results();
|
||||
var l2 = new List<T>();
|
||||
for( x in l ) {
|
||||
normalizeCache(x);
|
||||
var c = getFromCache(x,lock);
|
||||
if( c != null )
|
||||
l2.add(c);
|
||||
else {
|
||||
x = cacheObject(x,lock);
|
||||
make(x);
|
||||
l2.add(x);
|
||||
}
|
||||
}
|
||||
return l2;
|
||||
}
|
||||
|
||||
public function unsafeCount( sql : String ) {
|
||||
return unsafeExecute(sql).getIntResult(0);
|
||||
}
|
||||
|
||||
public function unsafeDelete( sql : String ) {
|
||||
unsafeExecute(sql);
|
||||
}
|
||||
|
||||
public function unsafeGet( id : Dynamic, ?lock : Bool ) : T {
|
||||
if( lock == null ) lock = true;
|
||||
if( table_keys.length != 1 )
|
||||
throw "Invalid number of keys";
|
||||
if( id == null )
|
||||
return null;
|
||||
var x : Dynamic = getFromCacheKey(Std.string(id) + table_name);
|
||||
if( x != null && (!lock || x._lock) )
|
||||
return x;
|
||||
var s = new StringBuf();
|
||||
s.add("SELECT * FROM ");
|
||||
s.add(table_name);
|
||||
s.add(" WHERE ");
|
||||
s.add(quoteField(table_keys[0]));
|
||||
s.add(" = ");
|
||||
getCnx().addValue(s,id);
|
||||
return unsafeObject(s.toString(), lock);
|
||||
}
|
||||
|
||||
public function unsafeGetWithKeys( keys : { }, ?lock : Bool ) : T {
|
||||
if( lock == null ) lock = true;
|
||||
var x : Dynamic = getFromCacheKey(makeCacheKey(cast keys));
|
||||
if( x != null && (!lock || x._lock) )
|
||||
return x;
|
||||
var s = new StringBuf();
|
||||
s.add("SELECT * FROM ");
|
||||
s.add(table_name);
|
||||
s.add(" WHERE ");
|
||||
addKeys(s,keys);
|
||||
return unsafeObject(s.toString(),lock);
|
||||
}
|
||||
|
||||
public function unsafeGetId( o : T ) : Dynamic {
|
||||
return o == null ? null : Reflect.field(o, table_keys[0]);
|
||||
}
|
||||
|
||||
public static function nullCompare( a : String, b : String, eq : Bool ) {
|
||||
if (a == null || a == 'NULL') {
|
||||
return eq ? '$b IS NULL' : '$b IS NOT NULL';
|
||||
} else if (b == null || b == 'NULL') {
|
||||
return eq ? '$a IS NULL' : '$a IS NOT NULL';
|
||||
}
|
||||
// we can't use a null-safe operator here
|
||||
if( cnx.dbName() != "MySQL" )
|
||||
return a + (eq ? " = " : " != ") + b;
|
||||
var sql = a+" <=> "+b;
|
||||
if( !eq ) sql = "NOT("+sql+")";
|
||||
return sql;
|
||||
}
|
||||
|
||||
function addCondition(s : StringBuf,x) {
|
||||
var first = true;
|
||||
if( x != null )
|
||||
for( f in Reflect.fields(x) ) {
|
||||
if( first )
|
||||
first = false;
|
||||
else
|
||||
s.add(" AND ");
|
||||
s.add(quoteField(f));
|
||||
var d = Reflect.field(x,f);
|
||||
if( d == null )
|
||||
s.add(" IS NULL");
|
||||
else {
|
||||
s.add(" = ");
|
||||
getCnx().addValue(s,d);
|
||||
}
|
||||
}
|
||||
if( first )
|
||||
s.add("TRUE");
|
||||
}
|
||||
|
||||
/* --------------------------- MISC API ------------------------------ */
|
||||
|
||||
public function dbClass() : Class<Dynamic> {
|
||||
return cast class_proto;
|
||||
}
|
||||
|
||||
public function dbInfos() {
|
||||
return table_infos;
|
||||
}
|
||||
|
||||
function getCnx() {
|
||||
return cnx;
|
||||
}
|
||||
|
||||
function getLockMode() {
|
||||
return lockMode;
|
||||
}
|
||||
|
||||
/**
|
||||
Remove the cached value for the given Object field : this will ensure
|
||||
that the value is updated when calling .update(). This is necessary if
|
||||
you are modifying binary data in-place since the cache will be modified
|
||||
as well.
|
||||
**/
|
||||
public function forceUpdate( o : T, field : String ) {
|
||||
// set a reference that will ensure != and .compare() != 0
|
||||
Reflect.setField(Reflect.field(o,cache_field),field,null);
|
||||
}
|
||||
|
||||
/* --------------------------- INIT / CLEANUP ------------------------- */
|
||||
|
||||
public static function initialize() {
|
||||
var l = init_list;
|
||||
init_list = new List();
|
||||
for( m in l )
|
||||
for( r in m.table_infos.relations )
|
||||
m.initRelation(r);
|
||||
}
|
||||
|
||||
public static function cleanup() {
|
||||
object_cache = new haxe.ds.StringMap();
|
||||
}
|
||||
|
||||
function initRelation( r : RecordInfos.RecordRelation ) {
|
||||
// setup getter/setter
|
||||
var spod : Dynamic = Type.resolveClass(r.type);
|
||||
if( spod == null ) throw "Missing spod type " + r.type;
|
||||
var manager : Manager<Dynamic> = spod.manager;
|
||||
var hprop = "__"+r.prop;
|
||||
var hkey = r.key;
|
||||
var lock = r.lock;
|
||||
if( manager == null || manager.table_keys == null ) throw ("Invalid manager for relation "+table_name+":"+r.prop);
|
||||
if( manager.table_keys.length != 1 ) throw ("Relation " + r.prop + "(" + r.key + ") on a multiple key table");
|
||||
}
|
||||
|
||||
function __get( x : Dynamic, prop : String, key : String, lock ) {
|
||||
var v = Reflect.field(x,prop);
|
||||
if( v != null )
|
||||
return v;
|
||||
var y = unsafeGet(Reflect.field(x, key), lock);
|
||||
Reflect.setField(x,prop,v);
|
||||
return y;
|
||||
}
|
||||
|
||||
function __set( x : Dynamic, prop : String, key : String, v : T ) {
|
||||
Reflect.setField(x,prop,v);
|
||||
if( v == null )
|
||||
Reflect.setField(x,key,null);
|
||||
else
|
||||
Reflect.setField(x,key,Reflect.field(v,table_keys[0]));
|
||||
return v;
|
||||
}
|
||||
|
||||
/* ---------------------------- OBJECT CACHE -------------------------- */
|
||||
|
||||
function makeCacheKey( x : T ) : String {
|
||||
if( table_keys.length == 1 ) {
|
||||
var k = Reflect.field(x,table_keys[0]);
|
||||
if( k == null )
|
||||
throw("Missing key "+table_keys[0]);
|
||||
return Std.string(k)+table_name;
|
||||
}
|
||||
var s = new StringBuf();
|
||||
for( k in table_keys ) {
|
||||
var v = Reflect.field(x,k);
|
||||
if( k == null )
|
||||
throw("Missing key "+k);
|
||||
s.add(v);
|
||||
s.add("#");
|
||||
}
|
||||
s.add(table_name);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
function addToCache( x : CacheType<T> ) {
|
||||
object_cache.set(makeCacheKey(x),x);
|
||||
}
|
||||
|
||||
function removeFromCache( x : CacheType<T> ) {
|
||||
object_cache.remove(makeCacheKey(x));
|
||||
}
|
||||
|
||||
function getFromCacheKey( key : String ) : T {
|
||||
return cast object_cache.get(key);
|
||||
}
|
||||
|
||||
function getFromCache( x : CacheType<T>, lock : Bool ) : T {
|
||||
var c : Dynamic = object_cache.get(makeCacheKey(x));
|
||||
if( c != null && lock && !c._lock ) {
|
||||
// synchronize the fields since our result is up-to-date !
|
||||
for( f in Reflect.fields(c) )
|
||||
Reflect.deleteField(c,f);
|
||||
for (f in table_infos.fields)
|
||||
{
|
||||
var name = f.name,
|
||||
fieldName = getFieldName(f);
|
||||
Reflect.setField(c,fieldName,Reflect.field(x,name));
|
||||
}
|
||||
// mark as locked
|
||||
c._lock = true;
|
||||
// restore our manager
|
||||
#if !neko
|
||||
untyped c._manager = this;
|
||||
#end
|
||||
// use the new object as our cache of fields
|
||||
Reflect.setField(c,cache_field,x);
|
||||
// remake object
|
||||
make(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
/* ---------------------------- QUOTES -------------------------- */
|
||||
|
||||
public static function quoteAny( v : Dynamic ) {
|
||||
if (v == null) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
var s = new StringBuf();
|
||||
cnx.addValue(s, v);
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public static function quoteList( v : String, it : Iterable<Dynamic> ) {
|
||||
var b = new StringBuf();
|
||||
var first = true;
|
||||
if( it != null )
|
||||
for( v in it ) {
|
||||
if( first ) first = false else b.addChar(','.code);
|
||||
cnx.addValue(b, v);
|
||||
}
|
||||
if( first )
|
||||
return "FALSE";
|
||||
return v + " IN (" + b.toString() + ")";
|
||||
}
|
||||
|
||||
// We need Bytes.toString to not be DCE'd. See #1937
|
||||
@:keep static function __depends() { return haxe.io.Bytes.alloc(0).toString(); }
|
||||
}
|
||||
|
||||
private typedef CacheType<T> = Dynamic;
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C)2005-2016 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
|
||||
/**
|
||||
Record Object : the persistent object base type. See the tutorial on Haxe
|
||||
website to learn how to use Record.
|
||||
**/
|
||||
@:keepSub
|
||||
@:autoBuild(sys.db.RecordMacros.macroBuild()) @:skipFields
|
||||
class Object {
|
||||
|
||||
var _lock(default,never) : Bool;
|
||||
var _manager(default,never) : sys.db.Manager<Dynamic>;
|
||||
#if !neko
|
||||
@:keep var __cache__:Dynamic;
|
||||
#end
|
||||
|
||||
public function new() {
|
||||
#if !neko
|
||||
if( _manager == null ) untyped _manager = __getManager();
|
||||
#end
|
||||
}
|
||||
|
||||
#if !neko
|
||||
private function __getManager():sys.db.Manager<Dynamic>
|
||||
{
|
||||
var cls:Dynamic = Type.getClass(this);
|
||||
return cls.manager;
|
||||
}
|
||||
#end
|
||||
|
||||
public function insert() {
|
||||
untyped _manager.doInsert(this);
|
||||
}
|
||||
|
||||
public function update() {
|
||||
untyped _manager.doUpdate(this);
|
||||
}
|
||||
|
||||
public function lock() {
|
||||
untyped _manager.doLock(this);
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
untyped _manager.doDelete(this);
|
||||
}
|
||||
|
||||
public function isLocked() {
|
||||
return _lock;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return untyped _manager.objectToString(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C)2005-2016 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
|
||||
enum RecordType {
|
||||
DId;
|
||||
DInt;
|
||||
DUId;
|
||||
DUInt;
|
||||
DBigId;
|
||||
DBigInt;
|
||||
DSingle;
|
||||
DFloat;
|
||||
DBool;
|
||||
DString( n : Int );
|
||||
DDate;
|
||||
DDateTime;
|
||||
DTimeStamp;
|
||||
DTinyText;
|
||||
DSmallText;
|
||||
DText;
|
||||
DSmallBinary;
|
||||
DLongBinary;
|
||||
DBinary;
|
||||
DBytes( n : Int );
|
||||
DEncoded;
|
||||
DSerialized;
|
||||
DNekoSerialized;
|
||||
DFlags( flags : Array<String>, autoSize : Bool );
|
||||
DTinyInt;
|
||||
DTinyUInt;
|
||||
DSmallInt;
|
||||
DSmallUInt;
|
||||
DMediumInt;
|
||||
DMediumUInt;
|
||||
DData;
|
||||
DEnum( name : String );
|
||||
// specific for intermediate calculus
|
||||
DInterval;
|
||||
DNull;
|
||||
}
|
||||
|
||||
typedef RecordField = {
|
||||
var name : String;
|
||||
var t : RecordType;
|
||||
var isNull : Bool;
|
||||
}
|
||||
|
||||
typedef RecordRelation = {
|
||||
var prop : String;
|
||||
var key : String;
|
||||
var type : String;
|
||||
var module : String;
|
||||
var cascade : Bool;
|
||||
var lock : Bool;
|
||||
var isNull : Bool;
|
||||
}
|
||||
|
||||
typedef RecordInfos = {
|
||||
var name : String;
|
||||
var key : Array<String>;
|
||||
var fields : Array<RecordField>;
|
||||
var hfields : Map<String,RecordField>;
|
||||
var relations : Array<RecordRelation>;
|
||||
var indexes : Array<{ keys : Array<String>, unique : Bool }>;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C)2005-2016 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
import sys.db.RecordInfos;
|
||||
|
||||
class TableCreate {
|
||||
|
||||
static function autoInc( dbName ) {
|
||||
// on SQLite, autoincrement is necessary to be primary key as well
|
||||
return dbName == "SQLite" ? "PRIMARY KEY AUTOINCREMENT" : "AUTO_INCREMENT";
|
||||
}
|
||||
|
||||
public static function getTypeSQL( t : RecordType, dbName : String ) {
|
||||
return switch( t ) {
|
||||
case DId: "INTEGER "+autoInc(dbName);
|
||||
case DUId: "INTEGER UNSIGNED "+autoInc(dbName);
|
||||
case DInt, DEncoded: "INTEGER";
|
||||
case DUInt: "INTEGER UNSIGNED";
|
||||
case DTinyInt: "TINYINT";
|
||||
case DTinyUInt, DEnum(_): "TINYINT UNSIGNED";
|
||||
case DSmallInt: "SMALLINT";
|
||||
case DSmallUInt: "SMALLINT UNSIGNED";
|
||||
case DMediumInt: "MEDIUMINT";
|
||||
case DMediumUInt: "MEDIUMINT UNSIGNED";
|
||||
case DSingle: "FLOAT";
|
||||
case DFloat: "DOUBLE";
|
||||
case DBool: "TINYINT(1)";
|
||||
case DString(n): "VARCHAR("+n+")";
|
||||
case DDate: "DATE";
|
||||
case DDateTime: "DATETIME";
|
||||
case DTimeStamp: "TIMESTAMP DEFAULT 0";
|
||||
case DTinyText: "TINYTEXT";
|
||||
case DSmallText: "TEXT";
|
||||
case DText, DSerialized: "MEDIUMTEXT";
|
||||
case DSmallBinary: "BLOB";
|
||||
case DBinary, DNekoSerialized, DData: "MEDIUMBLOB";
|
||||
case DLongBinary: "LONGBLOB";
|
||||
case DBigInt: "BIGINT";
|
||||
case DBigId: "BIGINT "+autoInc(dbName);
|
||||
case DBytes(n): "BINARY(" + n + ")";
|
||||
case DFlags(fl, auto): getTypeSQL(auto ? (fl.length <= 8 ? DTinyUInt : (fl.length <= 16 ? DSmallUInt : (fl.length <= 24 ? DMediumUInt : DInt))) : DInt, dbName);
|
||||
case DNull, DInterval: throw "assert";
|
||||
};
|
||||
}
|
||||
|
||||
public static function create( manager : sys.db.Manager<Dynamic>, ?engine ) {
|
||||
function quote(v:String):String {
|
||||
return untyped manager.quoteField(v);
|
||||
}
|
||||
var cnx : Connection = untyped manager.getCnx();
|
||||
if( cnx == null )
|
||||
throw "SQL Connection not initialized on Manager";
|
||||
var dbName = cnx.dbName();
|
||||
var infos = manager.dbInfos();
|
||||
var sql = "CREATE TABLE " + quote(infos.name) + " (";
|
||||
var decls = [];
|
||||
var hasID = false;
|
||||
for( f in infos.fields ) {
|
||||
switch( f.t ) {
|
||||
case DId:
|
||||
hasID = true;
|
||||
case DUId, DBigId:
|
||||
hasID = true;
|
||||
if( dbName == "SQLite" )
|
||||
throw "S" + Std.string(f.t).substr(1)+" is not supported by " + dbName + " : use SId instead";
|
||||
default:
|
||||
}
|
||||
decls.push(quote(f.name)+" "+getTypeSQL(f.t,dbName)+(f.isNull ? "" : " NOT NULL"));
|
||||
}
|
||||
if( dbName != "SQLite" || !hasID )
|
||||
decls.push("PRIMARY KEY ("+Lambda.map(infos.key,quote).join(",")+")");
|
||||
sql += decls.join(",");
|
||||
sql += ")";
|
||||
if( engine != null )
|
||||
sql += "ENGINE="+engine;
|
||||
cnx.request(sql);
|
||||
}
|
||||
|
||||
public static function exists( manager : sys.db.Manager<Dynamic> ) : Bool {
|
||||
var cnx : Connection = untyped manager.getCnx();
|
||||
if( cnx == null )
|
||||
throw "SQL Connection not initialized on Manager";
|
||||
try {
|
||||
cnx.request("SELECT * FROM `"+manager.dbInfos().name+"` LIMIT 1");
|
||||
return true;
|
||||
} catch( e : Dynamic ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C)2005-2017 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
|
||||
class Transaction {
|
||||
|
||||
public static function isDeadlock(e : Dynamic) {
|
||||
return Std.is(e,String) && ~/try restarting transaction/.match(e);
|
||||
}
|
||||
|
||||
private static function runMainLoop(mainFun,logError,count) {
|
||||
try {
|
||||
mainFun();
|
||||
} catch( e : Dynamic ) {
|
||||
if( count > 0 && isDeadlock(e) ) {
|
||||
Manager.cleanup();
|
||||
Manager.cnx.rollback(); // should be already done, but in case...
|
||||
Manager.cnx.startTransaction();
|
||||
runMainLoop(mainFun,logError,count-1);
|
||||
return;
|
||||
}
|
||||
if( logError == null ) {
|
||||
Manager.cnx.rollback();
|
||||
#if neko
|
||||
neko.Lib.rethrow(e);
|
||||
#else
|
||||
throw e;
|
||||
#end
|
||||
}
|
||||
logError(e); // should ROLLBACK if needed
|
||||
}
|
||||
}
|
||||
|
||||
public static function main( cnx, mainFun : Void -> Void, ?logError : Dynamic -> Void ) {
|
||||
Manager.initialize();
|
||||
Manager.cnx = cnx;
|
||||
Manager.cnx.startTransaction();
|
||||
runMainLoop(mainFun,logError,3);
|
||||
try {
|
||||
Manager.cnx.commit();
|
||||
} catch( e : String ) {
|
||||
// sqlite can have errors on commit
|
||||
if( ~/Database is busy/.match(e) )
|
||||
logError(e);
|
||||
}
|
||||
Manager.cnx.close();
|
||||
Manager.cnx = null;
|
||||
Manager.cleanup();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C)2005-2016 Haxe Foundation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
package sys.db;
|
||||
|
||||
// basic types
|
||||
|
||||
/** int with auto increment **/
|
||||
@:noPackageRestrict
|
||||
typedef SId = Null<Int>
|
||||
|
||||
/** int unsigned with auto increment **/
|
||||
typedef SUId = Null<Int>
|
||||
|
||||
/** big int with auto increment **/
|
||||
typedef SBigId = Null<Float>
|
||||
|
||||
typedef SInt = Null<Int>
|
||||
|
||||
typedef SUInt = Null<Int>
|
||||
|
||||
typedef SBigInt = Null<Float>
|
||||
|
||||
/** single precision float **/
|
||||
typedef SSingle = Null<Float>
|
||||
|
||||
/** double precision float **/
|
||||
typedef SFloat = Null<Float>
|
||||
|
||||
/** use `tinyint(1)` to distinguish with int **/
|
||||
typedef SBool = Null<Bool>
|
||||
|
||||
/** same as `varchar(n)` **/
|
||||
typedef SString<Const> = String
|
||||
|
||||
/** date only, use `SDateTime` for date+time **/
|
||||
typedef SDate = Date
|
||||
|
||||
/** mysql DateTime **/
|
||||
typedef SDateTime = Date
|
||||
|
||||
/** mysql Timestamp **/
|
||||
typedef STimeStamp = Date
|
||||
|
||||
/** TinyText (up to 255 bytes) **/
|
||||
typedef STinyText = String
|
||||
|
||||
/** Text (up to 64KB) **/
|
||||
typedef SSmallText = String
|
||||
|
||||
/** MediumText (up to 24MB) **/
|
||||
typedef SText = String
|
||||
|
||||
/** Blob type (up to 64KB) **/
|
||||
typedef SSmallBinary = haxe.io.Bytes
|
||||
|
||||
/** LongBlob type (up to 4GB) **/
|
||||
typedef SLongBinary = haxe.io.Bytes
|
||||
|
||||
/** MediumBlob type (up to 24MB) **/
|
||||
typedef SBinary = haxe.io.Bytes
|
||||
|
||||
/** same as binary(n) **/
|
||||
typedef SBytes<Const> = haxe.io.Bytes
|
||||
|
||||
/** one byte signed `-128...127` **/
|
||||
typedef STinyInt = Null<Int>
|
||||
|
||||
/** two bytes signed `-32768...32767` **/
|
||||
typedef SSmallInt = Null<Int>
|
||||
|
||||
/** three bytes signed `-8388608...8388607` **/
|
||||
typedef SMediumInt = Null<Int>
|
||||
|
||||
/** one byte `0...255` **/
|
||||
typedef STinyUInt = Null<Int>
|
||||
|
||||
/** two bytes `0...65535` **/
|
||||
typedef SSmallUInt = Null<Int>
|
||||
|
||||
/** three bytes `0...16777215` **/
|
||||
typedef SMediumUInt = Null<Int>
|
||||
|
||||
// extra
|
||||
|
||||
/** specify that this field is nullable **/
|
||||
typedef SNull<T> = Null<T>
|
||||
|
||||
/** specify that the integer use custom encoding **/
|
||||
typedef SEncoded = Null<Int>
|
||||
|
||||
/** Haxe Serialized string **/
|
||||
typedef SSerialized = String
|
||||
|
||||
/** native neko serialized bytes **/
|
||||
typedef SNekoSerialized = haxe.io.Bytes
|
||||
|
||||
/** a set of bitflags of different enum values **/
|
||||
typedef SFlags<T:EnumValue> = Null<haxe.EnumFlags<T>>
|
||||
|
||||
/** same as `SFlags` but will adapt the storage size to the number of flags **/
|
||||
typedef SSmallFlags<T:EnumValue> = SFlags<T>;
|
||||
|
||||
/** allow to store any value in serialized form **/
|
||||
typedef SData<T> = Null<T>
|
||||
|
||||
/** allow to store an enum value that does not have parameters as a simple int **/
|
||||
typedef SEnum<E:EnumValue> = Null<E>
|
||||
|
||||
Reference in New Issue
Block a user