Design factors for database query domain-specific languages (DSLs) in object-oriented languages
Pramod Kotipalli | Stanford CS343D | Fall 2020
Most applications that interface with a database are written with object-oriented programming (OOP) languages. Many applications use SQL databases to persist data. There exists an ‘impedance mismatch’ between the use of object-oriented systems that act on objects of non-scalar values and the storage of scalar values (e.g. strings and integers) organized in SQL tables. The ubiquity of OOP systems and SQL databases is hard to overcome; many developers must use both together to write effective and performant web applications. Numerous object-relational mapping (ORM) software libraries exist as libraries for popular languages such as Hibernate ORM for Java, Active Record for Ruby, and the Django ORM or SQLAlchemy for Python.
From the perspective of the programmer of a sophisticated backend API, three language ‘front-end’ design factors are key when selecting or implementing a query DSL for an OOP language (implementation details of ORMs will not be discussed):
- Syntax readability
- Type-checking
- Extensibility </ol>
Syntax readability
In addition to a method-chaining (i.e. “fluent interface”) interface common to many programming languages, some languages have taken to including data querying syntax natively, as in C# with Language Integrated Query (LINQ). This “query expression” syntax supports data-query-specific keywords like from
and select
as native language constructs.
class Person { public int Age; public String Name; } | |
Code Fragment 1 - Initializing a people array in C# |
IEnumerable<Person> minors = people.Where(p => p.Age < 18); |
Code Fragment 2 - LINQ through a method chaining or a fluent interface syntax |
IEnumerable<Person> minors = from person in people |
Code Fragment 3 - LINQ through query expression syntax |
minors = Person.objects.filter(lambda p: p.Age < 18) |
Code Fragment 4 - Python lambda syntax in an ORM query |
The use of the lambda
keyword over the =>
in more sophisticated queries grows to be a tiresome syntax.
Type-checking
C#’s support of LINQ enables compile-time type checking of every query written in a program. Django’s ORM is constrained to Python’s dynamic type checking system leading to syntax like so for a similar C# query.
minors = Person.object.filter(age__lt=18) |
Code Fragment 5 - A query for minors through a Python ORM |
public static class DateTimeExtensions |
Code Fragment 6 - “Literal expressions” in C# |
public static class OrderExtensions |
Code Fragment 7 - “Literal expressions” in C# |
This site is open source. Improve this page »