Module: QueryKit

Defined in:
lib/querykit.rb,
lib/querykit/query.rb,
lib/querykit/version.rb,
lib/querykit/connection.rb,
lib/querykit/repository.rb,
lib/querykit/case_builder.rb,
lib/querykit/delete_query.rb,
lib/querykit/insert_query.rb,
lib/querykit/update_query.rb,
lib/querykit/configuration.rb,
lib/querykit/adapters/adapter.rb,
lib/querykit/extensions/case_when.rb,
lib/querykit/adapters/mysql_adapter.rb,
lib/querykit/adapters/sqlite_adapter.rb,
lib/querykit/adapters/postgresql_adapter.rb

Overview

QueryKit is a lightweight, fluent query builder and micro-ORM for Ruby. It provides a clean, chainable API for building SQL queries without the overhead of Active Record.

Examples:

Basic usage

db = QueryKit.connect(:sqlite, database: 'app.db')
users = db.get(db.query('users').where('age', '>', 18))

Using repository pattern

class UserRepository < QueryKit::Repository
  table 'users'
  model User
end
repo = UserRepository.new(db)
user = repo.find(1)

Defined Under Namespace

Modules: Adapters, CaseWhenExtension Classes: CaseBuilder, Configuration, ConfigurationError, Connection, DeleteQuery, InsertQuery, Query, Repository, UpdateQuery

Constant Summary collapse

VERSION =
'0.1.0'

Class Method Summary collapse

Class Method Details

.configurationConfiguration

Get the global configuration instance

Returns:



51
52
53
# File 'lib/querykit/configuration.rb', line 51

def configuration
  @configuration ||= Configuration.new
end

.configure {|Configuration| ... } ⇒ void

This method returns an undefined value.

Configure QueryKit globally

Examples:

QueryKit.configure do |config|
  config.adapter = :sqlite
  config.connection_options = { database: 'db/app.db' }
end

Yields:



65
66
67
# File 'lib/querykit/configuration.rb', line 65

def configure
  yield(configuration) if block_given?
end

.connect(adapter_type, config) ⇒ Connection

Factory method for creating database connections

Examples:

SQLite connection

db = QueryKit.connect(:sqlite, database: 'app.db')
# or
db = QueryKit.connect(:sqlite, 'app.db')

PostgreSQL connection

db = QueryKit.connect(:postgresql, 
  host: 'localhost',
  database: 'myapp',
  user: 'postgres',
  password: 'secret'
)

MySQL connection

db = QueryKit.connect(:mysql,
  host: 'localhost',
  database: 'myapp',
  username: 'root',
  password: 'secret'
)

Parameters:

  • adapter_type (Symbol)

    The type of database adapter to use (:sqlite, :postgresql, :postgres, or :mysql)

  • config (Hash, String)

    Configuration for the adapter. For SQLite, can be a string path to the database file or a hash with :database key. For PostgreSQL/MySQL, should be a hash with connection parameters.

Returns:

  • (Connection)

    A new database connection instance

Raises:

  • (ArgumentError)

    if adapter_type is not supported



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/querykit.rb', line 73

def self.connect(adapter_type, config)
  adapter = case adapter_type
  when :sqlite
    Adapters::SQLiteAdapter.new(config)
  when :postgresql, :postgres
    Adapters::PostgreSQLAdapter.new(config)
  when :mysql
    Adapters::MySQLAdapter.new(config)
  else
    raise ArgumentError, "Unknown adapter type: #{adapter_type}. " \
                         "Supported types: :sqlite, :postgresql, :mysql"
  end

  Connection.new(adapter)
end

.connectionQueryKit::Connection

Note:

Thread-safety: The connection singleton creation is thread-safe, but individual database operations depend on the underlying adapter’s thread-safety. SQLite connections should not be shared across threads. For multi-threaded applications, create separate connections per thread using connect instead of using the global connection.

Get a connection using global configuration

Creates a singleton connection that is reused across calls. The connection is lazily initialized on first access.

Examples:

Single-threaded usage (safe)

QueryKit.setup(:sqlite, database: 'app.db')
db = QueryKit.connection
users = db.get(db.query('users'))

Multi-threaded usage (use separate connections)

threads = 10.times.map do
  Thread.new do
    # Create a new connection per thread
    db = QueryKit.connect(:sqlite, database: 'app.db')
    users = db.get(db.query('users'))
  end
end
threads.each(&:join)

Returns:

Raises:

See Also:



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/querykit/configuration.rb', line 119

def connection
  configuration.validate!
  
  # Thread-safe singleton initialization
  @connection_mutex ||= Mutex.new
  @connection_mutex.synchronize do
    @connection ||= begin
      # Normalize connection options for SQLite (expects string path)
      config = if configuration.adapter == :sqlite
        configuration.connection_options[:database] || configuration.connection_options
      else
        configuration.connection_options
      end
      
      connect(configuration.adapter, config)
    end
  end
end

.reset!void

Note:

This method is primarily intended for testing. In production, you typically configure once at application startup.

This method returns an undefined value.

Reset configuration (useful for testing)

Clears the global configuration and connection singleton.

Examples:

QueryKit.setup(:sqlite, database: 'test.db')
# ... tests ...
QueryKit.reset!
QueryKit.setup(:sqlite, database: 'other.db')


152
153
154
155
156
157
158
# File 'lib/querykit/configuration.rb', line 152

def reset!
  @connection_mutex&.synchronize do
    @connection = nil
  end
  @configuration = nil
  @connection_mutex = nil
end

.setup(adapter, options = {}) ⇒ void

Setup with parameters (alternative to configure block)

Setup with parameters (alternative to configure block)

Examples:

QueryKit.setup(:sqlite, database: 'db/app.db')
QueryKit.setup(:sqlite, database: 'db/app.db')

Parameters:

  • adapter (Symbol)

    the database adapter type (:sqlite, :postgresql, :mysql)

  • options (Hash) (defaults to: {})

    connection options specific to the adapter

  • adapter (Symbol)

    the database adapter type (:sqlite, :postgresql, :mysql)

  • options (Hash) (defaults to: {})

    connection options specific to the adapter

Returns:

  • (void)
  • (void)


85
86
87
# File 'lib/querykit/configuration.rb', line 85

def setup(adapter, options = {})
  configuration.setup(adapter, options)
end

.use_extensions(*extensions) ⇒ void

This method returns an undefined value.

Load extensions into QueryKit

Extensions are prepended to the Query class to allow method overrides and additional functionality. This enables opt-in features while keeping the core library minimal.

Examples:

Load single extension

require 'querykit/extensions/case_when'
QueryKit.use_extensions(QueryKit::CaseWhenExtension)

Load multiple extensions

QueryKit.use_extensions([QueryKit::CaseWhenExtension, MyCustomExtension])

Parameters:

  • extensions (Module, Array<Module>)

    One or more extension modules to load



105
106
107
108
109
# File 'lib/querykit.rb', line 105

def self.use_extensions(*extensions)
  extensions.flatten.each do |extension|
    Query.prepend(extension)
  end
end