Have you thought about JSON as a partial query placeholder, and all the native methods available for traversal, merging, plucking, etc.?
For example, here is :
{ type: 'select', columns: [{ expression: 'orgJobs.org_job_code', alias: 'job_code' }], joins: [{ table: 'org_jobs', alias: 'orgJobs' }], limit: 100, offset: 0 }
which yields:
select orgJobs.org_job_code as job_code from org_jobs as orgJobs limit 100 offset 0
and so its easy to do things like:
query.limit = 100;
and of course:
query.columns.push(additionalColumn);
and use something like lodash/underscore (or equivalent for your language) to add collection/array/object helper methods so you never have to write for-loops for things like mapping and property plucking.