#Core Haxe
1 messages ยท Page 5 of 1
but true is probably getting parsed to a json string "true"
oh yeah? Ok, but still, i dont like that you have to use string "true" in haxe... doesnt feel right
i think i'm doing something a bit off the road here anyways ๐
what i want here is a ```json
true
and what haxe `true` is parsing as is a json:
```json
"true"
still, i think ill UT it and see what happens, feels like it should notice its true (actual haxe bool) and either turn it into "true" (mysql string) or 1 (boolean bit - dunno if thats how mysql stores bools, but feels sensible)
i'm only guessing at what i think is going on here anyways
yeah, same, unit test will make it clear
mysql doesn't have a bool field does it?
MySQL treats it as a synonym for TINYINT(1)
ok, and its "TRUE" or "FALSE" - not string literals - no quotes
oh huh
wonder if that applies to json fields though... probably not
the json part i think will be different, i mean, im assuming
for sure, but the json was trying to make up for a lack of a bool type
WHERE jsonfield.someBoolField = TRUE - if that works, its defo ideal
yeah, no, its not the same
This is different from a BOOL column, which is really just a TINYINT(1) (numeric).
llm, so could be wrong, but i doubt it - will UT it tomorrow with the variations to confirm
still, i get the feeling that, nothing to do with json columns, core-db isnt handling true (haxe type) properly in the query expr... might be totally wrong about that, but will check it out
i tend to just use 1 and 0 for bool types in dbs... and, i dont think, ever use TRUE or FALSE... i also dont ever remember writing a query expr in core-db like $someField = true... so could just be an oversight (likely)
yeah, i was doing 1/0 but when i saw the json field i thought I could just get it to work
i like being able to do if (obj.isTrue)
yeah, thats the part i feel wouldnt work currently in core db (not a json field)... i know i handle that specifically in entities2 (in entities2 code there is macros like this.$field = record.get($v{field}) == 1)
i think it would be if (obj.isTrue == 1)
(im going to start referring to entities2 as entities, since i archived entities1 - that was news to me... "Past Ian" is more on the ball than i thought ๐ )
e^2
๐
trace(Type.typeof(settings.isdefault)); evaluates to a String on js
isdefault is a json field that just contains "true", right?
i think i prefer the hxcpp version here, though i dont like the mismatch
correct
same, on cpp it evaluates to bool
i have no idea why it doesn't here if it parses everything else as a json
thats because the db-core/libmysqlclient parses json fields
is it just a coincidence that js works with json fields then? lol
who knows, it probably parses it, but maybe there is some "if startswith { or [" or something
ahhhh
i cant control that npm lib
well either way its fine... i think
well, its defo not ideal, its a mismatch in behaviour, which i dont like - that said, it defo feels like an edge case
C:\Users\j\Documents\projects\ceramic\ProjectStudy\src\systems\StyleSystem.hx:30: TClass({
__name__ : String
}), false
yeah okay, not fine
its arguable that you are abusing the json field?
thought that would still eval to true
absolutely, but, it is valid json
in fact, hang on, why are you using a json field to have "true", why not just a bool?
because i only found out that it existed when you mentioned it not too long ago ๐
agreed
right, and maybe its not nicely supported in core-db... (that part is easily fixable)
i might be able to get that to work tho
wonder how a tinyint field gets eval'd on js
i defo feel like if you just want a bool, then you should use a bool type, if core-db isnt handling it properly, its better to fix that than shoehorn a json type
yeah, defo need unit tests here
testing tinyint now
i think in js "if (someVar)" means "not null", i dont know what happens in js if "someVar === 0"
some freaky js shit no doubt
so it isn't a real bool
but its not in the db either
tinyint isnt a bool... i mean, it is, but its just a 1/0
mysql has no concept of "bool"... as far as i understand
mysql being the same as C i presume
i think i just need to write some UTs to properly understand it... but i defo get that "if (record.isDefault)" is better than "if (record.isDefault == 1)", and im almost sure core-db should be able to handle that correctly (since i do in entities)
as far as i remember, in C / C++ its basically:
#define BOOL int
#define TRUE 1
#define FALSE 0
BOOL b = TRUE; // int b = 1;
there isnt some intrinsic "bool" type in computers
exactly, so its just conversion...
true, but "if (true)" is nicer than "if (1)"
js craziness
... yeah
x = 0 means it wont trigger if (x)
so x == 0 is the same, in js as x == null
so 1 and 0 is true and false in js? I mean, thats "ok" i think, the "0 is null" is odd though
yeah, crazy
x = 0
if (x) console.log("x"); else console.log("not x");
not x
๐ฌ
i thought "if x" meant "if its null or undefined", but nope, it also means "if its not 0", it seems, thank god i dont have to deal with vanilla js
yeah, haxe makes things quite nice
i treat js as if its native
and everything makes sense
amen
you cant even do "if x" in haxe (which makes perfect sense ofc)
if you are going to create that construct though, it should at least make sense... i dont even get the "or if its zero" thing tbh
"if x is null, undefined or zero"... that "zero" seems very out of place ๐
if you think about it like its a "speaking language" it makes a bit more sense
nothing == nada == none
dunno... im not on board... 1234/ 0 = undefined (undefinable)... they mean different things
agree
im probably over thinking it no, now one writes anything serious in vanilla js, but its crazy dangerous
well given all these crazy paths
you really would think true =="true" would pass ๐
if (!someVar) {
throw "some crazy exception that takes the whole system down because null is bad"
}
... ... ... someVar = 0... ๐ฑ
mental
note to self: if ever dealing with vanilla js, use if (someVar === null)
Wouldn't it be more "if x is null, undefined, false or zero" ? that false == 0 would kind of make sense
zero (or false) != undefined
(or null)
undefined is "without a definition", null, is "no value"... false and zero are both values (and definitions)
Don't worry I agree with you.. But I think there's some logic behind.
if (x) -> if (x==true) -> if (x!=0)
im sure there is logic, but its faulty, zero / false (or 1 / true) shoudnt be lumped in with null / undefined
Yeah it feels kind of "old" in a way... wouldn't have expected this in js.
thats not accurate though, it means if (x != null && x != undefined && x != 0) (for example)... the negative case is much worse: if (x == null || x == undefined || x == 0)
... ... that 0 just slips through ๐ฎ
wouldn't have expected this in js.
really? js is known for this insantity... there is this "whhhhhat" thing? Ill see if i can find it
Javascript Whaaat #shorts #shortvideo #node #javascript #development #coding #programming #js
... that was easy ๐
oh, its not the one i meant though
haha indeed... I knew php was kind of like this .... never knew js was this insane. I should thank haxe too ( for sanitizing it)!
seen this before... i feel like the audience is on something
this is unironically correct and sane 
if (x) {} wont run if x is a falsy value in js
as in, null, undefined, NaN, 0, -0 and the empty string IIRC
I do understand the logic... pretty simple when we think about it...
If you use "+", it tries special concatenator for string.
If it's "-", it considers both a number except that one is not a number so it's Nana
The big video though... there were too many for me.
ye
it's just type coercion doing its thing
Hey Ian, https://github.com/core-haxe/db-core/pull/9 in reference to this issue
underscore is failing
pls merge the flag
hmm, issue looks similar but may be a case of bad code
got 3 libs, don't want each lib to depend on each other, but at the same time they're all used together
so got duplicated code and mismatching type paths :/
hmm... what's the solution to the problem...
another library! ๐
lets see how it pans out ๐
i dunno, im a little averse to just adding a flag "because"... so, in all the haxeui-* libs, i need to do the same? I doubt it... i think there is something weird going wrong somewhere else...
-lib db-core
...
...
...
#if db_core
trace("got it");
#end
should work
also, that error doesnt seem to be related? Or, well, i guess, i dont know what Db.insert is doing... looks like a good 'ol type mismatch though
src/systems/PositionSys.hx:79: {
message : Invalid JSON text: "not a JSON text, may need CAST" at position 0 in value for column 'positions.open'.,
call : update
}
Yea, maybe auto conversion to json on nodejs at least isn't a good idea
what was the field value?
i dont think this is coming from db-core though... that error looks like its coming from mysql server
but maybe db core is creating a crappy query though
i don't think its core, i think this is the nodejs externs
I think I understand the problem here
i just don't know how or where to solve it
cant you use an actual BOOL type?
wdym
mysql doesn't have a bool type
it does apparently
waah i've looked at that list multiple times
i just switched to tinyint and you're telling me this now
i did see a unknown type for the column that i was tempted to mess around with
but it seemed a bit too experimental for my mood currently x)
What is the bool type lol
huh, your are right, i can only find this now: https://github.com/core-haxe/libmysqlclient/blob/main/lib/include/field_types.h#L77
and the comment doesnt fill me with confidence
its alright, getter life is fine
i did think that dbcore could auto convert true to 1 and false to 0 if it was passed as a value but i think that's an added assumption
like a nosql db supports actual bools so that wouldn't be good
i think it could / should if you use "true" in a query
(it might already do that tbh)
but getting it out of the db, it will always be 1 / 0... db core isnt going to know (i dont think) if its a bool or an actual int
(entities2 handles all this ofc ๐ - but thats because the entity objects are the schemas, so it knows its a boolean from the haxe source)
is that smart tho? postgres supports bool types as well
maybe it can auto convert true/false for the mysql backend?
well, the query just turns into a QueryExpr (so just a sort of small AST for a representation of a query), its then the db plugins job to turn that into something useful... so sql for mysql / sqlite
so if there was another db plugin then it would have to turn the QueryExpr into something that that db platform would understand
eg: eventually ill create a IndexedDB plugin (the database thingy that lives in the browser), that doesnt use sql, so all query exprs have to work with that system (not hard i dont think, maybe even easier than sql)
so, TLDR: i dont think there should be any problem with a QueryExpr, when turning into SQL, will recognise "its a bool" and turn it into "WHERE FIELD = 1"
Ohhh cool i getchu now
lots of layers to abstractions
missed where query expressions are in the chain
yeah, its a super important part of the abstraction tbh... because queries are pretty much everything, but once you say "has to be sql" you are now totally limited to what dbs you can support
another eg: eventually, id like to use this with lucene / solr and that has a totally different query system... so, if queries were "only sql" then its just a non starter
also, something like entities2 living in the browser (as IndexedDB) is a pretty cool idea
question about e2, if I have a record mapped out, and i update the field does that automatically update the database?
interesting either way
question is, is it worth moving from
Db.update('table', data, query($aid == aid));
๐
the issue here, to me, would be "what is 'data'"... Are you turning it to / from actual objects / typedefs at some point?
Nope
it's a db.Record that's generated by a macro from the class fields
so yeah, its just a collection...
entities creates actual objects, that can link to each other, etc
the relationship stuff sounds interesting for sure
you cant use arrays in your setup... and you certainly cant use an object that has a bunch of arrays contained in it
(not trying convince you, just highlighting the differences)
i would also say, this isnt a million miles away from e2, its just that e2 does it all for you generically... so you dont have think about it anymore... looking at this it seems like a "personal ORM" and entities is a "generic ORM"
yeah, that's kind of why i'm in the middle here
I think I basically have a form of orm with my ecs and the above setup
you've just gone way deeper with the details than i have
mines at version - "it works"
yeah, thats pretty much exactly why e2 exists, i ended up doing it over and over again...
if it works, and you dont need 1 -> 1 or 1 -> many relationships (which i think?) your ORM doesnt handle, then it doesnt matter so much
i think i will and i also want many to many at some point
how would you represent many -> many in haxe code? (the haxe code is the schema in e2)
i have no idea
i have no use for it currently
but i will have things like custom tagging for data
i figured many to many is the way to go about that
in entities it would probably just be an var tags:Array<Tag>
as a member var for an entity (Tag also being an entity ofc)
i think i'm nearing the point where i'll probably get to justify playing with it
couple more backend things to do on the list
then I can run away from the messy code base into e2 for a lil bit
and at least then, I can experiment on a new branch
cool - i would have a play with it in isolation first, you already have an ORM, so its a change
yes, i'll defo do that
i've peaked at it a few times and i don't immediately get it
don't want my project context to mix it up even more
nooo
just hit a moment where e2 would be useful ๐
i have an array of order ids, that i'd really like to be an array of order objects and i suspect e2 would have that setup
aaaand because i don't have access to the order objects some of my tables have additional columns that I probably wouldn't require if the relationships were handled
okay, i think i've got enough convincing to actually look into it ๐
its funny how we can work around problems and not even notice them x)
so the tricky part of figuring out e2 is gonna be all these meta's
yeah, e2 seems confusing as heck
where do you even load data from the db
all the cases seem to just create things locally
am i thinking "too db-like"?
wdym?
also, wdym?
i see no get queries or how to "load" data from the db
everything seems to just magically exist
at least in the test cases
there's no relatable app flow that I can pick up lol
everything does magically exist, yeah:
class MyEntity implements IEntity {
public var someString:String;
}
EntitiesManager.instance.database = ... // any db-core db
var myEntity = new MyEntity();
myEntity.someString = "bob";
myEntity.add().then(...);
or table definitions
e2 will build all the tables for you, will update them where needed also (schema diffing)
in the ref examples there's var arrayobj:Array<X>
but i have no idea what the type of arrayobj is
its fair, but does that mean i should start a completely new db for e2?
okay, that's good to know, i'll dupe rather than test on my existing db
not sure what you mean here
you should probably play with it outside of anything, just standalone if you are having trouble grepping it... @uncut phoenix i think has some code that uses it
i am playing with it alone ๐
public var arrayObjectA1:Array<SubObjectA>;
if there's a mini project out there it might be easier to understand than the test cases
for now, i'll see what happens if i just start a new mock db with e2
yeah, the UTs are probably a little over complex and badly named for it to be really useful (since for the most part they specifically testing something), like the ref one you are looking about is all about circular references and refs to refs to refs, etc
var db:IDatabase;
function new() {
db = DatabaseFactory.instance.createDatabase(DatabaseFactory.MYSQL, {
database: 'entities',
host: 'db',
user: '',
pass: ''
});
db.setProperty('autoReconnect', true);
db.setProperty('autoReconnectInterval', 5000);
db.setProperty('replayQueriesOnReconnection', true);
db.connect().then((res) -> {
if (res.data) {
trace('connected');
this.connected();
}
}, (err) -> trace(err));
var timer = new Timer(500);
timer.run = this.loop;
}
function connected() {
var order = new Order();
order.oid = '1';
order.exchange = 'Bybit';
order.symbol = 'BTCUSDT';
order.side = 'Buy';
order.price = 10;
order.quantity = 0.5;
order.add();
}
I have this little bit of code, but i'm getting a stack trace
called from order.add()
anything obviously silly here?
couple of things:
- i dont think you need to connect
- you have to actually specify the database on the entity manager
ahh okay
EntitiesManager.instance.database = ... // any db-core db
var myEntity = new MyEntity();
myEntity.someString = "bob";
myEntity.add().then(...);
hmmmmm
im just about to head into a meeting, can you paste the entities (as text) and ill see if i get the same
i kind of understand how you can map up the oids now though
pretty cool
import entities.IEntity;
class Order implements IEntity {
public var oid:String;
public var exchange:String;
public var symbol:String;
public var side:String;
public var price:Float;
public var quantity:Float;
}
class Position implements IEntity {
public var aid:String;
public var pid:String;
public var exchange:String;
public var symbol:String;
public var side:String;
public var price:Float;
public var quantity:Float;
public var liq:Float;
public var open:Bool;
public var stopId:Order;
public var takeId:Order;
public var oids:Array<Order>;
}
Will it be possible to specify a field type? like, i'm assuming Float will map to Double but I want it to be a Decimal in mysql
nope, and it wouldnt make sense to... its not guaranteed to be a mysql (or whatever) db
something like @:size could be reused for it... but currently that only applies to strings
awkward, can i prevent e2 from overwriting the field type then?
also no, you dont really deal with the db anymore... i mean, it might not change the type of the field if its already there, but if that works, its more a bug than a feature
whats the diff between double and decimal? Precision?
i feel like correct "entities" way to handle that would be to introduce a "Currency" type, like there is a "Timestamp" type
yeah, that does seem more correct
i can repro this... odd, will be something simple
"order" needs to be escaped ๐ - interesting its never come up before
the table name? lol
yup
they do, but obviously never used reserved keywords like "order"
ORDER BY
aaaahhh
fixed
wow the issue was in db-mysql
yeah so weird that never came up
actually... i never created a table with dbcore so i guess that makes sense
cool lil find
okay now i'm having a compile time error
function connected() {
var order = new Order();
order.oid = '1';
order.exchange = 'Bybit';
//order.symbol = 'BTCUSDT';
order.side = 'Buy';
order.price = 10;
order.quantity = 0.5;
var pos = new Position();
pos.oids.push(order);
pos.add().then(null, (err) -> trace(err));
order.add().then((_) -> {
}, (err) -> trace(err));
}
ERROR C:/HaxeToolkit/haxe/lib/entities2/git/src/entities/macros/EntityBuilder.hx:1103: characters 64-90
1103 | promiseList.push($p{classDef}.deleteById.bind(id));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
| (?fieldSet : Null<entities.EntityFieldSet>) -> promises.Promise<Bool> should be () -> promises.Promise<Any>
| For function argument 'x'
| For function argument 'onFulfilled'
position is:
class Position implements IEntity {
public var aid:String;
public var pid:String;
public var exchange:String;
public var symbol:String;
public var side:String;
public var price:Float;
public var quantity:Float;
public var liq:Float;
public var open:Int;
public var stopId:Order;
public var takeId:Order;
public var oids:Array<Order>;
}
runtime error you mean? You dont need to add() pos, pos.oids.push(...) is enough, e2 will take care of adding... also, you are using promises badly
sorry, wrong way round, you dont need to add() order
no compile time error
i dont think null is valid for a promise callback... ... ?
error is super odd though
this works fine for me, no compile / runtime errors:
var order = new Order();
order.oid = '1';
order.exchange = 'Bybit';
//order.symbol = 'BTCUSDT';
order.side = 'Buy';
order.price = 10;
order.quantity = 0.5;
var pos = new Position();
pos.oids = [];
pos.oids.push(order);
pos.add().then((_) -> {
}, (err) -> trace(err));
ahh is the error I forgot to instantiate the array?
doubt it
copy pasted your exact code
maybe this is a haxe 5 error....
yeah, that's it
seems like there's probably a type hint missing somewhere in the chain and it trips up on hx5
4.3.7 works fine
ahh yes it is a problem in e2 i think
just haxe 4 doesn't notice it
var promiseList:Array<() -> promises.Promise<Any>> = [];
that's how promiseList is defined
var deleteJoinDataFn = entityClass.addStaticFunction("deleteById", [
{name: "id", type: macro: Null<Int>},
{name: "fieldSet", type: macro: entities.EntityFieldSet, value: macro null}
], macro: promises.Promise<Bool>, [APrivate]);
that's the type of deleteById
is the issue here that Promise<Bool> isn't unifying with Promise<Any>? ๐ค
okay, i've got it somewhat working
its very magical how all of a sudden i have tables
makes me cautious ๐
ahhhahh
an entity is a table so queries are all done via Table.find() etc
so as long as i mock up the entity properly, everything should work fine. Wonder how it will play with 2 unique columns
You mean Entity.find?
like Order.find(...)
yeah, so you can use Entity.find / Entity.findAll which take queryexpr params
but instead of returning records, they'll return populated entities (including the sub entities, arrays, etc)
that's quite nice, does remove some boilerplate that i worked around
what i tend to do also, is create static functions on the entity class like findBySomeField(someField:String) that just calls the find / findAll
eventually these static functions will also be used to create indexes on the db, which should make them super fast...
im just not sure how, yet, to create indexes in db-core in a universal way... im thinking as simple as "createIndex(fields)" is enough for any most db engines
nope, meta is pretty slim on the ground currently
i dont think thats possible in core db even
yeah
enum ColumnOptions {
PrimaryKey;
NotNull;
AutoIncrement;
}
wonder if i mark it as unique in gui if it'll get overwritten ๐
i'm not sure i like how many assumptions there are for table creations
but maybe that's just beginner pains
like all my fields are marked as nullable
but i don't want it to be possible to send a null value for a lot of these
nice, if i flip a text field to varchar add unique and a length it doesn't get overwritten
@:size(100) will change text to a varchar(100)
i did try that but it didn't auto update the field
yeah, its a known bug, one that ill fix soon(ish)
which also means it will nuke your manual changes
as long as i can reapply them i dont particularly mind
you wont be able to, fixing that bug will mean the entity schema (the classes) will always win
then I won't be using e2 unfortunately ๐
cool - your call - @:unique wouldnt be hard to add, but its not some thing im going to be adding "now"
yeah, its cool
if i can't work around what's "not there yet" I can't really use it either way
well, at the moment, it will preserve any manual modifications you make to the table... but its a bug, not a feature
true, guess i could just not update ๐
Also, any particular reason why you default to nullable?
Wouldn't it be better to mark a field as nullable if I have var field:Null<Float>?
you mean turning var x:Float in var x:Null<Float>?
I mean, all of these allow NULL
but i haven't specified that anywhere in the schema
just the default i presume, its not explicit in the table creation i dont think
surely it makes sense anyway? I mean, no value = null
I want it to error if there's no value in some cases
like if oid is null, i want to know when its null, it shouldn't be
i mean, @:notNull is one of the other metadatas i want to add, but me thinks you rely on db validation too much ๐
is that a bad thing?
well, i defo personally prefer to not have to make a round trip to the server to find out if something is null or not
Its fair, but, i guess its just a secondary stop point
I can review how i write things and see if there's issues there
barring any fuck ups, imo, the apps job is to have the data is as ready a state as possible before it delivers it to the backend, and the backend validation is more of a backup
sure, but you said you want it to error in some cases, which indicated to me that you were relying on the db to tell you?
fair, maybe i am
dont get me wrong, im not saying @:notNull isnt useful / important to catch bad data santization on the front end...
but it doesnt, imo, remove the need for sending "good data" to the backend
for sure
also why not just check if the type is null wrapped? wouldn't that be a more "haxey" way to handle it?
rather than have the meta
could be an option, yeah... just have to think what that means for non nullable types... i have a feeling i turn primitives into null wrapped types anyway
you'd have to if you want something to be nulled
no, i mean, i think i turn Float into Null<Float> via macros
yeah
it works with abstracts as well which is nice
doesn't seem to trip up on that
i really like how the relationships are handled
i don't actually have to have an aid column in every table (was avoiding relationships)
in code I just make a simple account:Account field instead
e2 does actually reduce a good chunk of code that i've already written, just as i work through things
the question becomes, is there an e2 migration service if I wish to use it? ๐
message : You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order
ADD `account` INT' at line 1,
call : addColumn
}```
probably another escape issue i guess
probably another silly question
var user = new User();
user.name = "Test Main";
var account = new Account();
account.user = user;
account.name = "Test";
account.add().then(null, (err) -> trace(err));
//--------------
class Account implements IEntity {
public var user:User;
public var name:String;
public var altname:String;
public var exchange:Exchange;
public var key:String;
public var secret:String;
public var passphrase:String;
}
class User implements IEntity {
public var name:String;
}
No user table is created and no account table is created, and no errors
...maybe it's the change i just did ๐ค
unlikely, just double checked it
so, entities tables are created on demand as they are used, if you dont use an entity, it wont create tables, data, etc. However, if you want to force creation of all entities you can use EntitiesManager.instance.initAllEntities (its promise based, ofc, so you'll need to make sure you use it properly)
aren't i using an entity in the first few lines though?
oh yeah, you are, missed that
not sure then, null as a callback still looks really weird to me
will try with a value
maybe that is screwing with something?
same deal
not sure, defo does work, so something weird you must be doing... is your app exiting before its had a chance to add them or something? Sure you are looking in the right db, etc
app is still running and that's all the code besides db creation
weird....
i defo refreshed it 10 times
but just refreshed it again and it's there now :/
its not a local db, correct? Maybe the provider had a slow down or something
not local, yeah
well, my bad!
the relationship stuff is so damn cool man
i don't know how you figure this stuff out
i think i want to use it, but its a completely different workflow to what i have
its gonna be some work switching it out
yeah, i quite like it all ๐
it certainly stops me from writing the same ORM for each project over and over again, and invariably, every project needs some type of ORM
i'm just mentally, and roughly going through it
and i think i can drop like 2 or 3 tables, a bunch of code querying everything because I assume with this
if i do Orders.find(query($account == 6)) everything that returns is gonna be auto mapped
i don't need to run any additional queries looking for related accounts etc
still not completely clear tbh, but, i'm sure its gonna work well
exactly, yeah, you dont need to think about tables or anything anymore, the entities are the schema
gotta let go of that, my brain is still in query mode
yeah, i guess it takes some time to get out of "SQL Mode", but on the plus side it means you dont have sql queries littered around your app, which is always a pain to manage
i'm actually really looking forward to that part
it was defo on my list to go on a big query hunt and start refactoring stuff
granted my setup isn't too bad for that because of the ecs nature
like, you change a field name... oh, now i have to go through a bunch of SQL queries and update... that kinda thing just evaporates
I don't think the way that I interface with things is going to change that much, the thing that's gonna change the most is data is going to be more accessible with less work
i suppose you dont need your DB.query class (or whatever it was)
will have to see, first step first is start to port some data and get a more applicable glimpse of how things look
I have logging stuff in there as well
was about to add a column in heidi.... nope, i'm meant to add it to the class
heh heh ๐
public var active:Int = 0; syntax idea... registers as a default value for the field
... it would happen anyway though wouldnt it?
why would it need to be a default on the db?
i don't know man, i've been running two typers
maybe completely unnecessary work
yep, just works
yeah, as i mentioned, the set of haxe classes is effectively the schema, so it would be perfectly doable to say "if its 1, put it as the default value in the db table creation", and it would be fine, but in practice, you are already doing that when you set it to a default value in the haxe classes, so really the default value on the db column would be kinda meaningless
with the added pain of, if you changed it to "2", db-core / entities would have to notice that and update the db schema
yep, slow abandoning sql thinking
oh, is there a way to add a field to an entity but not have it db related?
in the case of a getter, a local state var etc
@:ignore
perfect ๐
expected that a setter on a field doesn't compile?
@:ignore public var date:String;
@:ignore public var time:String;
public var timestamp(default, set):Timestamp;
function set_timestamp(value) {
date = DateTools.format(Date.fromTime(value), '%d/%m/%Y');
time = DateTools.format(Date.fromTime(value), '%H:%M:%S');
return timestamp = value;
}
whats the error?
ERROR C:\HaxeToolkit\haxe\std/haxe/macro/Printer.hx:130: characters 18-20
130 | return switch (ct) {
| ^^
| Uncaught exception Null Access
-> C:\HaxeToolkit\haxe\std/haxe/macro/ComplexTypeTools.hx:40: characters 10-43
40 | return new Printer().printComplexType(c);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Called from here
-> C:/HaxeToolkit/haxe/lib/entities2/git/src/entities/macros/ClassBuilderTools.hx:51: characters 34-69
51 | var typeString = ComplexTypeTools.toString(arg.type);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Called from here
-> C:/HaxeToolkit/haxe/lib/entities2/git/src/entities/macros/EntityBuilder.hx:67: characters 13-60
67 | entityClass.substitutePrimaryKeysInQueryCalls();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| Called from here
-> src/Order.hx:3: character 1
3 | class Order implements IEntity {
| ^
| Called from here
ERROR src/Main.hx:43: characters 16-27
43 | var order = new Order();
| ^^^^^^^^^^^
| Order does not have a constructor
| For function argument 'onFulfilled'
probably not handling something, like the default... isnt that a kinda weird way round to handle that? Wouldnt it be more correct to have getters that return the date / time parts of the timestamp
want to cache the values
why? Because of cost?
it'll be used in haxeui tables
cost, just doesn't seem like a good idea to have as a getter when the value only needs to be set once
cache it in the getter then, but seems like a micro optimization if you ask me
i went through my whole codebase hitting these things because they were significant in tracy ๐
@:ignore public var _date:String;
public var date(get, never):String;
private function get_date():String {
if (_date != null) return _date;
_date = DateTools.format(Date.fromTime(timestamp), '%d/%m/%Y');
return _date
}
feels more correct and more localised than doing it in a setter to me
although, if timestamp changes then its a problem actually
indeed
... fixed
lol thanks
huh, i'm confused
Am i reading this right, it seems like you're converting floats to decimal's, but they're coming through as doubles on the db side
maybe decimal here isn't sql decimal, but a number with a decimal place
there is another set of mapping also, which is entity field type => core db field type
although, im guessing Decimal = Decimal there
public function haxeTypeToDatabaseType(haxeType:ColumnType):String {
return switch (haxeType) {
case Number: 'INT';
case Decimal: 'DOUBLE';
case Boolean: 'INT';
case Text(n): 'VARCHAR($n)';
case Memo: 'TEXT';
case Binary: 'BLOB';
case Unknown: 'TEXT';
}
}
i still think double is the right choice here, but i think a new Currency that maps to DECIMAL might be wise
(i dont want to add a Double to the enum because its too specific)
cool makes sense
uurrr, i think i've ported all the data over to an entities like structure
i guess now I try to branch my code and see if I can implement it all in the actual project ๐
Am i correct that @:cascade will basically "run down the list"
so if i delete something in my Position table, it will delete all the relationships linked to it as well?
yeah, entity typed variables marked @:cascade (one-to-one or one-to-many) will be deleted when the containing entity gets deleted
nice
how do you do ordered/limit queries with entities?
like a Table.GetFirst('column')
order doesnt exist in db-core yet, so you cant... limit i think there is a function for it, but i forget... two secs...
i have no idea what this is supposed to be doing
ah yes, i do a raw query in my previous setup
raw still works... you can use Query.raw(...) in entities
oh interesting
findByPage is i think how you would create a LIMIT query
I might see if i can reconfigure my current setup to see if I can keep it a bit more localised
i would just sort on the client side with array.sort until i add proper db ORDER BY
order by + limit
yeah, order by + limit, you'll have to use raw for now
no worries, i'm happy with that
im not ๐
๐
theres a couple of place in some apps ive written where ive used it, but its "ok" (useful to have the option) but its certainly not ideal
means you have to use / know the table structure, which is NOT ideal at all...
i just like we're not blocked
and figuring out a clean api for adding order somewhere seems a bit of a nuisance in itself ๐
defo
enums are nice
its more about where to put it
would it be a parameter on every function call in db-core?
I just do GetFirstRecord(table, where, value, orderby) and no need to think about it
but it's a private api
yeah.... seems awkward
firestore did have a query chaining kind of setup
maybe applicable here
query($id == 4).order(ASC).then(...)
a dsl would be built ontop of this, you'd still need to be able to use the lib "as is" (especically in e2 macros)
query($id == 4) is a queryexpr though... i think, if anything, it would be query($id == 4, [fields], DESC).. but even that doesnt really fit into the query expr (at all)
its even about the look of it, its that query(...) builds a query ast
so not sure how that would be represented in the ast... metadata maybe, or even a sort of QueryExprSort or something, either option is messy
ah yes, we're back in the abstract complication land
yeah
maybe a different backend would help make things a bit clearer
with the figuring out what's the ideal abstraction
and now that i say that, it probably explains why there's so many haxeui backends lol
I'm getting a bunch of these errors
exchange.Exchange is:
package exchange;
enum abstract Exchange(String) from String to String {
var Binance;
var Bybit;
var Coinbase;
}```
and they're all coming through on the class
any ideas on where to look?
I think there's an error forwarding issue in the entity macro somewhere
it's weird because it did work in an isolated project so I don't really think the issue is with the abstract
yeah, issue is somewhere else. Changing it to a string gets me Order.hx:8: character 1 : String has no field data
changing what to a string?
sorry realised I never sent the code
the line it's complaining about is var exchange:Exchange;
which is the abstract above, but I'm not sure it's actually relevant
can you paste (as files) the Position.hx, Order.hx, Balance.hx and PositionHistory.hx?
could be some other macro in your project (ceramic / state thingy) interfering perhaps?
Could be, but i've never gotten the error prior to e2
Okay, so I just went for a walk and got back and I think i've got a pretty big hint
it is something to do with the variable name
var exchange:Exchange
If i change the var name to test the error goes away
feels very odd, exchange isnt a reserved word in anything afaik
maybe there's an incomplete type path somewhere?
the error exchange.Exchange has no field data
looks like the package, package exchange.Exchange
you couldnt repro this outside your project though, correct?
i haven't tried, i've tried to figure out what's the link between everything
the package in those files is exchange.data
be interesting to see if it happens in your "e2 only" test app
I can try, i think it's a decent hint
ah, ok, i think i can understand it though... the variable name is exchange, the package is exchange
yeah
nice, just reprod it as well
... gonna be fun to track down, i get a no stack trace
yeah, tried to get the debugger to trip up in the macro but no dice
i have no idea on where it does things ๐
im not sure there is a way round it
it basically creates code like:
exchange.data.Something.DoSomething
but you have a member var called exchange
i think you would have a similar issue if you tried to it in user code
i think i can minimize the collision, but i dont think its fully removable
var joinTableName = entityField.joinTableName();
var joinForeignKey = entityField.joinForeignKey();
var classDef = entityField.toClassDefExpr();
trace(classDef);
trace(entityDefinition.className.split("."));
var temp1 = classDef.copy();
var temp2 = entityDefinition.className.split(".");
temp1.pop();
temp2.pop();
if (temp1.join(".") == temp2.join(".")) {
trace(">>>>>>>>>>>>>>>>>>> they are the same");
classDef = [classDef.pop()];
}
this can minimize it, but you'll still get the issue of you try to use an "exchange" var in an entity that isnt in the same package
problem is that you cant create imports in macros, so you have to use fully qualified names
what's going on?
it thinks the package exchange is the same as the variable exchange?
the issue is that, in macros you have to use fully qualified paths (you cant add imports), so, the macro is creating code like:
exchange.data.Order.findById(...)
but exhcnage is a membmer var, so it thinks you mean the member var
ohhh
i can minimize it by checking the packages, and if they are they same, doing:
Order.findById(...)
which would work for your case, but the issue is technically still there, and im not sure its solvable
i think the saving grace is that usually you have a single package of entities, so it should be fine for like 99.9% of cases
yeah, seems like it's a shadow collision. Maybe rudy would know a way around it
i dont think there is a way round it, its a language "thing" (that makes perfect sense really)
you just could work around it in user code by doing an "import exchange.data.Order"
isn't that just normal?
i think the solution is the one im proposing, if the packages are the same, then just use "Order" not "package.Order"
it minimizes the issue, but i suspect, 99% of the time, entities are all in one package anyway
so, to trigger the issue you'd have to a) have entities in two different packakges AND b) use a variable name in one of them that is the first part of the package of another
there are 2 packages here that trip up and knowing the issue i'm confused by it
which seems pretty minimal
my exchange library entities and the projects db.HyroAccount
do you understand the issue? Im not sure you are following what i mean
i think ill add in the "mitigation"... and i think it will be "fine" for most use cases, you'll have to kinda try to break it (or have a bit of a weird setup) to trigger it
fixed
ok, so yeah, this is the edge case... totally different package
what's the way to work around it at a user level
dont call the var exchange, or move the HydroAccount into the exchange package
i can live with platform
and theoretically e2 will just handle the refactor for me ๐
until you use platform as a package also ๐ฆ
๐
If it makes you feel any better I've just realised that because e2 handles relationships at the point of the query
I actually don't need every table to have the exchange column ๐คฃ
I only need the column on the account and the rest can just become getters
although, i find it curious why the ignore isn't working here
Account.findAll(query($user == 5)).then((accounts) -> {});
also another weird thing. This query is returning 0 results
but there are defo matches
hmmm
its still a varaible in the class... so it will still mess things up
ahhh I thought it was just because of the macro parsing it
nope, the issue is the variable is called exchange and there is code that is generated like exchange.data.Something.Else(...)
@:ignoring the var doesnt change that conflict
this im not sure about, but for sure this works as its the most basic thing
can you trying something really quick though, in EntityBuilder.hx there is entityClass.substitutePrimaryKeysInQueryCalls()... can you comment that out just to sanity check something
still 0 results
hmm... actually maybe initialisation order has changed due to using entities
Db.getRecords('account', query($user == 5), (records:RecordSet) -> {
trace('Direct: ' + records.length);
});
Account.findAll(query($user == '5')).then((accounts) -> {
trace('Entities: ' + accounts.length);
});
It gets weirder... Both of these return 0 results
db is defo connected
!!
im guessing the second shouldnt be a string?
was just testing
figured out the issue
dbs.init("tracker", "", "", "");
was still using old db name x)
entities created the table on the og db
so it never actually errored
silly oversight x)
public var entryTimestamp(default, set):Float; {}
this field is being ignored
probably due to the setter
yeah, i think fields that are getters / setters are explicitly ignored because they arent really "schema like"
like, there is behaviour associated with them, so the assumption is made to ignore them
it might not be the case, but i think so
i swear they were going through at some point
so could i
yeah, that was a recent addition so maybe just an oversight
you know, i think the auto overwrite tables thing is quite dangerous
I just got a little scare because I just realised that the misnamed db issue from earlier could have erased data in my original db by sheer coincidence
... with great power... ... .... ....
๐
comes greater power
realisitically, your local app should in NO WAY be connected to your prod server, and you should be using a local version, so on your head be it ๐
Oh by the way Ian totally related to programming.
I am doing a playthrough of factorio and trying to launch the rocket.
for sure it would have been my mistake but what a massive mistake that would have been ๐
I got the space age dlc, I wanna see how crazy it gets :,)
I am going to immediately backup my og db now that i've been reminded how important the data is x)
ive also got the dlc, tried to play a few times, but never gotten even close to getting off the planet... keep giving up after a few hours
What roadblock are you hitting?
i mean, it would be like running a bunch of sql commands on your prod server, regardless of entities, its not a good move
time
Are you starting fresh each time?
im going to start again though, this time going to go huge
yeah
i get to my normal "right, trains trains everywhere" and then get all "fuck this, i cant be botherered"
Well that's the problem, the starting phase is so tedious and slow
nah that's where you have to double down
you gotta make ugly complex systems it's part of the game
defo, thats the part you have to push through
i just got totally bored of laying tracks for 8 hours when i defo should be doing other things
What I've been doing to get past it, is I've been building factories in horozontal focusing on something I want
so I don't have one mega complicated spagetti monster
I only lay tracks to move resources
damn ๐ that's so overkill
the distances are HUGE ๐
Yeah but still you have 4 drop off points in the middle of nowhere
well, thats the begginning of the main factory the other one above is just my starter factory
I get what you're going for, but to me it seems you are scaling way to fast.
Did you have blue science by that point?
naw, i dont think so, ill get blue conveyers in my starter soon
It's so overkill ๐
i dont start building the "main factory" until i have blue conveyors because its soo much effort to replace red -> blue
the point, to me at least, is defo overkill... even worse is how i build all my production lines as loops as to not waste ANY resources (ie, they feed back into themselves)... totally over complicates everything for little gain
and every time i restart im like "right, no loops this time"... and then i start building the loops
one of the simpler examples, couldnt find an older save game
also, you say overkill, but have you seen the insane amount of resources needed for the late game stuff, its crazy
yeah but why not scale after you hit the point when you actually need it
this is just insanity
i can have a bank of 64 factories working flat out producing copper wire and it still not enough
well, i dont build it all at once, its modular for sure
what are you producing o.O
blue conveyors require 15 blue circuits
awful, i hate it ๐
But but but WHY I mean I know it's faster and better, but the resource sink is just insane.
Were you doing oil yet?
yeah, i get oil as fast as possible
not sure about this play through, but generally as soon as i can i do
even if its a little hodge podge to start with
trust me (bro), your setup will bite you in the end... everything will crawl to a halt ๐
I'll just make another one! ๐
yeah, thats what im doing... well, was doing... big(ish) start base, but its all just there for the "final base" which is the one that will just max out everything so i dont have spend years removing shit at upgrading it...
is that ingame years lol
defo works, and eventually its 100% needed
(no idea on factorio)
feels like literal years when you are expanding things and go "oh, shit, this wont fit" and then have to spagettify everything
px doesnt seem to care though looking at his train setup, so more power to him ๐
Yeah I gave up caring about grand setups
I am using the train there to just move around
My current save there I want to build a nuclear reactor
well, you've inspired me to start again, check back in a few months and lets compare notes and see your frustration and my inner zen / peace ๐
so I laid a bunch of tracks to find a uranium deposit
Okay deal
I would be suprised if you hit inner zen, but I'm also more curious if one or both of us will launch the rocket.
we'll both launch one (probably), but for you it will be like pulling teeth, for me it will just be "yeah, its all there, throughput is x 1000 of items per second"... ๐
you'll be gray, and ill still be my youthful self ๐คฃ
I don't KNOW, I don't have the same impulse of needing to go through the early stages and grinding again.
I think that's where the youthful energy goes to die!
everything. must. be. perfect.
but also, it really helps the late game imo
Also this is where I will build my end base because it's so pretty
i hate you, im considering discord blocking you ๐
I have struck a cord I didn't even know existed, ๐
yeah, its new to me too, im going to lose sleep over your factory setup ๐
I think you will lose your mind if I build a giant spaghetti monster and launch the rocket and I show the picture of the end base and it's so incredibly hideous and awful. You ask me oh how many teeth did you pull and I just reply, oh it was a breeze, super simple
I think there's a high probability especially given the drones you get at end game
I could build total nonsense and still get it to work.
Oh no did I get blocked... ๐
Ian has probably started a game
@:isVar public var testSetter(get, set):Timestamp;
function set_testSetter(value) {
date = DateTools.format(Date.fromTime(value), '%d/%m/%Y');
time = DateTools.format(Date.fromTime(value), '%H:%M:%S');
return testSetter = value;
}
function get_testSetter() {
return testSetter;
}
Just checked this out and its also ignored so I guess we can't have setters on fields
haha, no, was eating ๐
i think properties in general
was browsing through the code and found some thoughts
not sure if its about this kind of thing though
just seems related to properties
i think its better, in a way, to think of entities as typedefs...
i mean, from a data pov
i wouldnt want getters / setters to be in the db, nor would i want to decorate them all with @:ignore... they are behaviour type things, not "just data"
just seemed like a good place to init some variables
it isn't actually affecting the db data, but its preparing the data for the client
maybe the isVar could be a modifier there, like, if its isVar it will end up in the db
the alternative here is I basically have to add getters/setters to each of these props
@:ignore public var entryObj:Date;
@:ignore public var exitObj:Date;
@:ignore public var entryDate:String;
@:ignore public var entryTime:String;
@:ignore public var exitDate:String;
@:ignore public var exitTime:String;
which is equally meh
thats because you are insisting on caching all this stuff...
one thing i think i am going to add is some type of overridable function: onBeforeLoad and onAfterLoad (or something)
then the entryObj could be cached in a getter (which feels right to me) and the onAfterLoad would null it (or reset the cache basically)
eg:
bro it was necessary
58 million iterations?
58 million iterations
no, i dont think you are joking, im just saying that 58 million iterations isnt realistic, if it were in a hot loop, maybe, but it shouldnt be
anyway, i have no fundemental issue with the cache, i just think its in the wrong place
it should be in the getter, the problem there is if timestamp changes, your cache is wrong / old value
there's a lot of places where i use date stuff in my app so it all compounded
58 million times? ๐
๐
5800 times would be excessive
surprised me as well
i was just doing Date.now() etc every where
i saw that figure and was like NOPE
tracy very good x)
i still dont really get how you can do a date.now 58 million times in 33s tbh... but, fine
it defo aint that high now, i should probably check at some point tho
still in e2 migration mode
yeah, but it sounds like you are still calling that function 58 million times in 33s, it just is returning the cached value...
and i dont really understand why its being called that much in the first place... indicates your app is sitting there idle calling the function in a hot loop
hmmmm, i'm not sure if that's the case post review
i don't think the 58m figure moved to cache vars
but that was like 2 months ago now so i have little memory of what i did now x)
all i know is app ran pretty good after addressing it
it is possible
just something for down the road
Oh man, you really do see the difference in data response time with entities, will need to handle that at some point
how do you handle that in your apps?
queries are typically instant
oh you know what I think is happening, at least on this page
For this particular example i'm querying for 30 records and its taking about 900ms to load in
Is it pulling all of the associated relationships in this query?
Is there a way to say "no need to get the relationships for this query"?
for cases like this that might be a decent solution
1 trade can consist of at least 2 orders, so that's a minimum of 90 queries going on here and there's probably more queries to look up the relationship id which if i understand right, would add another 30
where can i trace the final built query? want to see if i can figure out what's going on
i've put traces in all of the functions in databaseconnection for nodejs but none of them have it
found it
very confused
var now = Date.now().getTime();
Account.find(query($accountId == 1)).then((resp) -> {
trace('entity elapsed: ${Date.now().getTime() - now}');
});
var now = Date.now().getTime();
Db.get('account', query($accountId == 1), (resp) -> {
trace('dbcore elapsed: ${Date.now().getTime() - now}');
});
This returns around 300ms each, so something else is adding latency, but heidi completes the query immediately so it isn't a network issue
so weird
if I switch to my old database the same dbcore query takes 36ms
hmm no further leads, but just left with more weirdness unfortunately
i think its sub queries as you say, although 300ms seems excessive
what does the Account entity look like
in fact, can you dump all your entities in a zip?
you can use fieldsets
30 distinct queries?
Nope, a singe query
var _loadStart = Date.now().getTime();
PositionHistory.findAll(query($entryTimestamp >= startTime && $entryTimestamp <= endTime && $account == aid)).then(function(records) {
var _loadEnd = Date.now().getTime();
trace('Elapsed: ${_loadEnd - _loadStart} length: ${records.length}');
yeah, ive been running some tests locally, and it seems network latency and query count is problematic
it can't be latency though because heidi returns instantly and the old db returns instantly
still involves a network though, its not local connections... and even if it runs "instantly" it still has to deliver the result to you... even 10ms adds up here
i did try to compare both dbs last night and couldn't find any differences
under the hood though, entities is doing more querying
I'd like to run the entire query stack for the page but i'm getting new weird and fun error this morning lol
in my example, from one of the unit tests, i have an entity, granted its super nested and has a BUNCH of sub entities and sub-sub entities, etc (so lots of queries)... when i run the test against a local db, it takes 11ms... ... when i run it against a remote db its a whopping 2000ms
it seems really odd tho, no? my old db was running on the exact same server and 2seconds for a small example seems crazy
again, its network latency, it adds up fast...
each query is a round trip to the server
even 5-10ms here is very significant
yeah, 30*10*relationships
SELECT * FROM
positionhistory_orders
WHERE (positionhistory_orders.positionHistoryId= ?);`
Is it possible to output the queries with the values?
i noticed the option but didn't know how to use it
they can / will help in the short term
at the top of the entity, do something like:
@:fieldset(NoSomeField, [!someField])
and then when you call find, use that fieldset
SomeEntity.find(..., SomeEntity.NoSomeField).then(...)
they were originally intended to be used to not query certain data for security reasons, but they "accidently" double as a way of reducing queries
but the fundemental issue remains... ive never hit this because i wouldnt in a million years allow my client apps to make direct queries to a db, and everything goes through an api, which lives on the same network (effectively) as the db... but regardless, its defo an issue, and the diff between 11ms and 2000ms is... ... ... shocking
yeah, that's the plan, it just seemed odd. Like poeple actually do ship mysql in their clients and even a 100+ queries seems like it should be pretty damn quick
especially with a small dataset
my db only has no more than around 3-4000 records
its not the data size, its the general network latency... if you had a latency of 5ms (which is tiny, its going to be bigger), then 100 queries is 500ms
eg, a single query on my non-local db is about 45ms
that drops to about 0-1 locally (and the 1s are 0.999999999999s so rounding)
yeah, added the fieldset and now my response is 30-100ms
have noticed something else weird going on
all my haxeui page changes are occuring 3 times
exactly, less queries = less latency, its an "ok" solution, but im a little surprised just how high it was without query tuning (especially for me locally)
yeah the example seems quite simple, like at first glance it seems like "how does anyone else handle this"
less queries
entities1 was join based, and it can get completely out of hand fast (query wise)
its one of the reasons e2 exists actually
and in my initial tests things looked great... i didnt (obviously) factor in network...
so i wonder if some type of hybrid approach can be used
adds a HUGE amount of complexity to already complex code though
yeah the joins aren't easy with tons of relationships
and the coding nature of entities really encourages relationships lol
coding nature of entities really encourages relationships
exactly
i cant remember the details exactly, but with a deeply nested entity in v1, i was getting like 30 joins and a result set of 1 million rows or something crazy
granted it was an extreme example, but still
you'll have to live with fieldsets for the time being until i can digest it properly... suffice to say, i can repro it (and worse) locally
jesus
fieldsets would help there as well
yeah, fieldsets didnt exist in v1 - they are pretty powerful
no probs, fieldsets solve the bulk of the delay just an interesting problem in general to poke at
you saying interesting, i say fucking annoying ๐
could probably have some preset fieldsets as well
Layer 0 - No Relationships
Layer 1 - 1 Level
Layer 2 - 2 Levels
etc
its interesting because of how seemingly simple but damaging it is ๐
its not how fieldsets work, they exclude fields by name, not by type, so "no relationships" would have to be handled explicitly, and i dont really like / want to do that
also, you shouldnt have to use it... fieldsets were never supposed to be a "oh, queries are taking too long? Use a fieldset"
it was supposed to be "oh, leaking sensitive info to the client after serilaization? Use a fieldset"
true enough...
there is valid in using them to exclude entire subobjects... but perf should have to be one of them
if you want to use it for perf, cool, it should make a fast thing faster, but 2000ms vs 11ms... is crazy
fieldsets likely don't have the flexibility for the problem as well
like, i might want my orders but don't need the relationships on the orders
should be able to do that with field sets
oh really?
iirc you can pass down fieldsets from other entities and exclude them
Oh cool!
so
Account.findByBy(..., Account.NoSomeField | Order.NoSomeOtherField)
something like that anyway
neat
again, the idea being that you wouldnt want, for example, User.passwordHash coming through, but User could be "anywhere"
Does that actually make things more secure?
If the request is on the clientside, couldn't the client just modify the request to re-inlude the hash?
possibly, though no easily... and anyway, it should be an api function anyway, its for things like a "findUsers" api call not returning things you dont want it to
rather than having to null results so they dont end up coming down the wire
class UISettings<T> implements IEntity {}
Can we get type params on entities ๐
useful for general purpose + json fields
probably a complicated ask in general actually
yeah, i think that would be very complex... and would probably only really work with @:generic... defo not something im thinking about addding. I even dropped inheritance because, in practice it felt like it was "cool" but not really very useful and added a bunch of complexity
A simple workaround could just be that it maps an unknown type to Dynamic and just doesn't error
because project does compile but its giving a macro error
oh nvm, anything marked as Dynamic is ignored as well ๐ค
I was browsing the internals of e2 and saw a Date type
what does that become? mysql date or timestamp?
Would be cool if entity.table was publicly exposed
Would allow for making some static extensions that can be universal to entities but not specific to any one in particular
without requiring a table name
there goes that idea ๐ฅฒ
why would insertOrUpdate be useful, thats what add does
or, well, update
if it doesnt exist it will add it
didn't know that, but also, it's a small example there's other extensions that will be useful
public static function getFirst(account:AccountId) {
return find(Query.raw('SELECT * FROM `order` WHERE `account` = \'$account\' ORDER BY `created` ASC LIMIT 1'));
}
I'm duplicating this code in multiple places as another example
I don't necessarily need to set succ/err on promises everywhere and can just handle that in a single place
so where is this getFirst function? I would expect it to be on the Order class
Yeah, it's in the respective entities
and the query is the same?
besides the tablename yeah
feels very "meh" to want to put that single (tiny) query in a generically typed class
even if not a sort by field option isn't an awful idea
it's not just about the query, it's also about other things, like this
i have to do the whole promise boilerplate with callbacks everywhere
around 40% of these, i don't need specific actions
cant you handle the error in the getFirst function? Its like an additional 3-4 lines
then i lose the flexibility of being able to manage the error in a place i might want to
you mean on the thing that calls getFirst?
yeah
i haven't gotten this part of the project to compile yet though, and i'm gonna try casting to dynamic and see if that lets me through
then a moving it all to another class aint gonna help you, you are still going to need handle the promise error handler in the code that calls getFirst, regardless where the error originates
It will
entity.add().then(null, (err) -> trace(err));
entity.insert(); // static extension
static function insert(entity, ?succ, ?err) {
entity.add().then(successHandler.bind(succ), errorHandler.bind(err));
}
the promise is already handled and its handled a lot better than a lazy trace
this seems immensibly over complicated, and you run the risk of using entities before they are "done", ie, you arent really using promises correct here at all
entity.insert(); // static extension
trace(entity.primaryKey); // may have written to the db, may not have, insert should be promise based and you should use then, its an async function
but if i want entity.primaryKey I pass a succ function to insert
entity.insert((succ) -> {
//normal callabck
});
ok, then why not just uses promises? You are creating (potential) callback hell over the top of a promises??
because I can handle a bulk of my use cases in a better way
Proper logging without the additional work
seems completely mental, but, ok ๐
entity.insert((succ) -> {
});
vs
entity.insert().then((succ) -> {
});
and, now do it where you want to add five entities one after another
entity.insert((succ) -> {
entity.insert((succ) -> {
entity.insert((succ) -> {
entity.insert((succ) -> {
entity.insert((succ) -> {
});
});
});
});
});
?
just feels like a bad pattern in general, and i dont even see the benefit, except having to type "then", but now you cant chain promises, or use PromiseUtils.runAll / runSequential...
but there's a lot of situations where you just want to do entity.add()
and because you're in a flow you end up just doing entity.add.then(null, (err) -> trace(err)) which is a pretty lazy error handler
fire and fogetting something like a database add feels dangerous, unless its like logging or something, and even then, id like to know it was written (or not)
which is a pretty lazy error handler
better than no error handler?
mine has error handling by default
ok, so you are handling promise errors globaly
and success handling by default
so you can get a nice log (If you want) that something completed or errored without manually adding it everywhere
it does lead to a better experience in general
code is less messy and more accurate
still feels like a total anti pattern and misuse of promises, but well, its not my app ๐
hmm, i haven't had a problem with it tho
the worst problem i had when i first used it was line numbers/call location
but that's solvable with PosInfos
i think you are sidestepping the async nature of promises for the sort term benefit of not explicitly handling errors
entity.add.then(null, GlobalErrorHandler.instance)
is how i would do it by NOT using callbacks and having this little function that is basically telling me "use promises like they were sync"
there is a tempation to do something like:
entity.field = 0;
entity.add();
entity.field = 100;
entity.update();
and this is totally wrong... and the result would be "who knows", depends on a few things
I can see that occurring for a public lib but i've never personally done that
you never need to add an entity and then update it?
or worse, have a process that is, at different point in time, updating some entity, like a timer or something?
well previously i had my insertOrUpdate command ๐
and you said that update does that
it does, i think add might also update if it already exists all, cant remember
actually, thats not true, add will always add a new entity
but update will add if it doesnt have a PK, update if it does
this is probable but how does using a promise the normal way avoid this? they would both be subject to the same issue here
updating, adding is defo cool to know
yeah, not a great example tbh, but i more meant that the nature of the promises "instructs" you to think of it as an async operation, imo, your helper hides that (with the added "benefit" of putting you in callback hell if you want to make, say 3, updates in a row)
but as i said, its not my app, so you do you ๐
it would be used in context specific situations, not all
there are a lot of times where all you want to do is a simple instruction without the nesting
its just cutting out some boilerplate
makes it worse, again, imo: "heres a util function that helps, dont use it all the time though, use proper promises the rest of the time"
where as im of the opinion: "use proper promises, all the time, its consistent"
something that has always annoyed me about haxe, just tried to add this function:
function doSomething<T:IEntity>(instance:IEntity) {
return instance.add();
}
ofc, .add doesnt exist on the IEntity (since im just using it for macro building), so i thought, ok, cool, ill add it (probably not a bad idea anyway), so:
@:autoBuild(entities.macros.EntityBuilder.build())
interface IEntity {
public function add(fieldSet:EntityFieldSet):Promise<IEntity>;
}
and now:
./cases/basic/entities/BasicEntity.hx:11: character 1 : ... error: cases.basic.entities.BasicEntity should be entities.IEntity
./cases/basic/entities/BasicEntity.hx:11: character 1 : ... have: (...) -> promises.Promise<cases.basic.entities.BasicEntity>
./cases/basic/entities/BasicEntity.hx:11: character 1 : ... want: (...) -> promises.Promise<entities.IEntity>
even though class BasicEntity implements IEntity
consistency is a fair point for sure
i've never understood that either
i can cast it i think in the macro function...
and probably no negative side effects... unless i lose the typing of BasicEntity in the promise result
i think you would
prolly :/
so T basically can't be forwarded
actually, i dont even think i can cast it
i would have to change the function signature of the add to return an IEntity, then i would defo lose type info
i could do "implements IEntity<TheType>" to be fair
so actually, i think the error is "alright" now im thinking a little better about
is it possible to make the _ private?