Skip to content

Commit

Permalink
enable arithmetics on Id/Id64
Browse files Browse the repository at this point in the history
  • Loading branch information
andyli committed Sep 27, 2023
1 parent 5c4cb30 commit b58113a
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 27 deletions.
56 changes: 49 additions & 7 deletions src/tink/sql/Types.hx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,19 @@ abstract Id<T>(Int) to Int {
@:op(A>=B) static function lte<T>(a:Id<T>, b:Id<T>):Bool;
@:op(A==B) static function eq<T>(a:Id<T>, b:Id<T>):Bool;
@:op(A!=B) static function neq<T>(a:Id<T>, b:Id<T>):Bool;

@:op(A+B) static function plus<T>(a:Id<T>, b:Int):Id<T>;
@:op(A++) inline function postfixInc<T>():Id<T> {
return this++;
}
@:op(++A) inline function prefixInc<T>():Id<T> {
return ++this;
}
@:op(A--) inline function postfixDec<T>():Id<T> {
return this--;
}
@:op(--A) inline function prefixDec<T>():Id<T> {
return --this;
}
}

abstract Id64<T>(Int64) to Int64 {
Expand All @@ -78,11 +90,41 @@ abstract Id64<T>(Int64) to Int64 {
@:to public function toExpr():Expr<Id64<T>>
return tink.sql.Expr.ExprData.EValue(new Id64(this), cast VInt64);

@:op(A>B) static function gt<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A<B) static function lt<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A>=B) static function gte<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A>=B) static function lte<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A==B) static function eq<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A!=B) static function neq<T>(a:Id64<T>, b:Id64<T>):Bool;
@:op(A>B) inline static function gt<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) > (b:Int64);
}
@:op(A<B) inline static function lt<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) < (b:Int64);
}
@:op(A>=B) inline static function gte<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) >= (b:Int64);
}
@:op(A>=B) inline static function lte<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) <= (b:Int64);
}
@:op(A==B) inline static function eq<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) == (b:Int64);
}
@:op(A!=B) static function neq<T>(a:Id64<T>, b:Id64<T>):Bool {
return (a:Int64) != (b:Int64);
}
@:op(A+B) static function plus<T>(a:Id64<T>, b:Int64):Id64<T> {
return (a:Int64) + b;
}
@:op(A-B) static function minus<T>(a:Id64<T>, b:Int64):Id64<T> {
return (a:Int64) - b;
}
@:op(A++) inline function postfixInc<T>():Id64<T> {
return this++;
}
@:op(++A) inline function prefixInc<T>():Id64<T> {
return ++this;
}
@:op(A--) inline function postfixDec<T>():Id64<T> {
return this--;
}
@:op(--A) inline function prefixDec<T>():Id64<T> {
return --this;
}

}
39 changes: 19 additions & 20 deletions src/tink/sql/macros/Targets.hx
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,31 @@ package tink.sql.macros;
import haxe.macro.Expr;
import haxe.macro.Context;
import haxe.macro.Type;

using tink.MacroApi;

class Targets {

static public function from(db:Expr, targetE:Expr, cnx:Expr) {
return switch targetE.expr {
case EObjectDecl([target]):
var name = target.field;
switch Context.typeof(macro @:privateAccess ${target.expr}.asSelected()) {
case TInst(_, [fields, filter, result, db]):
case TInst(_, [fields, filter, result, db]):
var fields = [];
var fieldsComplex = ComplexType.TAnonymous(fields);
var resultComplex = result.toComplex();
var aliasFields = [];
switch haxe.macro.Context.followWithAbstracts(result) {
case TAnonymous(_.get().fields => originalFields):
for (field in originalFields) {
for (field in originalFields) {
var fComplex = field.type.toComplex();
fields.push({
pos: field.pos,
name: field.name,
kind: FProp('default', 'never', macro : tink.sql.Expr.Field<$fComplex, $resultComplex>)
kind: FProp('default', 'never', macro :tink.sql.Expr.Field<$fComplex, $resultComplex>)
});
aliasFields.push({
field: field.name,
field: field.name,
expr: macro new tink.sql.Expr.Field($v{name}, $v{field.name}, ${typeToExprOfExprType(field.type)}),
});
}
Expand All @@ -36,37 +36,36 @@ class Targets {
var aliasFieldsE = EObjectDecl(aliasFields).at(target.expr.pos);
var f:Function = {
expr: macro return null,
ret: macro : tink.sql.Expr.Condition,
args: [{
name: name,
type: fieldsComplex
}],
ret: macro :tink.sql.Expr.Condition,
args: [
{
name: name,
type: fieldsComplex
}
],
}
var filterType = f.asExpr().typeof().sure().toComplex({direct: true});
var blank = target.expr.pos.makeBlankType();
macro @:pos(target.expr.pos) {
var query = ${target.expr};
var fields = (cast $aliasFieldsE: $fieldsComplex);
@:privateAccess new tink.sql.Dataset.Selectable(
$cnx,
fields,
(TQuery($v{name}, query.toQuery()): tink.sql.Target<$resultComplex, $blank>),
function (filter:$filterType) return filter(fields)
);
var fields = (cast $aliasFieldsE : $fieldsComplex);
@:privateAccess new tink.sql.Dataset.Selectable($cnx, fields,
(TQuery($v{name}, query.toQuery()) : tink.sql.Target<$resultComplex, $blank>),
function(filter:$filterType) return filter(fields));
}
default: target.expr.reject('Dataset expected');
}
default: targetE.reject('Object declaration with a single property expected');
}
}

static function typeToExprOfExprType(type:Type):ExprOf<tink.sql.Expr.ExprType<Dynamic>> {
return switch type.getID() {
case 'String': macro VString;
case 'Bool': macro VBool;
case 'Float': macro VFloat;
case 'Int' | 'tink.sql.Id': macro VInt;
case 'haxe.Int64': macro VInt64;
case 'haxe.Int64' | 'tink.sql.Id64': macro VInt64;
case 'haxe.io.Bytes': macro VBytes;
case 'Date': macro VDate;
case 'tink.s2d.Point': macro VGeometry(Point);
Expand All @@ -83,4 +82,4 @@ class Targets {
case _: throw 'Cannot convert $type to ExprType';
}
}
}
}
108 changes: 108 additions & 0 deletions tests/IdTest.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package;

import Db;
import tink.sql.Types;
import haxe.Int64;
using tink.CoreApi;

@:asserts
class IdTest {
public function new():Void {}

public function arithmetics() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert(id + 1 == 124);
asserts.assert(id - 1 == 122);
return asserts.done();
}
public function arithmetics64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert(id + 1 == Int64.ofInt(124));
asserts.assert(id - 1 == Int64.ofInt(122));
return asserts.done();
}

public function addAssign() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert((id += 1) == 124);
return asserts.done();
}
public function addAssign64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert((id += 1) == Int64.ofInt(124));
return asserts.done();
}
public function minusAssign() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert((id -= 1) == 122);
return asserts.done();
}
public function minusAssign64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert((id -= 1) == Int64.ofInt(122));
return asserts.done();
}

public function postfixInc() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert(id++ == 123);
asserts.assert(id == 124);
return asserts.done();
}
public function postfixInc64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert(id++ == Int64.ofInt(123));
asserts.assert(id == Int64.ofInt(124));
return asserts.done();
}
public function postfixDec() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert(id-- == 123);
asserts.assert(id == 122);
return asserts.done();
}
public function postfixDec64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert(id-- == Int64.ofInt(123));
asserts.assert(id == Int64.ofInt(122));
return asserts.done();
}
public function prefixInc() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert(++id == 124);
asserts.assert(id == 124);
return asserts.done();
}
public function prefixInc64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert(++id == Int64.ofInt(124));
asserts.assert(id == Int64.ofInt(124));
return asserts.done();
}
public function prefixDec() {
final id:Id<User> = 123;
asserts.assert(id == 123);
asserts.assert(--id == 122);
asserts.assert(id == 122);
return asserts.done();
}
public function prefixDec64() {
final id:Id64<User> = Int64.ofInt(123);
asserts.assert(id == Int64.ofInt(123));
asserts.assert(--id == Int64.ofInt(122));
asserts.assert(id == Int64.ofInt(122));
return asserts.done();
}
}
4 changes: 4 additions & 0 deletions tests/Run.hx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class Run extends TestWithDb {
Promise.reject(Error.asError(err));
}, max10Seconds)
.next(_ -> Runner.run(TestBatch.make([
new IdTest(),
new TypeTest(mysql, dbMysql),
new SelectTest(mysql, dbMysql),
new FormatTest(mysql, dbMysql),
Expand Down Expand Up @@ -104,6 +105,7 @@ class Run extends TestWithDb {
final dbPostgres = new Db(env('POSTGRES_DB', 'test'), postgres);
return Promise.retry(()->loadFixture(dbPostgres, 'init_postgresql'), max10Seconds)
.next(_ -> Runner.run(TestBatch.make([
new IdTest(),
new TypeTest(postgres, dbPostgres),
new SelectTest(postgres, dbPostgres),
new FormatTest(postgres, dbPostgres),
Expand Down Expand Up @@ -135,6 +137,7 @@ class Run extends TestWithDb {
final db = new Db(env('COCKROACH_DATABASE', 'test'), cockroachdb);
return Promise.retry(()->loadFixture(db, 'init_cockroachdb'), max10Seconds)
.next(_ -> Runner.run(TestBatch.make([
new IdTest(),
new TypeTest(cockroachdb, db),
new SelectTest(cockroachdb, db),
new FormatTest(cockroachdb, db),
Expand Down Expand Up @@ -162,6 +165,7 @@ class Run extends TestWithDb {

return loadFixture(dbSqlite, 'init_sqlite')
.next(_ -> Runner.run(TestBatch.make([
new IdTest(),
new TypeTest(sqlite, dbSqlite),
new JsonTest(sqlite, dbSqlite),
new DateTest(sqlite, dbSqlite),
Expand Down

0 comments on commit b58113a

Please sign in to comment.