The article makes a good point; I never think of an ORM as a replacement for SQL -- it can work in concert with it. A lot of my code is much simpler with an ORM than it would be worth out it and in other places it's much simpler with direct SQL than without it. Both can live together harmoniously.
Another example of this would be Pandas for Python, the code the developer writes looks like Python, but the DSL provided actually translate to Fortran & C. There's also a project called Dask which reimplements the backend for Pandas' DSL to run distributed. I wish there was an equivalent for pyspark :)
1. They isolate the "magic strings" where your code knows about your database schema in one place (the mappings or conventions). Database changes break your app in only one predictable place.
2. They keep junior developers from constructing queries in ways that are vulnerable to SQL injections.
I put part of that blame on languages. When the wrong thing is so much more natural than the right thing, it's bound to happen.
We use relate (https://github.com/lucidsoftware/relate), a Scala lib.
sql"SELECT * FROM users WHERE email = $email"
After years and years of no ORM and dozens of junior developers, we've never had a SQL injection bug.
SQL (in strings) is not composable at all. Your app rarely has fixed set of queries and almost always need to be able to construct 'where' dynamically, add joins, etc. SQL syntax is especially non-composable, because there once was hype to make programming languages imitate natural languages. In this case, ORM is inevitable if you don't want to have rube goldberg machines of string concatenation everywhere.
Non-OO ORMs may be not called "ORM"s but idea is the same. Moreover, Sqlalchemy Core mentioned in article is great example of non-OO ORM: it composes queries and returns result in tuples[1].
[1] http://docs.sqlalchemy.org/en/rel_1_1/core/tutorial.html