jackcess-rb 0.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 13808690cb806345d019bc40fbf8dbb4f26219b2671a33df8f8f490b86c02adc
4
+ data.tar.gz: fe077ca9129c8b22667f5bebc20da22da3312e9e06c4f7be54db368bc6398afc
5
+ SHA512:
6
+ metadata.gz: d68146bdbbb184ff3b10a854c760abb0cf2d854de97d6a8873837cb16e7d64895c488f7416f1f39e9377748869c3dfee8bbc86aa6d6b70fd2e8b55bb97b29607
7
+ data.tar.gz: ffae044f60f706949828e838065d319f797be6e1ee32644c8db9921df99ac1f8a2969330998270c95247dd7c790bdcfe0d0df82040e4cfedb968337a7e04fe21
data/CHANGELOG.md ADDED
@@ -0,0 +1,18 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-02-12
9
+
10
+ ### Added
11
+ - Initial release
12
+ - Support for opening and creating Access databases (.mdb and .accdb)
13
+ - CRUD operations on tables and rows
14
+ - Schema inspection (tables, columns, indexes)
15
+ - Type conversion between Java and Ruby types
16
+ - Idiomatic Ruby API wrapping Jackcess Java library
17
+ - Comprehensive test suite
18
+ - Documentation and examples
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Durable Programming LLC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,435 @@
1
+ # jackcess-rb
2
+
3
+ A JRuby interface to the Jackcess library for reading and writing Microsoft Access databases.
4
+
5
+ jackcess-rb provides a Ruby-friendly interface to the powerful [Jackcess](https://jackcess.healthmarketscience.com/) Java library, enabling programmatic interaction with Access database files (`.mdb` and `.accdb`) directly from JRuby. This gem is designed with Durable Programming principles: pragmatic solutions, sustainability, quality, and customer-centric development.
6
+
7
+ ## Features
8
+
9
+ - **Pure JRuby**: No native dependencies—runs on any platform with JRuby
10
+ - **Read and Write Access Databases**: Full support for both `.mdb` (Jet) and `.accdb` (ACE) formats
11
+ - **Idiomatic Ruby API**: Natural Ruby interface wrapping Jackcess's Java API
12
+ - **Table Operations**: Create, read, update, and delete tables and records
13
+ - **Schema Inspection**: Examine database structure, columns, indexes, and relationships
14
+ - **Type Safety**: Automatic conversion between Java and Ruby types
15
+
16
+ ## Quick Start
17
+
18
+ ```ruby
19
+ require 'jackcess'
20
+
21
+ # Open an existing database
22
+ db = Jackcess::Database.open('path/to/database.accdb')
23
+
24
+ # Read from a table
25
+ table = db.table('Customers')
26
+ table.each do |row|
27
+ puts "#{row['FirstName']} #{row['LastName']}"
28
+ end
29
+
30
+ # Add a new row
31
+ table.add_row(
32
+ 'FirstName' => 'Alice',
33
+ 'LastName' => 'Smith',
34
+ 'Email' => 'alice@example.com'
35
+ )
36
+
37
+ # Close the database
38
+ db.close
39
+ ```
40
+
41
+ ## Installation
42
+
43
+ ### Requirements
44
+
45
+ - **JRuby 9.3+**: This gem requires JRuby and will not run on MRI Ruby
46
+ - **Java 8+**: Jackcess requires Java 8 or higher
47
+
48
+ Verify your JRuby installation:
49
+
50
+ ```bash
51
+ jruby --version
52
+ # Expected: jruby 9.3.x (or higher)
53
+ ```
54
+
55
+ ### Install via Bundler (Recommended)
56
+
57
+ Add to your `Gemfile`:
58
+
59
+ ```ruby
60
+ gem 'jackcess-rb'
61
+ ```
62
+
63
+ Then run:
64
+
65
+ ```bash
66
+ bundle install
67
+ ```
68
+
69
+ ### Install via gem
70
+
71
+ ```bash
72
+ gem install jackcess-rb
73
+ ```
74
+
75
+ ## Usage
76
+
77
+ ### Opening and Closing Databases
78
+
79
+ ```ruby
80
+ require 'jackcess'
81
+
82
+ # Open an existing database
83
+ db = Jackcess::Database.open('data/northwind.accdb')
84
+
85
+ # Work with the database
86
+ # ...
87
+
88
+ # Always close when done
89
+ db.close
90
+
91
+ # Or use block form for automatic cleanup
92
+ Jackcess::Database.open('data/northwind.accdb') do |db|
93
+ # Database automatically closed when block exits
94
+ end
95
+ ```
96
+
97
+ ### Reading Data
98
+
99
+ ```ruby
100
+ # Access a table
101
+ table = db.table('Products')
102
+
103
+ # Iterate through all rows
104
+ table.each do |row|
105
+ puts "Product: #{row['ProductName']}, Price: #{row['UnitPrice']}"
106
+ end
107
+
108
+ # Get specific row by ID
109
+ row = table.find_by_id(42)
110
+
111
+ # Access column values
112
+ name = row['ProductName']
113
+ price = row['UnitPrice']
114
+ ```
115
+
116
+ ### Writing Data
117
+
118
+ ```ruby
119
+ table = db.table('Products')
120
+
121
+ # Add a new row
122
+ table.add_row(
123
+ 'ProductName' => 'Widget',
124
+ 'UnitPrice' => 19.99,
125
+ 'UnitsInStock' => 100
126
+ )
127
+
128
+ # Update an existing row
129
+ row = table.find_by_id(42)
130
+ row['UnitPrice'] = 24.99
131
+ row.save
132
+
133
+ # Delete a row
134
+ row.delete
135
+ ```
136
+
137
+ ### Creating Tables
138
+
139
+ ```ruby
140
+ # Create a new table with columns
141
+ db.create_table('Orders') do |t|
142
+ t.column 'OrderID', :long, auto_number: true
143
+ t.column 'CustomerID', :long
144
+ t.column 'OrderDate', :date_time
145
+ t.column 'ShipAddress', :text, length: 255
146
+ t.column 'Total', :double
147
+
148
+ t.primary_key 'OrderID'
149
+ end
150
+ ```
151
+
152
+ ### Schema Inspection
153
+
154
+ ```ruby
155
+ # List all tables
156
+ db.table_names.each do |name|
157
+ puts "Table: #{name}"
158
+ end
159
+
160
+ # Inspect table structure
161
+ table = db.table('Customers')
162
+
163
+ puts "Columns:"
164
+ table.columns.each do |col|
165
+ puts " #{col.name} (#{col.type})"
166
+ end
167
+
168
+ puts "Indexes:"
169
+ table.indexes.each do |idx|
170
+ puts " #{idx.name}: #{idx.columns.join(', ')}"
171
+ end
172
+ ```
173
+
174
+ ### Transaction Management
175
+
176
+ ```ruby
177
+ # Explicit transaction control
178
+ db.transaction do
179
+ table = db.table('Accounts')
180
+
181
+ from_account = table.find_by_id(1)
182
+ to_account = table.find_by_id(2)
183
+
184
+ from_account['Balance'] -= 100
185
+ to_account['Balance'] += 100
186
+
187
+ from_account.save
188
+ to_account.save
189
+
190
+ # Automatically committed if no exception
191
+ # Automatically rolled back on exception
192
+ end
193
+ ```
194
+
195
+ ## API Documentation
196
+
197
+ ### `Jackcess::Database`
198
+
199
+ Main entry point for database operations.
200
+
201
+ #### Class Methods
202
+
203
+ - `Database.open(path, options = {})` → `Database`
204
+ - Opens an existing database file
205
+ - Options:
206
+ - `:readonly` (Boolean): Open in read-only mode (default: `false`)
207
+ - `:auto_sync` (Boolean): Auto-sync changes to disk (default: `true`)
208
+ - Returns: `Database` instance
209
+ - Block form: Automatically closes database when block exits
210
+
211
+ - `Database.create(path, format = :v2000)` → `Database`
212
+ - Creates a new database file
213
+ - Formats: `:v2000` (.mdb), `:v2003` (.mdb), `:v2007` (.accdb), `:v2010` (.accdb)
214
+
215
+ #### Instance Methods
216
+
217
+ - `#table(name)` → `Table`
218
+ - Access a table by name
219
+
220
+ - `#table_names` → `Array<String>`
221
+ - Returns array of all table names
222
+
223
+ - `#create_table(name, &block)` → `Table`
224
+ - Create a new table with schema defined in block
225
+
226
+ - `#close`
227
+ - Close the database connection
228
+
229
+ ### `Jackcess::Table`
230
+
231
+ Represents a table in the database.
232
+
233
+ #### Instance Methods
234
+
235
+ - `#each(&block)` → `Enumerator`
236
+ - Iterate through all rows
237
+
238
+ - `#find_by_id(id)` → `Row`
239
+ - Find row by primary key value
240
+
241
+ - `#add_row(data)` → `Row`
242
+ - Add a new row with given data (Hash)
243
+
244
+ - `#columns` → `Array<Column>`
245
+ - Returns array of column definitions
246
+
247
+ - `#indexes` → `Array<Index>`
248
+ - Returns array of indexes
249
+
250
+ ### `Jackcess::Row`
251
+
252
+ Represents a single row/record in a table.
253
+
254
+ #### Instance Methods
255
+
256
+ - `#[](column_name)` → `Object`
257
+ - Get column value
258
+
259
+ - `#[]=(column_name, value)`
260
+ - Set column value
261
+
262
+ - `#save`
263
+ - Save changes to the database
264
+
265
+ - `#delete`
266
+ - Delete this row from the table
267
+
268
+ See [API Documentation](https://rubydoc.info/gems/jackcess-rb) for complete reference.
269
+
270
+ ## Type Mapping
271
+
272
+ jackcess-rb automatically converts between Access/Java types and Ruby types:
273
+
274
+ | Access Type | Ruby Type | Notes |
275
+ |-------------|-----------|-------|
276
+ | TEXT | String | Variable length text |
277
+ | MEMO | String | Long text fields |
278
+ | BYTE | Integer | 8-bit integer |
279
+ | INT | Integer | 16-bit integer |
280
+ | LONG | Integer | 32-bit integer |
281
+ | FLOAT | Float | Single precision |
282
+ | DOUBLE | Float | Double precision |
283
+ | CURRENCY | BigDecimal | Fixed-point decimal |
284
+ | DATE_TIME | Time | Date and time |
285
+ | BOOLEAN | Boolean | true/false |
286
+ | BINARY | String (binary) | Binary data |
287
+ | GUID | String | UUID/GUID strings |
288
+
289
+ ## Design Principles
290
+
291
+ jackcess-rb is built following Durable Programming principles:
292
+
293
+ ### Pragmatic Problem-Solving
294
+
295
+ - Solves real-world need: accessing Access databases without Windows
296
+ - Focuses on common use cases first
297
+ - Provides escape hatches to underlying Jackcess API when needed
298
+ - No unnecessary abstractions—just enough Ruby idioms for comfort
299
+
300
+ ### Sustainability and Longevity
301
+
302
+ - Built on mature, well-maintained Jackcess library
303
+ - Minimal dependencies (JRuby + Jackcess only)
304
+ - Clear separation between Ruby API and Java interop
305
+ - Designed for long-term maintenance
306
+
307
+ ### Quality and Reliability
308
+
309
+ - Comprehensive test coverage
310
+ - Type-safe conversions between Ruby and Java
311
+ - Proper resource management (automatic cleanup)
312
+ - Error handling with meaningful messages
313
+
314
+ ### Customer-Centric
315
+
316
+ - Developer experience prioritized
317
+ - Idiomatic Ruby API
318
+ - Clear documentation with practical examples
319
+ - Progressive disclosure: simple things simple, complex things possible
320
+
321
+ ### Transparency
322
+
323
+ - Open source (MIT license)
324
+ - Clear documentation of capabilities and limitations
325
+ - Honest about JRuby requirement
326
+ - Links to underlying Jackcess documentation
327
+
328
+ ## Architecture
329
+
330
+ jackcess-rb provides a thin Ruby wrapper around the Jackcess Java library:
331
+
332
+ ```
333
+ ┌─────────────────────────────────────┐
334
+ │ Ruby Application Code │
335
+ ├─────────────────────────────────────┤
336
+ │ jackcess-rb (Ruby API) │
337
+ │ - Idiomatic Ruby interface │
338
+ │ - Type conversions │
339
+ │ - Resource management │
340
+ ├─────────────────────────────────────┤
341
+ │ JRuby Bridge │
342
+ ├─────────────────────────────────────┤
343
+ │ Jackcess Java Library │
344
+ │ - Access file format handling │
345
+ │ - Database operations │
346
+ ├─────────────────────────────────────┤
347
+ │ Access Database Files │
348
+ │ (.mdb, .accdb) │
349
+ └─────────────────────────────────────┘
350
+ ```
351
+
352
+ The gem focuses on:
353
+ - Ruby-friendly method names and conventions
354
+ - Automatic type conversions
355
+ - Block-based resource management
356
+ - Iterator patterns for large datasets
357
+
358
+ ## Performance Considerations
359
+
360
+ - **Memory**: Large tables are iterated lazily—only current row in memory
361
+ - **Transactions**: Batch operations in transactions for better performance
362
+ - **Indexes**: Use indexed columns for lookups when possible
363
+ - **File Format**: `.accdb` (v2007+) generally faster than `.mdb` for large databases
364
+
365
+ ## Limitations
366
+
367
+ - **JRuby Only**: This gem requires JRuby and will not work with MRI Ruby
368
+ - **File-Based**: Jackcess works with Access files directly, not via ODBC/ADO
369
+ - **Access Features**: Some advanced Access features (forms, reports, VBA) are not accessible
370
+ - **Concurrent Access**: Limited support for multiple processes accessing same file simultaneously
371
+
372
+ ## Contributing
373
+
374
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for:
375
+ - Development setup
376
+ - Running tests
377
+ - Code style guidelines
378
+ - Pull request process
379
+
380
+ ## Testing
381
+
382
+ ```bash
383
+ # Run the test suite
384
+ bundle exec rake test
385
+
386
+ # Run specific test file
387
+ bundle exec ruby test/database_test.rb
388
+ ```
389
+
390
+ ## Troubleshooting
391
+
392
+ ### "Java::JavaLang::UnsupportedClassVersionError"
393
+
394
+ Your Java version is too old. Jackcess requires Java 8+.
395
+
396
+ ```bash
397
+ java -version
398
+ # Should show 1.8.0 or higher
399
+ ```
400
+
401
+ ### "Cannot find Java library 'jackcess'"
402
+
403
+ The Jackcess JAR is missing. Reinstall the gem:
404
+
405
+ ```bash
406
+ gem uninstall jackcess-rb
407
+ gem install jackcess-rb
408
+ ```
409
+
410
+ ### "Database format not supported"
411
+
412
+ The Access file format may be too old or corrupted. Try:
413
+ - Opening in Access and saving as newer format (.accdb)
414
+ - Using Access's "Compact and Repair Database" feature
415
+
416
+ ## License
417
+
418
+ [MIT License](LICENSE)
419
+
420
+ ## Support
421
+
422
+ - **Documentation**: [https://rubydoc.info/gems/jackcess-rb](https://rubydoc.info/gems/jackcess-rb)
423
+ - **Issues**: [GitHub Issues](https://github.com/durableprogramming/jackcess-rb/issues)
424
+ - **Jackcess Documentation**: [https://jackcess.healthmarketscience.com/](https://jackcess.healthmarketscience.com/)
425
+ - **Email**: commercial@durableprogramming.com
426
+
427
+ ## Credits
428
+
429
+ jackcess-rb is developed by [Durable Programming LLC](https://durableprogramming.com).
430
+
431
+ Built on the [Jackcess](https://jackcess.healthmarketscience.com/) library by Health Market Science.
432
+
433
+ ## Changelog
434
+
435
+ See [CHANGELOG.md](CHANGELOG.md) for version history and release notes.
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jackcess
4
+ class Column
5
+ attr_reader :java_column
6
+
7
+ def initialize(java_column)
8
+ @java_column = java_column
9
+ end
10
+
11
+ # Get column name
12
+ def name
13
+ @java_column.get_name
14
+ end
15
+
16
+ # Get column type as Ruby symbol
17
+ def type
18
+ TypeConverter.data_type_to_ruby_type(@java_column.get_type)
19
+ end
20
+
21
+ # Get column SQL type
22
+ def sql_type
23
+ @java_column.get_sql_type
24
+ end
25
+
26
+ # Get column length
27
+ def length
28
+ @java_column.get_length
29
+ end
30
+
31
+ # Check if column is auto-number
32
+ def auto_number?
33
+ @java_column.is_auto_number
34
+ end
35
+
36
+ # Check if column is variable length
37
+ def variable_length?
38
+ @java_column.is_variable_length
39
+ end
40
+
41
+ # Get column properties
42
+ def properties
43
+ {
44
+ name: name,
45
+ type: type,
46
+ sql_type: sql_type,
47
+ length: length,
48
+ auto_number: auto_number?,
49
+ variable_length: variable_length?
50
+ }
51
+ end
52
+
53
+ def inspect
54
+ "#<Jackcess::Column name=#{name.inspect} type=#{type.inspect}>"
55
+ end
56
+
57
+ def to_s
58
+ "#{name} (#{type})"
59
+ end
60
+ end
61
+ end