diff --git a/docs/querying.md b/docs/querying.md index b04c3604..91c087ef 100644 --- a/docs/querying.md +++ b/docs/querying.md @@ -477,6 +477,36 @@ Post.include('comments', 'author') Post.find().with('comments').with('author') ``` +Please be noted that the chaining order of `.with()` matters, queries like below are not equivalent: + +```js +Post.findOne().with('comments') +// NOT EQUALS TO +Post.find().with('comments').first +``` + +By type definitions, both queries will return a Post instance or null depending on the record can be found or not. But the generated SQLs are quite different: + +```sql +SELECT * FROM (SELECT * FROM posts LIMIT 1) AS posts LEFT JOIN comments ON comments.post_id = posts.id +-- NOT EQUALS TO +SELECT * FROM posts AS posts LEFT JOIN comments ON comments.post_id = posts.id LIMIT 1 +``` + +The major difference is the place of `LIMIT`, the former query will fetch the first post and all of its associated comments, the latter query however, will only return the first post and its first comment. + +We can keep on chaining the query methods if comments need to be limited as well: + +```js +Post.findOne().with('comments').limit(10) +``` + +which is equivalent of SQL below: + +```sql +SELECT * FROM (SELECT * FROM posts LIMIT 1) AS posts LEFT JOIN comments ON comments.post_id = posts.id LIMIT 10 +``` + ### Arbitrary Joins If a join is needed but not predefined in `Model.describe()`, it can still be accomplished with `.join()`: diff --git a/docs/zh/querying.md b/docs/zh/querying.md index 598b6b83..61bf91bb 100644 --- a/docs/zh/querying.md +++ b/docs/zh/querying.md @@ -471,6 +471,36 @@ Post.include('comments', 'author') Post.find().with('comments').with('author') ``` +注意,链式调用 `.with()` 产生的作用会跟调用顺序有关系,下面两个写法是不等价的: + +```js +Post.findOne().with('comments') +// 不等同于 +Post.find().with('comments').first +``` + +虽然从接口定义来看,两者都会返回 Post 实例或者 null,但是两者所执行的 SQL 会有差别: + +```sql +SELECT * FROM (SELECT * FROM posts LIMIT 1) AS posts LEFT JOIN comments ON comments.post_id = posts.id +-- 不等同于 +SELECT * FROM posts AS posts LEFT JOIN comments ON comments.post_id = posts.id LIMIT 1 +``` + +可以看到区别在于 LIMIT 所在的位置,前者会返回第一条 Post 及其所有的 Comment,后者则只会返回第一条 Post 及其第一条 Comment。 + +使用第一种查询时,如果需要限制返回的评论数量,可以直接写: + +```js +Post.findOne().with('comments').limit(10) +``` + +等价于下面的 SQL: + +```sql +SELECT * FROM (SELECT * FROM posts LIMIT 1) AS posts LEFT JOIN comments ON comments.post_id = posts.id LIMIT 10 +``` + ### 任意 JOIN 如果需要 JOIN 未在 `Model.describe()` 预先定义的关联关系,可以使用 `.join()` 方法: diff --git a/src/spell.js b/src/spell.js index 81c2d550..ca578a6f 100644 --- a/src/spell.js +++ b/src/spell.js @@ -387,9 +387,7 @@ class Spell { #emptySpell() { Object.assign(this, { - columns: [], - whereConditions: this.Model.shardingKey ? this.whereConditions : [], - // whereConditions: [], + whereConditions: [], groups: [], orders: [], havingConditions: [], @@ -808,6 +806,7 @@ class Spell { $with(...qualifiers) { if (this.rowCount > 0 || this.skip > 0) { const spell = this.dup; + spell.columns = []; this.#emptySpell(); this.table = { type: 'subquery', value: spell }; } diff --git a/test/integration/suite/associations.test.js b/test/integration/suite/associations.test.js index 705494e8..80ddf792 100644 --- a/test/integration/suite/associations.test.js +++ b/test/integration/suite/associations.test.js @@ -324,5 +324,13 @@ describe('=> Associations order / offset / limit', function() { assert.equal(posts[0].title, 'New Post'); assert.equal(posts[0].comments.length, 2); }); + + it('on subquery with select', async function() { + await assert.doesNotReject(async function() { + const post = await Post.first.select('title').with('comments'); + assert.ok(post); + assert.ok(Array.isArray(post.comments)); + }); + }); }); }); diff --git a/test/integration/suite/sharding.test.ts b/test/integration/suite/sharding.test.ts deleted file mode 100644 index dcddf538..00000000 --- a/test/integration/suite/sharding.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { strict as assert } from "assert"; -import Photo from "../../models/photo"; - -describe('=> Sharding', function() { - it('should retain where conditions if sharding needed', function() { - assert.equal( - Photo.findOne({ userId: 1 }).with('user').toSqlString(), - "SELECT `photos`.*, `user`.* FROM (SELECT * FROM `photos` WHERE `photos`.`user_id` = 1 LIMIT 1) AS `photos` LEFT JOIN `users` AS `user` ON `photos`.`user_id` = `user`.`id` WHERE `photos`.`user_id` = 1" - ); - }); -});