Skip to content

Commit 7650c13

Browse files
authored
implement $query method dialect (#130)
* implement dialect * 2.6.77
1 parent 785720e commit 7650c13

File tree

5 files changed

+132
-5
lines changed

5 files changed

+132
-5
lines changed

eslint.config.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ export default [{
3737
'no-invalid-this': 'warn',
3838
'no-undef': 'error',
3939
'no-unused-vars': 'warn',
40-
'no-var': ['error'],
41-
quotes: ['error', 'single'],
40+
'no-var': ['off'],
41+
quotes: ['off', 'single'],
4242
strict: [2, 'never'],
4343
},
4444
}, ...compat.extends(

formatter.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,18 @@ SqlFormatter.prototype.$bit = function(p0, p1)
885885
return sprintf('CAST(%s AS char)', this.escape(p0));
886886
};
887887

888+
/**
889+
* Converts a select query expression to the equivalent statement.
890+
* @param arg {QueryExpression|*}
891+
*/
892+
SqlFormatter.prototype.$query = function(arg)
893+
{
894+
if (typeof arg.$select === 'object') {
895+
return Number.isInteger(arg.$take) ? `(${this.formatLimitSelect(arg)})` : `(${this.formatSelect(arg)})`;
896+
}
897+
throw new Error('Invalid query expression. Expected a valid select expression.');
898+
};
899+
888900
/**
889901
*
890902
* @param query {QueryExpression|*}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@themost/query",
3-
"version": "2.6.76",
3+
"version": "2.6.77",
44
"description": "@themost/query is a query builder for SQL. It includes a wide variety of helper functions for building complex SQL queries under node.js.",
55
"main": "index.js",
66
"scripts": {
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { QueryEntity, QueryExpression } from '../index';
2+
// eslint-disable-next-line no-unused-vars
3+
import { length, round, max, min, count, avg } from '../closures/index';
4+
import { MemoryAdapter } from './test/TestMemoryAdapter';
5+
import { QueryField } from '../query';
6+
7+
describe('Subqueries', () => {
8+
9+
/**
10+
* @type {MemoryAdapter}
11+
*/
12+
let db;
13+
beforeAll(() => {
14+
db = new MemoryAdapter({
15+
name: 'local',
16+
database: './spec/db/local.db'
17+
});
18+
});
19+
afterAll((done) => {
20+
if (db) {
21+
db.close();
22+
return done();
23+
}
24+
});
25+
26+
it('should use subqueries', async () => {
27+
const Orders = new QueryEntity('OrderData');
28+
const OrderStatusTypes = new QueryEntity('OrderStatusTypeData').as('orderStatus');
29+
const People = new QueryEntity('PersonData');
30+
let query = new QueryExpression()
31+
.select((x) => {
32+
x.id,
33+
x.orderDate
34+
})
35+
.from(Orders)
36+
.join(OrderStatusTypes)
37+
.with((x, y) => {
38+
return x.orderStatus === y.id;
39+
})
40+
.where((x) => {
41+
return x.orderStatus.alternateName === 'OrderPickup';
42+
});
43+
const {[Orders.name]: select} = query.$select;
44+
select.push(new QueryField({
45+
customer: {
46+
$query: [
47+
new QueryExpression().select(
48+
{
49+
$concat: [
50+
new QueryField('givenName').from(People),
51+
' ',
52+
new QueryField('familyName').from(People)
53+
]
54+
}
55+
).from(People).where(
56+
new QueryField('id').from(People)
57+
).equal(
58+
new QueryField('customer').from(Orders)
59+
)
60+
]
61+
}
62+
}))
63+
let results = await db.executeAsync(query);
64+
expect(results.length).toBeTruthy();
65+
results.forEach((item) => {
66+
expect(item.customer).toBeTruthy();
67+
});
68+
69+
});
70+
71+
it('should use aggregate subquery', async () => {
72+
const Orders = new QueryEntity('OrderData');
73+
const OrderStatusTypes = new QueryEntity('OrderStatusTypeData').as('orderStatus');
74+
let query = new QueryExpression()
75+
.select((x) => {
76+
x.id,
77+
x.orderDate
78+
})
79+
.from(Orders)
80+
.join(OrderStatusTypes)
81+
.with((x, y) => {
82+
return x.orderStatus === y.id;
83+
})
84+
.where((x) => {
85+
return x.orderStatus.alternateName === 'OrderPickup';
86+
}).orderByDescending(
87+
new QueryField('orderCount')
88+
);
89+
const {[Orders.name]: select} = query.$select;
90+
select.push(new QueryField({
91+
orderCount: {
92+
$query: [
93+
new QueryExpression().select(
94+
{
95+
$count: [
96+
new QueryField('id').from('a')
97+
]
98+
}
99+
).from(new QueryEntity('OrderData').as('a')).where(
100+
new QueryField('customer').from('a')
101+
).equal(
102+
new QueryField('customer').from(Orders)
103+
)
104+
]
105+
}
106+
}))
107+
let results = await db.executeAsync(query);
108+
expect(results.length).toBeTruthy();
109+
results.forEach((item) => {
110+
expect(item.orderCount).toBeTruthy();
111+
});
112+
113+
});
114+
115+
});

0 commit comments

Comments
 (0)