4 ms·
It's a feature, not a bug, that the code blows up when the database schema doesn't match my models. Just as the necessity of DI frameworks isn't an argument ag
by slumdev 5y ago
It's a feature, not a bug, that the code blows up when the database schema doesn't match my models.
Just as the necessity of DI frameworks isn't an argument against unit testing or the inversion principle, the necessity of ORM frameworks isn't an argument against static typing or relational databases.
- blacktriangle 5y agoIt's not the schema matching your model, it's the result of any query. How many different types do you need to represent the result of all possible projections on a single 10 attribute relation? Now join that to another 10 attribute relation, how many types to represent all possible projections of a single join between two relations? And Maybe is not the answer, Maybe is a lie. The data is either part of the result set or it is not based on the query.
- arc619 5y agoYou only need to map the database types to the language types at worst. So int, string, timestamps, binary, maybe GUID. Or you could just use string for all data and then you're pretty much matching a dynamic language. Results from joins between arbitrary queries are just lists of these types per field.
- blacktriangle 5y agoThe problem isn't the attributes. I WISH there was a dynamic language that would statically type your attributes, that would be the perfect hybrid for me. The problem is typing the agregates. So for all projections from a single table, that's 2^9 types. For all projections for a join on two 10 attribute relations, 2^19. This is in the realm of yes you can do this in a static type system, but why?
- slumdev 5y agoMost ORMs don't let us do this, and it works well. Getting back the entire relation (rather than some sub-tuple) isn't the kind of expense that causes problems scaling. It chews up network bandwidth between the database and the API, but it's not more computationally expensive (asymptotically). And if my entities are dozens of columns wide, I'm probably not in 3NF anyway, so it'd be better to focus my efforts on getting there.
- arc776 5y agoWhy do you want to have a static type for each combination of fields in a query? There's no need to do this. > I WISH there was a dynamic language that would statically type your attributes, that would be the perfect hybrid for me. In statically typed database frameworks it's often the other way round: you have pseudo-dynamic typing for fields but they're static under the hood, sub-typed for the specific database type and/or stored as raw bytes. This is basically "boxing" fields - exactly the same principle as dynamically typed languages do behind the scenes, except the library will have customised "boxing" designed for the subset of types the database supports, e.g., typed per field column rather than for every individual field in the result (like dynamic languages). This hugely reduces the overhead of actual boxing as you don't need to store the type of the field or indirect to its data. This is sort of like dynamic typing just for the database, except the possible types are focused on a specific subset the database supports and therefore can be made efficient for the task. Dynamically typed languages must cater for reassigning properties, fields, and/or types ad hoc, and must be made much more general - AKA slow. For example you could (in pseudocode) do: procedure showTitles(queryResults: QueryResults, titleName: string): for title in queryResults.fieldData(titleName): let str = title.getString # Returns a string type. display str let queryResults = db.query("SELECT * FROM MYTABLE") showTitles(queryResults, "title") You get the benefits of static typing and dynamic typing; type errors are caught at compile time, and you explicitly or implicitly convert the "dynamic" box for the field. For instance, trying to pass an object that isn't a `QueryResult` to the `showTitles` procedure will throw a compile time error. In dynamic languages, you could pass anything to that procedure and have to hope it doesn't blow up at run time. Testing all the possible paths and dynamic types that could be given to this procedure could be a combinational nightmare, so "to be safe" you'll have to check the type is the equivilent to a `QueryResult` anyway at run time... The `getString` function can do whatever it needs to do to convert the data if it's not stored as a string (or throw an error if this isn't possible/appropriate), whilst maintaining type relationships once it's out of the pseudo-boxed type and ensuring memory used is appropriate to the "real" type. Source: I've written database query frameworks for statically typed languages.