Hone logo
Hone
Problems

Go Query Builder: Constructing SQL Queries Dynamically

Building SQL queries dynamically is a common task in many applications. This challenge asks you to implement a basic query builder in Go, allowing users to construct SQL queries programmatically. This is useful for creating flexible data access layers and avoiding manual string concatenation, which can be error-prone and vulnerable to SQL injection.

Problem Description

You are tasked with creating a QueryBuilder struct in Go that allows users to construct SQL queries in a fluent, chainable manner. The builder should support the following operations:

  • Select(fields ...string): Specifies the columns to select. Returns the builder for chaining.
  • From(table string): Specifies the table to select from. Returns the builder.
  • Where(condition string): Adds a WHERE clause to the query. Returns the builder.
  • OrderBy(field string, direction string): Adds an ORDER BY clause. direction should be either "ASC" or "DESC". Returns the builder.
  • Limit(limit int): Adds a LIMIT clause. Returns the builder.
  • Offset(offset int): Adds an OFFSET clause. Returns the builder.
  • Build(): Returns the constructed SQL query string.

The QueryBuilder should initialize with an empty query string. Each method should append the appropriate SQL fragment to the query string, ensuring proper formatting (e.g., spaces, commas). The Build() method should return the complete SQL query string.

Key Requirements:

  • The query builder should be chainable, allowing users to call methods sequentially.
  • The Build() method should return a valid SQL query string based on the operations performed.
  • Error handling is not required for this challenge (e.g., no validation of direction in OrderBy). Assume inputs are valid.
  • The query builder should handle cases where certain clauses are not added (e.g., calling Build() after only calling Select and From).

Examples

Example 1:

Input:
builder := QueryBuilder.New()
builder.Select("id", "name").From("users").Where("age > 25").OrderBy("name", "ASC").Limit(10).Offset(5).Build()
Output:
SELECT id, name FROM users WHERE age > 25 ORDER BY name ASC LIMIT 10 OFFSET 5
Explanation:
The builder constructs a query selecting 'id' and 'name' from the 'users' table, filtering where age is greater than 25, ordering by name in ascending order, limiting the result to 10 rows, and offsetting by 5 rows.

Example 2:

Input:
builder := QueryBuilder.New()
builder.Select("*").From("products").Build()
Output:
SELECT * FROM products
Explanation:
The builder constructs a query selecting all columns from the 'products' table.

Example 3: (Edge Case - No WHERE clause)

Input:
builder := QueryBuilder.New()
builder.Select("id", "product_name").From("inventory").OrderBy("product_name", "DESC").Build()
Output:
SELECT id, product_name FROM inventory ORDER BY product_name DESC
Explanation:
The builder constructs a query selecting 'id' and 'product_name' from the 'inventory' table, ordering by 'product_name' in descending order.  The absence of a `WHERE` clause is handled correctly.

Constraints

  • The SQL query string returned by Build() should be well-formatted and valid SQL.
  • The query builder should be implemented using a struct with methods.
  • The Select method can accept a variable number of field names.
  • The direction parameter in OrderBy is expected to be either "ASC" or "DESC" (no validation required).
  • The Limit and Offset parameters must be non-negative integers.

Notes

  • Consider using string concatenation to build the SQL query.
  • Think about how to handle the order of operations and ensure proper SQL syntax.
  • Focus on the core functionality of the query builder. Advanced features like joins, subqueries, or parameter binding are not required for this challenge.
  • Start with a basic implementation and gradually add more features.
  • The QueryBuilder.New() function should be a constructor function that returns a new initialized QueryBuilder struct.
Loading editor...
go