Skip to content

Commit

Permalink
fix: select everything when forming subspell (#382)
Browse files Browse the repository at this point in the history
otherwise the columns might be quolified unnecessarily, or worse, insufficient for further joining
  • Loading branch information
cyjake authored Mar 24, 2023
1 parent 43d7af4 commit fc88a06
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 14 deletions.
30 changes: 30 additions & 0 deletions docs/querying.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`:
Expand Down
30 changes: 30 additions & 0 deletions docs/zh/querying.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()` 方法:
Expand Down
5 changes: 2 additions & 3 deletions src/spell.js
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,7 @@ class Spell {

#emptySpell() {
Object.assign(this, {
columns: [],
whereConditions: this.Model.shardingKey ? this.whereConditions : [],
// whereConditions: [],
whereConditions: [],
groups: [],
orders: [],
havingConditions: [],
Expand Down Expand Up @@ -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 };
}
Expand Down
8 changes: 8 additions & 0 deletions test/integration/suite/associations.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
});
});
});
11 changes: 0 additions & 11 deletions test/integration/suite/sharding.test.ts

This file was deleted.

0 comments on commit fc88a06

Please sign in to comment.