Skip to content

Instantly share code, notes, and snippets.

@zmts
Last active November 13, 2020 01:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save zmts/753cb85a25e4aa365a1dc17d60d4f4c1 to your computer and use it in GitHub Desktop.
Save zmts/753cb85a25e4aa365a1dc17d60d4f4c1 to your computer and use it in GitHub Desktop.
Raw SQL query vs Query builders (Knex.js/Objection.js)

Raw SQL query vs Query builders (Knex.js/Objection.js)

Raw SQL

static async listPostsPublicRaw ({ offset, limit, filter = {} } = {}) {
    assert.integer(limit, { required: true, min: 10 })
    assert.integer(offset, { required: true, min: 0 })
    assert.validate(filter.blogId, BlogModel.schema.id, { required: true })
    assert.validate(filter.stackId, StackModel.schema.id)

    const countWithStackIdQuery = `
    SELECT COUNT("posts"."id")
    FROM "posts" FULL JOIN "stacks" ON "posts"."stackId" = "stacks"."id"
    WHERE "posts"."blogId" = ? AND "posts"."private" = false AND "stacks"."private" = false AND "posts"."isDraft" = false AND "posts"."stackId" = ?;
    `

    const countNoStackIdQuery = `
    SELECT COUNT("posts"."id")
    FROM "posts" FULL JOIN "stacks" ON "posts"."stackId" = "stacks"."id"
    WHERE "posts"."blogId" = ? AND "posts"."private" = false AND "stacks"."private" = false AND "posts"."isDraft" = false
    OR "posts"."blogId" = ? AND "posts"."private" = false AND "posts"."stackId" IS NULL AND "posts"."isDraft" = false;
    `

    const countQuery = filter.stackId ? [countWithStackIdQuery, [filter.blogId, filter.stackId]] : [countNoStackIdQuery, [filter.blogId, filter.blogId]]

    const postsWithStackIdQuery = `
    SELECT "posts".*
    FROM "posts" FULL JOIN "stacks" ON "posts"."stackId" = "stacks"."id"
    WHERE "posts"."blogId" = ? AND "posts"."private" = false AND "stacks"."private" = false AND "posts"."isDraft" = false AND "posts"."stackId" = ?
    ORDER BY "posts"."createdAt" DESC
    LIMIT ? OFFSET ?;`

    const postsNoStackIdQuery = `
    SELECT "posts".*
    FROM "posts" FULL JOIN "stacks" ON "posts"."stackId" = "stacks"."id"
    WHERE "posts"."blogId" = ? AND "posts"."private" = false AND "stacks"."private" = false AND "posts"."isDraft" = false
    OR "posts"."blogId" = ? AND "posts"."private" = false AND "posts"."stackId" IS NULL AND "posts"."isDraft" = false
    ORDER BY "posts"."createdAt" DESC
    LIMIT ? OFFSET ?;`

    const postsQuery = filter.stackId ? [postsWithStackIdQuery, [filter.blogId, filter.stackId, limit, offset]] : [postsNoStackIdQuery, [filter.blogId, filter.blogId, limit, offset]]

    const count = await this.knex().raw(...countQuery)
    const total = Number(count.rows[0].count)
    if (total) {
      const { rows } = await this.knex().raw(...postsQuery)
      return { results: rows, total }
    }

    return this.emptyPageResponse()
  }

Query builder

static async listPostsPublic ({ offset, limit, filter = {} } = {}) {
    assert.integer(offset, { required: true, min: 0 })
    assert.integer(limit, { required: true, min: 10 })
    assert.validate(filter.blogId, BlogModel.schema.id, { required: true })
    assert.validate(filter.stackId, StackModel.schema.id)

    const whereOptions = {
      'posts.blogId': filter.blogId,
      'posts.isDraft': false,
      'posts.private': false,
      'stacks.private': false,
      ...(filter.stackId && { 'posts.stackId': filter.stackId })
    }
    const orWhereOptions = filter.stackId ? {} : {
      'posts.blogId': filter.blogId,
      'posts.isDraft': false,
      'posts.private': false,
      'posts.stackId': null
    }

    const postsCount = await this.knexQuery()
      .count('posts.id')
      .fullOuterJoin('stacks', 'posts.stackId', 'stacks.id')
      .where(whereOptions)
      .orWhere(orWhereOptions)

    const total = Number(postsCount[0].count)

    if (total) {
      const [blog, posts] = await Promise.all([
        BlogDAO.baseGetById(Number(filter.blogId)),
        this.knexQuery()
          .select('posts.*')
          .fullOuterJoin('stacks', 'posts.stackId', 'stacks.id')
          .where(whereOptions)
          .orWhere(orWhereOptions)
          .orderBy('createdAt', 'desc')
          .offset(offset)
          .limit(limit)
      ])

      return {
        results: posts.map(post => ({ ...post, blog })),
        total
      }
    }

    return this.emptyPageResponse()
  }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment