database-model-generator 0.6.0 → 0.7.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c7a39c7334cf104518e8ecab58a57ea7baa2b34c4a12048b45b0df7d2cf56368
4
- data.tar.gz: 9bb0bd52e6de9ff30f54a609a5c96db968aac877cc00824ba789b3aa3c4eeff0
3
+ metadata.gz: f565ac034c268e0422b5da72e50d74cd527b14537a903999cb540a6d61cade81
4
+ data.tar.gz: c6472df0598d9118ec24ae8e9d44c81610b7c3aa2e02504054dcbdfffe1e3007
5
5
  SHA512:
6
- metadata.gz: 15c94ddcedc209de09dad9c27f2655a2d163e3df51bdb21051526cbbe60b0effa8569eeb5168de27f11845ddf4b39a68927b985619eac53196e154867bc26d30
7
- data.tar.gz: 5fe097a00ba3151aa4ab21048b245ee26163e19e26daa2a05fd24131355bc296823d7e40a5040563797ae0722d9aa15505072bf1f1e611e555133d2295cb3668
6
+ metadata.gz: e71a3140a6c228bd2e0bba38e2ce3fb316d1e864a5823afb673d5dc4aec4d6eb6a3f6fee87e6861faf3cdddc59cab372c15bfcd18b736ad77662dce34d2e5648
7
+ data.tar.gz: '09cf787750a59cff756ac3a2fae2f607fe6125ef5fcbb59dfe9395f4d79012fa29aa07093796910fe753854f82d084f47379cff22388f3e383719d989e1eb4ee'
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGES.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## 0.7.0 - 22-Dec-2025
2
+ * Added full PostgreSQL support via the pg gem.
3
+ * Created PostgreSQL generator implementation with all features.
4
+ * Added PostgreSQL Docker setup for testing.
5
+ * Added comprehensive PostgreSQL test suite.
6
+ * Updated documentation to include PostgreSQL examples.
7
+ * Added pg gem as development dependency.
8
+
9
+ ## 0.6.1 - 28-Jul-2025
10
+ * Added "datetime" field for validates_timeliness.
11
+ * Added validates_timeliness as a development dependency.
12
+
1
13
  ## 0.6.0 - 24-Jul-2025
2
14
  * Renamed from oracle-model-generator to database-model-generator.
3
15
  * Added enum support.
data/MANIFEST.md CHANGED
@@ -1,10 +1,38 @@
1
1
  CHANGES.md
2
2
  MANIFEST.md
3
3
  README.md
4
- oracle-model-generator.gemspec
4
+ LICENSE
5
+ database-model-generator.gemspec
6
+ Gemfile
5
7
  Rakefile
6
- bin/omg
8
+ bin/dmg
7
9
  certs/djberg96_pub.pem
8
- lib/oracle-model-generator.rb
10
+ lib/database_model_generator.rb
9
11
  lib/oracle/model/generator.rb
10
- test/test_oracle_model_generator.rb
12
+ lib/sqlserver/model/generator.rb
13
+ lib/postgresql/model/generator.rb
14
+ spec/spec_helper.rb
15
+ spec/oracle_model_generator_spec.rb
16
+ spec/postgresql_model_generator_spec.rb
17
+ spec/support/oracle_connection.rb
18
+ spec/support/postgresql_connection.rb
19
+ docker/oracle/docker-compose.yml
20
+ docker/oracle/Dockerfile
21
+ docker/oracle/README.md
22
+ docker/oracle/test.sh
23
+ docker/sqlserver/docker-compose.yml
24
+ docker/sqlserver/Dockerfile
25
+ docker/sqlserver/test-Dockerfile
26
+ docker/sqlserver/init-db.sql
27
+ docker/sqlserver/setup-db.sh
28
+ docker/sqlserver/run_tests.sh
29
+ docker/sqlserver/test.sh
30
+ docker/sqlserver/DOCKER.md
31
+ docker/sqlserver/SUPPORT.md
32
+ docker/sqlserver/TESTING.md
33
+ docker/postgresql/docker-compose.yml
34
+ docker/postgresql/Dockerfile
35
+ docker/postgresql/test-Dockerfile
36
+ docker/postgresql/init-db.sql
37
+ docker/postgresql/test.sh
38
+ docker/postgresql/README.md
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ## Description
2
2
  A library for generating an ActiveRecord model from an existing database table.
3
3
 
4
- Currently supports both Oracle and SQL Server databases.
4
+ Currently supports Oracle, SQL Server, and PostgreSQL databases.
5
5
 
6
6
  This will install a "dmg" (Database Model Generator) executable that you can
7
7
  use from the command line.
@@ -9,7 +9,7 @@ use from the command line.
9
9
  ## Renamed
10
10
  Originally called "oracle-model-generator" and put into the dust bin, I've
11
11
  decided to revive this library with the help of AI. Specifically, I've added
12
- SQLServer support, and plan to Postgres support.
12
+ SQLServer and PostgreSQL support, and plan to add more features.
13
13
 
14
14
  I also plan on lots of improvements, and some general refactoring.
15
15
 
@@ -22,9 +22,15 @@ Using the command line tool:
22
22
  ### SQL Server:
23
23
  `dmg -T sqlserver -s localhost -d your_database -t locations -u sa -p your_password`
24
24
 
25
+ ### PostgreSQL:
26
+ `dmg -T postgresql -h localhost -d your_database -t locations -u postgres [-p password]`
27
+
25
28
  ### Auto-detection:
26
- `dmg -d your_database -t locations -u some_user -p some_password` # Oracle (default)
27
- `dmg -s localhost -d your_database -t locations -u sa -p password` # SQL Server (detected)
29
+ # Oracle (default)
30
+ `dmg -d your_database -t locations -u some_user -p some_password`
31
+
32
+ # SQL Server (detected)
33
+ `dmg -s localhost -d your_database -t locations -u sa -p password`
28
34
 
29
35
  The above command results in a file called "location.rb". This is an
30
36
  ActiveRecord model declaration, with all validations, primary keys,
@@ -121,6 +127,9 @@ end
121
127
  ### SQLServer
122
128
  * tiny_tds
123
129
 
130
+ ### PostgreSQL
131
+ * pg
132
+
124
133
  ## Running the specs
125
134
  ### Oracle:
126
135
  Run `cd docker/oracle && docker-compose run --rm oracle-model-generator bundle exec rspec`.
@@ -131,6 +140,10 @@ with database client libraries.
131
140
  ### SQL Server:
132
141
  Run `cd docker/sqlserver && ./test.sh` to start SQL Server, then run tests.
133
142
 
143
+ ### PostgreSQL:
144
+ Run `cd docker/postgresql && docker-compose up -d postgres-db` to start PostgreSQL,
145
+ then run `docker-compose run --rm dmg_test` to execute tests.
146
+
134
147
  Again, no guarantees on MacOS.
135
148
 
136
149
  ## Optional Libraries
@@ -146,19 +159,23 @@ If you want date format validations, then you will need to install the
146
159
  ## Database Support
147
160
  * **Oracle**: Full support via ruby-oci8
148
161
  * **SQL Server**: Full support via tiny_tds
162
+ * **PostgreSQL**: Full support via pg
149
163
  * **Auto-detection**: Automatically detects database type based on connection parameters
150
164
 
151
165
  ## Author's Comments
152
166
  Originally focused only on Oracle, this library has been expanded to support
153
- SQL Server as well. The architecture now supports multiple database vendors,
154
- and I will probably add Postgres support in the future.
167
+ SQL Server and PostgreSQL as well. The architecture now supports multiple
168
+ database vendors, making it easy to add support for additional databases in
169
+ the future.
155
170
 
156
171
  ## Current Features
157
- * **Multi-database support**: Oracle and SQL Server
172
+ * **Multi-database support**: Oracle, SQL Server, and PostgreSQL
158
173
  * **Auto-detection**: Automatically detects database type
159
174
  * **Index recommendations**: Suggests optimal indexes for your tables
160
175
  * **Multiple test frameworks**: Supports test-unit, minitest, and rspec
161
- * **Docker support**: Complete Docker environments for testing both databases
176
+ * **Docker support**: Complete Docker environments for testing all databases
177
+ * **Enum detection**: Automatically detects enum columns from CHECK constraints
178
+ * **Polymorphic associations**: Identifies polymorphic relationship patterns
162
179
 
163
180
  ## Future Plans (originally)
164
181
  * Add support for views.
data/bin/dmg CHANGED
@@ -40,9 +40,9 @@ def help
40
40
  -u, --user => The username used to establish a connection to the database.
41
41
  -p, --password => The password used to establish a connection to the database.
42
42
  -d, --database => The name of the database to connect to.
43
- -s, --server => The database server hostname (for SQL Server).
44
- -P, --port => The database server port (default: 1433 for SQL Server).
45
- -T, --type => Database type: 'oracle' or 'sqlserver' (auto-detected if not specified).
43
+ -s, --server => The database server hostname (for SQL Server and PostgreSQL).
44
+ -P, --port => The database server port (default: 1433 for SQL Server, 5432 for PostgreSQL).
45
+ -T, --type => Database type: 'oracle', 'sqlserver', or 'postgresql' (auto-detected if not specified).
46
46
  -r, --rails => The version of rails you're using (2 or higher).
47
47
  -x, --tests => Generate tests using testunit, minitest or rspec.
48
48
  -c, --class => Class name for the generated table (optional)
@@ -55,13 +55,18 @@ def help
55
55
  SQL Server:
56
56
  dmg -T sqlserver -s localhost -P 1433 -d mydb -u sa -p password -t users
57
57
 
58
+ PostgreSQL (password optional):
59
+ dmg -T postgresql -s localhost -d mydb -u postgres -t users
60
+ dmg -T postgresql -s localhost -d mydb -u postgres -p password -t users
61
+
58
62
  Auto-detection (Oracle if no server specified, SQL Server if server specified):
59
63
  dmg -d localhost:1521/XE -u scott -p tiger -t users # Oracle
60
64
  dmg -s localhost -d mydb -u sa -p password -t users # SQL Server
61
65
 
62
- If no user or password are supplied, then the generator will attempt to glean that
63
- information using a combination of the database name and your .dbrc file.
64
- If that cannot be found, then an error is raised.
66
+ If no user is supplied, an error is raised. For PostgreSQL, password is optional
67
+ if pg_hba.conf is configured for trust authentication. For Oracle and SQL Server,
68
+ if no password is supplied, the generator will attempt to find credentials in your
69
+ .dbrc file using the dbi-dbrc library.
65
70
 
66
71
  If no output file is supplied then the file generated will match the name
67
72
  of the table, minus the 's' if present, with a .rb extension. This is lazy,
@@ -110,6 +115,7 @@ pass = opts['password']
110
115
 
111
116
  # Determine database type
112
117
  database_type = opts['type']&.downcase
118
+
113
119
  unless database_type
114
120
  if opts['server'] || opts['port']
115
121
  database_type = 'sqlserver'
@@ -118,24 +124,31 @@ unless database_type
118
124
  end
119
125
  end
120
126
 
121
- unless ['oracle', 'sqlserver'].include?(database_type)
122
- puts "Invalid database type: #{database_type}. Must be 'oracle' or 'sqlserver'."
127
+ unless ['postgresql', 'oracle', 'sqlserver'].include?(database_type)
128
+ puts "Invalid database type: #{database_type}. Must be 'oracle', 'sqlserver', or 'postgresql'."
123
129
  exit!
124
130
  end
125
131
 
126
- unless user && pass
132
+ unless user
133
+ puts "You must specify a user with the -u option."
134
+ exit!
135
+ end
136
+
137
+ # For PostgreSQL, password is optional (can use pg_hba.conf trust authentication)
138
+ # For Oracle and SQL Server, password is required unless using dbrc
139
+ unless pass || database_type == 'postgresql'
127
140
  begin
128
141
  dbrc = DBI::DBRC.new(opts['database'], user)
129
142
  user = dbrc.user
130
143
  pass = dbrc.passwd
131
144
  rescue NameError
132
- msg = "If you do not specify a username or password on the command line "
145
+ msg = "If you do not specify a password on the command line "
133
146
  msg << "then you must use the dbi-dbrc library and create a .dbrc file in "
134
147
  msg << "your home directory."
135
148
  puts msg
136
149
  exit!
137
150
  rescue DBI::DBRC::Error
138
- msg = "No user or password provided, and no dbrc entry found for '"
151
+ msg = "No password provided, and no dbrc entry found for '"
139
152
  msg << opts['database'] + "'."
140
153
  puts msg
141
154
  exit!
@@ -169,6 +182,20 @@ begin
169
182
  port: port.to_i,
170
183
  database: opts['database']
171
184
  )
185
+ when 'postgresql'
186
+ require 'pg'
187
+ server = opts['server'] || 'localhost'
188
+ port = opts['port'] || 5432
189
+
190
+ conn_params = {
191
+ host: server,
192
+ port: port.to_i,
193
+ dbname: opts['database'],
194
+ user: user
195
+ }
196
+ conn_params[:password] = pass if pass
197
+
198
+ connection = PG.connect(conn_params)
172
199
  end
173
200
  rescue LoadError => e
174
201
  case database_type
@@ -176,6 +203,8 @@ rescue LoadError => e
176
203
  puts "Oracle support requires the 'oci8' gem. Install with: gem install oci8"
177
204
  when 'sqlserver'
178
205
  puts "SQL Server support requires the 'tiny_tds' gem. Install with: gem install tiny_tds"
206
+ when 'postgresql'
207
+ puts "PostgreSQL support requires the 'pg' gem. Install with: gem install pg"
179
208
  end
180
209
  exit!
181
210
  rescue => e
@@ -312,6 +341,7 @@ File.open(ofile, 'w') do |fh|
312
341
  if rails == 2
313
342
  # Character fields, size
314
343
  omg.column_info.each{ |col|
344
+ next if omg.primary_keys.map(&:downcase).include?(col.name.downcase) # Skip primary keys
315
345
  data_type = col.data_type.to_s
316
346
  if ['char', 'varchar', 'varchar2'].include?(data_type)
317
347
  validation = "validates_size_of :#{col.name.downcase}, :maximum => #{col.data_size}"
@@ -324,6 +354,7 @@ File.open(ofile, 'w') do |fh|
324
354
 
325
355
  # Fields that must be present
326
356
  omg.column_info.each{ |col|
357
+ next if omg.primary_keys.map(&:downcase).include?(col.name.downcase) # Skip primary keys
327
358
  unless col.nullable?
328
359
  validation = "validates_presence_of :#{col.name.downcase}"
329
360
  fh.puts " #{validation}"
@@ -334,6 +365,7 @@ File.open(ofile, 'w') do |fh|
334
365
 
335
366
  # Numeric fields
336
367
  omg.column_info.each{ |col|
368
+ next if omg.primary_keys.map(&:downcase).include?(col.name.downcase) # Skip primary keys
337
369
  if col.data_type.to_s == 'number'
338
370
  max = ("9" * (col.precision - col.scale)).to_i
339
371
 
@@ -350,11 +382,12 @@ File.open(ofile, 'w') do |fh|
350
382
  else
351
383
  # Character fields, size
352
384
  omg.column_info.each{ |col|
385
+ next if omg.primary_keys.map(&:downcase).include?(col.name.downcase) # Skip primary keys
353
386
 
354
- data_type = col.data_type.to_s
387
+ data_type = col.data_type.to_s.downcase
355
388
 
356
389
  case data_type
357
- when 'char', 'varchar', 'varchar2'
390
+ when 'char', 'varchar', 'varchar2', 'character varying', 'text', 'bpchar'
358
391
  validation = "validates :#{col.name.downcase}, "
359
392
  validation << ":length => {:maximum => #{col.data_size}}"
360
393
 
@@ -369,26 +402,55 @@ File.open(ofile, 'w') do |fh|
369
402
  validation << format_str
370
403
  validation << ",\n :presence => #{!col.nullable?}" unless col.nullable?
371
404
  validation << "\n\n"
372
- when 'number'
373
- max = "9" * col.precision
374
- max.insert(col.precision - col.scale, ".") if col.scale > 0
405
+ when 'number', 'integer', 'bigint', 'smallint', 'numeric', 'decimal', 'real', 'double precision'
406
+ # For PostgreSQL numeric types
407
+ if ['integer', 'bigint', 'smallint'].include?(data_type)
408
+ # Integer types
409
+ max = case data_type
410
+ when 'smallint' then 32767
411
+ when 'integer' then 2147483647
412
+ when 'bigint' then 9223372036854775807
413
+ end
414
+
415
+ validation = "\n validates :#{col.name.downcase}"
416
+
417
+ unless col.nullable?
418
+ validation << ", :presence => #{!col.nullable?}"
419
+ end
375
420
 
376
- validation = "\n validates :#{col.name.downcase}"
421
+ if max
422
+ validation << ", :numericality => {"
423
+ validation << "\n :less_than_or_equal_to => #{max}, "
424
+ validation << "\n :greater_than_or_equal_to => -#{max},"
425
+ validation << "\n :only_integer => true"
426
+ validation << "\n }\n\n"
427
+ end
428
+ elsif data_type == 'number' || ['numeric', 'decimal', 'real', 'double precision'].include?(data_type)
429
+ # Oracle NUMBER or PostgreSQL decimal types
430
+ validation = "\n validates :#{col.name.downcase}"
377
431
 
378
- unless col.nullable?
379
- validation << ", :presence => #{!col.nullable?}"
380
- end
432
+ unless col.nullable?
433
+ validation << ", :presence => #{!col.nullable?}"
434
+ end
381
435
 
382
- unless max.empty?
383
- validation << ", :numericality => {"
384
- validation << "\n :less_than_or_equal_to => #{max}, "
385
- validation << "\n :greater_than_or_equal_to => -#{max}"
436
+ if col.respond_to?(:precision) && col.precision
437
+ max = "9" * col.precision
438
+ max.insert(col.precision - (col.scale || 0), ".") if col.scale && col.scale > 0
386
439
 
387
- if col.scale == 0
388
- validation << ",\n :only_integer => true"
389
- end
440
+ unless max.empty?
441
+ validation << ", :numericality => {"
442
+ validation << "\n :less_than_or_equal_to => #{max}, "
443
+ validation << "\n :greater_than_or_equal_to => -#{max}"
444
+
445
+ if col.scale == 0
446
+ validation << ",\n :only_integer => true"
447
+ end
390
448
 
391
- validation << "\n }\n\n"
449
+ validation << "\n }\n\n"
450
+ end
451
+ else
452
+ validation << ", :numericality => true\n\n"
453
+ end
392
454
  end
393
455
 
394
456
  end
@@ -402,19 +464,21 @@ File.open(ofile, 'w') do |fh|
402
464
 
403
465
  # Date fields
404
466
  omg.column_info.each{ |col|
405
- data_type = col.data_type.to_s
467
+ next if omg.primary_keys.map(&:downcase).include?(col.name.downcase) # Skip primary keys
468
+ data_type = col.data_type.to_s.downcase
406
469
 
407
- if ['date', 'time'].include?(data_type)
470
+ if ['date', 'time', 'datetime', 'timestamp', 'timestamp without time zone', 'timestamp with time zone', 'time without time zone', 'time with time zone'].include?(data_type)
408
471
  if data_type == 'date'
409
472
  validation = "validates_date :#{col.name.downcase}"
410
- end
411
-
412
- if data_type == 'timestamp'
473
+ elsif data_type =~ /^time/
413
474
  validation = "validates_time :#{col.name.downcase}"
475
+ elsif data_type =~ /timestamp|datetime/
476
+ validation = "validates_datetime :#{col.name.downcase}"
414
477
  end
415
478
 
416
479
  unless header_printed
417
480
  fh.puts " # Requires the validates_timeliness library"
481
+ header_printed = true
418
482
  end
419
483
 
420
484
  fh.puts " #{validation}"
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
 
3
3
  Gem::Specification.new do |spec|
4
4
  spec.name = 'database-model-generator'
5
- spec.version = '0.6.0'
5
+ spec.version = '0.7.0'
6
6
  spec.author = 'Daniel J. Berger'
7
7
  spec.license = 'Apache-2.0'
8
8
  spec.email = 'djberg96@gmail.com'
@@ -22,10 +22,15 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency('rspec', '~> 3.12')
23
23
  spec.add_development_dependency('ruby-oci8', '~> 2.2')
24
24
  spec.add_development_dependency('tiny_tds', '~> 3.2.1')
25
+ spec.add_development_dependency('pg', '~> 1.5')
26
+
27
+ # Again, I only set this as a development dependency mainly as a reminder.
28
+ # The version you need will depend on which version of Rails you're using.
29
+ spec.add_development_dependency('validates_timeliness')
25
30
 
26
31
  spec.description = <<-EOF
27
32
  The database-model-generator library allows you to generate an ActiveRecord
28
- model from an existing Oracle table or view, as well as automatically
29
- generate a baseline test file for test-unit or minitest.
33
+ model from an existing Oracle, SQL Server, or PostgreSQL table or view,
34
+ as well as automatically generate a baseline test file for test-unit or minitest.
30
35
  EOF
31
36
  end
@@ -0,0 +1,22 @@
1
+ FROM ruby:3.2-alpine
2
+
3
+ # Install build dependencies
4
+ RUN apk add --no-cache \
5
+ build-base \
6
+ postgresql-dev \
7
+ git
8
+
9
+ # Set working directory
10
+ WORKDIR /app
11
+
12
+ # Copy gemspec and Gemfile
13
+ COPY database-model-generator.gemspec Gemfile ./
14
+ COPY lib/database_model_generator.rb lib/
15
+
16
+ # Install Ruby dependencies
17
+ RUN bundle install
18
+
19
+ # Copy the rest of the application
20
+ COPY . .
21
+
22
+ CMD ["bundle", "exec", "rspec", "spec/postgresql_model_generator_spec.rb"]