Class: Jackcess::Database

Inherits:
Object
  • Object
show all
Defined in:
lib/jackcess/database.rb

Overview

Represents a Microsoft Access database file (.mdb or .accdb).

This class provides the main entry point for interacting with Access databases through the Jackcess library. It supports opening existing databases, creating new ones, and managing tables within the database.

Examples:

Open an existing database

db = Jackcess::Database.open('path/to/database.accdb')
db.table_names
# => ["Customers", "Orders", "Products"]
db.close

Create a new database with block

Jackcess::Database.create('new.accdb', :v2007) do |db|
  db.create_table('Users') do |t|
    t.column 'ID', :long, auto_number: true
    t.column 'Name', :text, length: 255
    t.primary_key 'ID'
  end
end # Database automatically closed

Defined Under Namespace

Classes: TableBuilderDSL

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(java_database) ⇒ Database

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates a new Database instance wrapping a Java database object. This method is typically not called directly; use open or create instead.

Parameters:

  • java_database (Java::ComHealthmarketscienceJackcess::Database)

    The Java database object



34
35
36
37
# File 'lib/jackcess/database.rb', line 34

def initialize(java_database)
  @java_database = java_database
  @closed = false
end

Instance Attribute Details

#java_databaseJava::ComHealthmarketscienceJackcess::Database (readonly)

The underlying Java database object from Jackcess

Returns:

  • (Java::ComHealthmarketscienceJackcess::Database)


27
28
29
# File 'lib/jackcess/database.rb', line 27

def java_database
  @java_database
end

Class Method Details

.create(path, format = :v2000) {|db| ... } ⇒ Database

Creates a new Access database file.

This method creates a new Microsoft Access database file in the specified format. If a block is given, the database will be automatically closed when the block exits.

Examples:

Create a database without block

db = Jackcess::Database.create('new.accdb', :v2007)
# ... work with database ...
db.close

Create a database with block (auto-close)

Jackcess::Database.create('new.accdb', :v2007) do |db|
  db.create_table('Products') do |t|
    t.column 'ID', :long, auto_number: true
    t.column 'Name', :text, length: 255
    t.primary_key 'ID'
  end
end # Database automatically closed

Parameters:

  • path (String)

    The file path for the new database

  • format (Symbol) (defaults to: :v2000)

    The Access file format (:v2000, :v2003, :v2007, or :v2010)

Yields:

  • (db)

    Passes the database to the block

Yield Parameters:

  • db (Database)

    The created database

Yield Returns:

  • (Object)

    The return value of the block (with block form)

Returns:

  • (Database)

    A new Database instance (without block)

Raises:

  • (ArgumentError)

    If path is nil, empty, not a String, or format is invalid

  • (DatabaseError)

    If the database cannot be created



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/jackcess/database.rb', line 132

def self.create(path, format = :v2000)
  raise ArgumentError, "Database path cannot be nil" if path.nil?
  raise ArgumentError, "Database path must be a String" unless path.is_a?(String)
  raise ArgumentError, "Database path cannot be empty" if path.empty?
  raise ArgumentError, "Database format cannot be nil" if format.nil?

  path = File.expand_path(path)

  begin
    file_format = case format
                  when :v2000
                    com.healthmarketscience.jackcess.Database::FileFormat::V2000
                  when :v2003
                    com.healthmarketscience.jackcess.Database::FileFormat::V2003
                  when :v2007
                    com.healthmarketscience.jackcess.Database::FileFormat::V2007
                  when :v2010
                    com.healthmarketscience.jackcess.Database::FileFormat::V2010
                  else
                    raise DatabaseError, "Unknown database format: #{format}. Valid formats are: :v2000, :v2003, :v2007, :v2010"
                  end

    java_db = DatabaseBuilder.create(file_format, java.io.File.new(path))
    db = new(java_db)

    if block_given?
      begin
        yield db
      ensure
        db.close
      end
    else
      db
    end
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to create database '#{path}': #{e.message}"
  rescue Java::JavaLang::Exception => e
    raise DatabaseError, "Failed to create database '#{path}': #{e.message}"
  end
end

.open(path, options = {}) {|db| ... } ⇒ Database

Opens an existing Access database file.

This method opens an existing Microsoft Access database file (.mdb or .accdb) for reading and/or writing. If a block is given, the database will be automatically closed when the block exits, even if an exception is raised.

Examples:

Open database without block

db = Jackcess::Database.open('data/northwind.accdb')
# ... work with database ...
db.close

Open database with block (auto-close)

Jackcess::Database.open('data/northwind.accdb') do |db|
  puts db.table_names
end # Database automatically closed

Open in read-only mode

db = Jackcess::Database.open('data/northwind.accdb', readonly: true)

Parameters:

  • path (String)

    The file path to the database

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

    Optional configuration

Options Hash (options):

  • :readonly (Boolean) — default: false

    Open the database in read-only mode

  • :auto_sync (Boolean) — default: true

    Automatically sync changes to disk

Yields:

  • (db)

    Passes the database to the block

Yield Parameters:

Yield Returns:

  • (Object)

    The return value of the block (with block form)

Returns:

  • (Database)

    A new Database instance (without block)

Raises:

  • (ArgumentError)

    If path is nil, empty, or not a String

  • (DatabaseError)

    If the file doesn’t exist, is a directory, or cannot be opened



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/jackcess/database.rb', line 70

def self.open(path, options = {})
  raise ArgumentError, "Database path cannot be nil" if path.nil?
  raise ArgumentError, "Database path must be a String" unless path.is_a?(String)
  raise ArgumentError, "Database path cannot be empty" if path.empty?

  path = File.expand_path(path)
  raise DatabaseError, "Database file not found: #{path}" unless File.exist?(path)
  raise DatabaseError, "Path is a directory, not a file: #{path}" if File.directory?(path)

  begin
    builder = DatabaseBuilder.new(java.io.File.new(path))
    builder.set_read_only(options[:readonly]) if options.key?(:readonly)
    builder.set_auto_sync(options[:auto_sync]) if options.key?(:auto_sync)

    java_db = builder.open
    db = new(java_db)

    if block_given?
      begin
        yield db
      ensure
        db.close
      end
    else
      db
    end
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to open database '#{path}': #{e.message}"
  rescue Java::JavaLang::Exception => e
    raise DatabaseError, "Failed to open database '#{path}': #{e.message}"
  end
end

Instance Method Details

#closenil

Closes the database and flushes any pending changes to disk.

After calling this method, the database cannot be used. Calling close on an already-closed database is safe and will not raise an error.

Examples:

Close a database

db = Jackcess::Database.open('data.accdb')
# ... work with database ...
db.close

Returns:

  • (nil)

Raises:

  • (DatabaseError)

    If an error occurs during the close operation



305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/jackcess/database.rb', line 305

def close
  return if @closed

  begin
    @java_database.close
    @closed = true
  rescue Java::JavaIo::IOException => e
    # Log the error but mark as closed to prevent further operations
    @closed = true
    raise DatabaseError, "Failed to close database cleanly: #{e.message}"
  end
end

#closed?Boolean

Checks whether the database has been closed.

Examples:

Check if database is closed

db = Jackcess::Database.open('data.accdb')
db.closed? # => false
db.close
db.closed? # => true

Returns:

  • (Boolean)

    true if the database is closed, false otherwise



327
328
329
# File 'lib/jackcess/database.rb', line 327

def closed?
  @closed
end

#create_table(name) {|t| ... } ⇒ Table

Creates a new table in the database.

This method uses a DSL (Domain-Specific Language) for defining the table schema. The block receives a table builder object that supports column and primary_key methods.

Examples:

Create a simple table

table = db.create_table('Users') do |t|
  t.column 'ID', :long, auto_number: true
  t.column 'Name', :text, length: 255
  t.column 'Email', :text, length: 255
  t.column 'CreatedAt', :date_time
  t.primary_key 'ID'
end

Parameters:

  • name (String, Symbol)

    The name for the new table

Yields:

  • (t)

    Passes a table builder to the block for defining columns

Yield Parameters:

Returns:

  • (Table)

    The newly created table

Raises:

  • (ArgumentError)

    If name is nil, empty, or not a String/Symbol

  • (DatabaseError)

    If the database is closed or table cannot be created

See Also:



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/jackcess/database.rb', line 246

def create_table(name, &block)
  check_closed!
  raise ArgumentError, "Table name cannot be nil" if name.nil?
  raise ArgumentError, "Table name must be a String or Symbol" unless name.is_a?(String) || name.is_a?(Symbol)
  raise ArgumentError, "Table name cannot be empty" if name.to_s.empty?

  begin
    builder = TableBuilder.new(name)
    table_builder = TableBuilderDSL.new(builder)
    table_builder.instance_eval(&block) if block_given?

    java_table = builder.to_table(@java_database)
    Table.new(java_table, self)
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to create table '#{name}': #{e.message}"
  rescue Java::JavaLang::Exception => e
    raise DatabaseError, "Failed to create table '#{name}': #{e.message}"
  end
end

#flushnil

Flushes any pending changes to disk.

This method forces all buffered changes to be written to the database file. It’s generally not necessary to call this manually unless you need to ensure changes are persisted immediately.

Examples:

Flush changes

db = Jackcess::Database.open('data.accdb')
# ... make changes ...
db.flush # Ensure changes are written to disk

Returns:

  • (nil)

Raises:



345
346
347
348
349
350
351
352
353
# File 'lib/jackcess/database.rb', line 345

def flush
  check_closed!

  begin
    @java_database.flush
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to flush database: #{e.message}"
  end
end

#table(name) ⇒ Table

Retrieves a table by name from the database.

Examples:

Get a table

table = db.table('Customers')
puts table.name # => "Customers"

Parameters:

  • name (String, Symbol)

    The name of the table to retrieve

Returns:

  • (Table)

    The requested table

Raises:

  • (ArgumentError)

    If name is nil or not a String/Symbol

  • (TableNotFoundError)

    If the table doesn’t exist

  • (DatabaseError)

    If the database is closed or table cannot be accessed



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/jackcess/database.rb', line 186

def table(name)
  check_closed!
  raise ArgumentError, "Table name cannot be nil" if name.nil?
  raise ArgumentError, "Table name must be a String or Symbol" unless name.is_a?(String) || name.is_a?(Symbol)

  name = name.to_s
  begin
    java_table = @java_database.get_table(name)
    raise TableNotFoundError, "Table not found: #{name}" if java_table.nil?

    Table.new(java_table, self)
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to access table '#{name}': #{e.message}"
  end
end

#table_namesArray<String>

Returns a sorted array of all table names in the database.

Examples:

List all tables

db.table_names
# => ["Customers", "Orders", "Products"]

Returns:

  • (Array<String>)

    Sorted array of table names

Raises:

  • (DatabaseError)

    If the database is closed or table names cannot be retrieved



211
212
213
214
215
216
217
218
219
# File 'lib/jackcess/database.rb', line 211

def table_names
  check_closed!

  begin
    @java_database.get_table_names.to_a.sort
  rescue Java::JavaIo::IOException => e
    raise DatabaseError, "Failed to get table names: #{e.message}"
  end
end

#transaction { ... } ⇒ Object

Executes a block within a transaction context.

Note: Jackcess doesn’t have explicit ACID transaction support like traditional databases. This method provides a semantic grouping for operations and will wrap exceptions in DatabaseError. For true atomicity, consider implementing checkpointing or using database-level features if available.

Examples:

Execute a transaction

db.transaction do
  table = db.table('Accounts')
  # Perform multiple operations
end

Yields:

  • The block of operations to execute

Raises:

  • (DatabaseError)

    If the database is closed or if an error occurs during the transaction



282
283
284
285
286
287
288
289
290
# File 'lib/jackcess/database.rb', line 282

def transaction
  check_closed!

  # Note: Jackcess doesn't have explicit transaction support like traditional databases
  # This is a placeholder for future enhancement
  yield
rescue StandardError => e
  raise DatabaseError, "Transaction failed: #{e.message}"
end