activemdb 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +5 -0
- data/README.txt +23 -9
- data/Rakefile +1 -1
- data/db/.DS_Store +0 -0
- data/db/not_an_mdb.txt +0 -0
- data/db/retreat.mdb +0 -0
- data/lib/active_mdb.rb +3 -2
- data/lib/active_mdb/base.rb +126 -0
- data/lib/active_mdb/column.rb +39 -2
- data/lib/active_mdb/mdb.rb +16 -6
- data/lib/active_mdb/mdb_tools.rb +54 -12
- data/test/test_activemdb.rb +55 -0
- data/test/test_base.rb +86 -0
- data/test/test_helper.rb +3 -1
- data/test/test_mdb.rb +3 -10
- data/test/test_mdb_tools.rb +38 -2
- data/test/test_record.rb +24 -24
- data/test/test_table.rb +50 -50
- metadata +10 -4
data/Manifest.txt
CHANGED
@@ -2,9 +2,13 @@ History.txt
|
|
2
2
|
Manifest.txt
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
|
+
db/.DS_Store
|
6
|
+
db/not_an_mdb.txt
|
7
|
+
db/retreat.mdb
|
5
8
|
db/sample.mdb
|
6
9
|
irb.rc
|
7
10
|
lib/active_mdb.rb
|
11
|
+
lib/active_mdb/base.rb
|
8
12
|
lib/active_mdb/column.rb
|
9
13
|
lib/active_mdb/mdb.rb
|
10
14
|
lib/active_mdb/mdb_tools.rb
|
@@ -12,6 +16,7 @@ lib/active_mdb/record.rb
|
|
12
16
|
lib/active_mdb/table.rb
|
13
17
|
support/a.insert
|
14
18
|
test/test_activemdb.rb
|
19
|
+
test/test_base.rb
|
15
20
|
test/test_helper.rb
|
16
21
|
test/test_mdb.rb
|
17
22
|
test/test_mdb_tools.rb
|
data/README.txt
CHANGED
@@ -4,24 +4,38 @@ http://rubyforge.org/projects/activemdb/
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
|
7
|
+
Library for getting info out of MS Access (.mdb) files, which uses ActiveRecord-ish reflection to parse table and column names.
|
8
8
|
|
9
|
-
Intended for exploration and migration, not production. ActiveMDB provides a
|
9
|
+
Intended for exploration and migration, not production. And it's *READ ONLY*, so don't try to get fresh. ActiveMDB provides a wrapper of varying thickness around the utilities from Brian Bruns's MDB Tools project (http://mdbtools.sourceforge.net/). Kudos to Mr. Bruns.
|
10
10
|
|
11
11
|
== FEATURES/PROBLEMS:
|
12
12
|
|
13
|
-
*
|
14
|
-
*
|
13
|
+
* MDBTools - Straightforward wrapper around the CLI tools that you get with libmdb
|
14
|
+
* ActiveMDB::Base - Subclass to make your models, just like the big shots do.
|
15
|
+
|
15
16
|
|
16
17
|
== SYNOPSIS:
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
# When your Access database schema conforms to the 37s stylebook:
|
20
|
+
class Bacon < ActiveMDB::Base
|
21
|
+
set_mdb_file 'db/wherefore.mdb'
|
22
|
+
end
|
20
23
|
|
21
24
|
# in the find_* methods, the entries in the hash
|
22
25
|
# get turned into "WHERE #{key} like %#{value}%" conditions,
|
23
|
-
#
|
24
|
-
|
26
|
+
# which fails when the column is a boolean, which is a regression from 0.1.0.
|
27
|
+
# I could fix this tonight, but my son is yelling at me to come out for dinner.
|
28
|
+
best_bacon = Bacon.find_all(:rind => 'creamy', :sodium_content => 'Awesome!' )
|
29
|
+
|
30
|
+
# When it doesn't:
|
31
|
+
class Employee < ActiveMDB::Base
|
32
|
+
set_mdb_file 'db/sample.mdb'
|
33
|
+
set_table_name 'Employee'
|
34
|
+
set_primary_key 'Emp_Id'
|
35
|
+
end
|
36
|
+
|
37
|
+
paula = Employee.find_first(:Department => 'Engineering', :Specialty => 'paulaBeans')
|
38
|
+
|
25
39
|
|
26
40
|
== REQUIREMENTS:
|
27
41
|
|
@@ -29,7 +43,7 @@ Intended for exploration and migration, not production. ActiveMDB provides a thi
|
|
29
43
|
|
30
44
|
== INSTALL:
|
31
45
|
|
32
|
-
* Sadly, no easy install at this time.
|
46
|
+
* Sadly, no easy install of MDB Tools at this time. It compiles on Mac OS X 10.4.x, both PPC and Intel. Haven't tested on Linuxes yet, but that's what Parallels is for, right?
|
33
47
|
|
34
48
|
== LICENSE:
|
35
49
|
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.new('activemdb', ActiveMDB::VERSION) do |p|
|
|
8
8
|
p.rubyforge_name = 'activemdb'
|
9
9
|
p.author = 'Matthew King'
|
10
10
|
p.email = 'automatthew@gmail.com'
|
11
|
-
p.summary = '
|
11
|
+
p.summary = 'ActiveRecordy wrapper around MDB Tools, which lets POSIX platforms read MS Access (.mdb) files'
|
12
12
|
p.description = p.paragraphs_of('README.txt', 2).join("\n\n")
|
13
13
|
p.url = p.paragraphs_of('README.txt',0).first.split(/\n/)[2..-1]
|
14
14
|
# p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
data/db/.DS_Store
ADDED
Binary file
|
data/db/not_an_mdb.txt
ADDED
File without changes
|
data/db/retreat.mdb
ADDED
Binary file
|
data/lib/active_mdb.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__))
|
2
2
|
module ActiveMDB
|
3
|
-
VERSION = '0.
|
3
|
+
VERSION = '0.2.0'
|
4
4
|
end
|
5
5
|
|
6
6
|
|
7
7
|
require 'rubygems'
|
8
|
-
require 'active_support
|
8
|
+
require 'active_support'
|
9
9
|
require 'active_mdb/mdb_tools'
|
10
10
|
load 'active_mdb/mdb.rb'
|
11
11
|
load 'active_mdb/table.rb'
|
12
12
|
load 'active_mdb/record.rb'
|
13
13
|
load 'active_mdb/column.rb'
|
14
|
+
load 'active_mdb/base.rb'
|
14
15
|
require 'faster_csv'
|
15
16
|
|
16
17
|
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module ActiveMDB
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(attributes=nil)
|
5
|
+
@attributes = attributes unless attributes.nil?
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
cattr_accessor :pluralize_table_names, :instance_writer => false
|
11
|
+
@@pluralize_table_names = true
|
12
|
+
|
13
|
+
class << self # Class methods
|
14
|
+
attr_accessor :mdb_file
|
15
|
+
attr_reader :mdb
|
16
|
+
|
17
|
+
def set_mdb_file(file)
|
18
|
+
@mdb_file = file
|
19
|
+
@mdb = MDB.new(file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def table_name
|
23
|
+
table_name = Inflector.underscore(Inflector.demodulize(self.to_s))
|
24
|
+
table_name = Inflector.pluralize(table_name) if pluralize_table_names
|
25
|
+
table_name
|
26
|
+
end
|
27
|
+
|
28
|
+
# borrowed from ActiveRecord
|
29
|
+
def set_table_name(value = nil, &block)
|
30
|
+
define_attr_method :table_name, value, &block
|
31
|
+
end
|
32
|
+
alias :table_name= :set_table_name
|
33
|
+
|
34
|
+
# Returns an array of column objects for the table associated with this class.
|
35
|
+
def columns
|
36
|
+
unless @columns
|
37
|
+
@columns = @mdb.columns(table_name)
|
38
|
+
# @columns.each {|column| column.primary = column.name == primary_key}
|
39
|
+
end
|
40
|
+
@columns
|
41
|
+
end
|
42
|
+
|
43
|
+
def column_names
|
44
|
+
@mdb.column_names(table_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def primary_key
|
48
|
+
'id'
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_primary_key(value = nil, &block)
|
52
|
+
define_attr_method :primary_key, value, &block
|
53
|
+
end
|
54
|
+
alias :primary_key= :set_primary_key
|
55
|
+
|
56
|
+
def table_exists?
|
57
|
+
@mdb.tables.include? table_name
|
58
|
+
end
|
59
|
+
|
60
|
+
def count
|
61
|
+
@mdb.count(table_name, primary_key)
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_first(conditions_hash)
|
65
|
+
# rekey_hash(conditions_hash)
|
66
|
+
sql_search(conditions_hash).first
|
67
|
+
end
|
68
|
+
|
69
|
+
def find_all(conditions_hash)
|
70
|
+
sql_search(conditions_hash)
|
71
|
+
end
|
72
|
+
|
73
|
+
# borrowed from ActiveRecord
|
74
|
+
def define_attr_method(name, value=nil, &block)
|
75
|
+
sing = class << self; self; end
|
76
|
+
sing.send :alias_method, "original_#{name}", name
|
77
|
+
if block_given?
|
78
|
+
sing.send :define_method, name, &block
|
79
|
+
else
|
80
|
+
# use eval instead of a block to work around a memory leak in dev
|
81
|
+
# mode in fcgi
|
82
|
+
sing.class_eval "def #{name}; #{value.to_s.inspect}; end"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# relies on stuff that doesn't work right now
|
87
|
+
def rekey_hash(conditions_hash)
|
88
|
+
conditions_hash.each do |key,value|
|
89
|
+
column = self[key.to_s]
|
90
|
+
if column.boolean?
|
91
|
+
key = column.name + '!'
|
92
|
+
else
|
93
|
+
key = column.name
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# the conditions hash keys are column names, the values are search values
|
99
|
+
# e.g. sql_search(:first_name => 'Matthew', :last_name => 'King')
|
100
|
+
def sql_search(conditions_hash)
|
101
|
+
conditions = MDBTools.compile_conditions(conditions_hash)
|
102
|
+
MDBTools.sql_select(mdb_file, table_name, nil, conditions).collect! { |record| instantiate(record) }
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def instantiate(record)
|
108
|
+
new(record)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
def method_missing(method_id, *args, &block)
|
117
|
+
method_name = method_id.to_s
|
118
|
+
if @attributes.include?(method_name)
|
119
|
+
value = @attributes[method_name]
|
120
|
+
else
|
121
|
+
super
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
data/lib/active_mdb/column.rb
CHANGED
@@ -4,14 +4,51 @@ class Column
|
|
4
4
|
attr_reader :method_name, :name, :type, :size
|
5
5
|
|
6
6
|
def initialize(name, type, size)
|
7
|
-
@name = name
|
8
|
-
@method_name, @
|
7
|
+
@name, @type = name, type
|
8
|
+
@method_name, @size = methodize(name), size.to_i
|
9
9
|
end
|
10
10
|
|
11
11
|
def self.new_from_describe(describe_hash)
|
12
12
|
self.new(describe_hash["Column Name"], describe_hash["Type"], describe_hash["Size"])
|
13
13
|
end
|
14
14
|
|
15
|
+
# return Ruby class corresponding to data type.
|
16
|
+
# Borrowed from ActiveRecord
|
17
|
+
def klass
|
18
|
+
case type
|
19
|
+
when 'Text', 'Character' then String
|
20
|
+
when 'Long Integer' then Fixnum
|
21
|
+
when 'Currency', 'Float' then Float
|
22
|
+
when 'DateTime (Short)' then Time
|
23
|
+
when 'Boolean' then Object
|
24
|
+
when 'Decimal' then BigDecimal
|
25
|
+
when 'Binary' then String
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Casts value (which is a String) to an appropriate instance.
|
30
|
+
# Totally borrowed from ActiveRecord
|
31
|
+
def type_cast(value)
|
32
|
+
return nil if value.nil?
|
33
|
+
case type
|
34
|
+
when 'Text', 'Character' then value
|
35
|
+
when 'Long Integer' then value.to_i rescue value ? 1 : 0
|
36
|
+
when 'Currency', 'Float' then value.to_f
|
37
|
+
when 'DateTime (Short)' then self.class.string_to_time(value)
|
38
|
+
when 'Boolean' then self.class.value_to_boolean(value)
|
39
|
+
when 'Decimal' then self.class.value_to_decimal(value)
|
40
|
+
when 'Binary' then self.class.binary_to_string(value)
|
41
|
+
else value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.value_to_boolean(value)
|
46
|
+
if value == true || value == false
|
47
|
+
value
|
48
|
+
else
|
49
|
+
%w(true t 1).include?(value.to_s.downcase)
|
50
|
+
end
|
51
|
+
end
|
15
52
|
|
16
53
|
def boolean?
|
17
54
|
self.type == 'boolean'
|
data/lib/active_mdb/mdb.rb
CHANGED
@@ -3,25 +3,35 @@
|
|
3
3
|
class MDB
|
4
4
|
include MDBTools
|
5
5
|
|
6
|
-
attr_reader :mdb_file, :prefix, :exclude, :
|
6
|
+
attr_reader :mdb_file, :prefix, :exclude, :tables
|
7
7
|
|
8
8
|
def initialize(mdb_file, options = {})
|
9
9
|
@mdb_file = check_file(mdb_file)
|
10
10
|
@prefix = options[:prefix] || ''
|
11
11
|
@exclude, @include = options[:exclude], options[:include]
|
12
12
|
@export_syntax = options[:sql_syntax] || 'mysql'
|
13
|
-
@
|
14
|
-
@tables = create_table_objects
|
13
|
+
@tables = mdb_tables(@mdb_file, :exclude => @exclude, :include => @include)
|
14
|
+
# @tables = create_table_objects
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def count(table_name, attribute)
|
18
|
+
MDBTools.faked_count(@mdb_file, table_name, attribute)
|
19
19
|
end
|
20
20
|
|
21
|
+
def columns(table_name)
|
22
|
+
MDBTools.describe_table(@mdb_file, table_name).map do |column|
|
23
|
+
Column.new_from_describe(column)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def column_names(table_name)
|
28
|
+
MDBTools.field_names_for(@mdb_file, table_name)
|
29
|
+
end
|
21
30
|
|
22
31
|
|
23
32
|
private
|
24
|
-
|
33
|
+
|
34
|
+
# Deprecated.
|
25
35
|
def create_table_objects
|
26
36
|
tables = {}
|
27
37
|
@table_names.each do |table|
|
data/lib/active_mdb/mdb_tools.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module MDBTools
|
2
|
-
|
2
|
+
|
3
|
+
extend self
|
3
4
|
|
4
5
|
DELIMITER = '::'
|
5
6
|
LINEBREAK = "\n"
|
@@ -15,6 +16,14 @@ module MDBTools
|
|
15
16
|
mdb_file
|
16
17
|
end
|
17
18
|
|
19
|
+
def valid_file?(file)
|
20
|
+
!mdb_version(file).blank?
|
21
|
+
end
|
22
|
+
|
23
|
+
def mdb_version(file)
|
24
|
+
`mdb-ver #{file} 2> /dev/null`.chomp
|
25
|
+
end
|
26
|
+
|
18
27
|
def check_table(mdb_file, table_name)
|
19
28
|
unless mdb_tables(mdb_file).include?(table_name)
|
20
29
|
raise ArgumentError, "mdbtools does not think a table named \"#{table_name}\" exists"
|
@@ -22,6 +31,7 @@ module MDBTools
|
|
22
31
|
table_name
|
23
32
|
end
|
24
33
|
|
34
|
+
|
25
35
|
def mdb_tables(mdb_file, options = {})
|
26
36
|
included, excluded = options[:include], options[:exclude]
|
27
37
|
return `mdb-tables -1 #{mdb_file}`.split(LINEBREAK) if not (included || excluded)
|
@@ -37,19 +47,49 @@ module MDBTools
|
|
37
47
|
tables
|
38
48
|
end
|
39
49
|
|
40
|
-
def sql_select(mdb_file, table_name, attributes = nil, conditions
|
41
|
-
attributes
|
42
|
-
|
50
|
+
def sql_select(mdb_file, table_name, attributes = nil, conditions=nil)
|
51
|
+
if attributes.respond_to?(:join)
|
52
|
+
fields = attributes.join(' ')
|
53
|
+
else
|
54
|
+
attributes ||= '*'
|
55
|
+
end
|
56
|
+
where = conditions ? "where #{conditions}" : ""
|
57
|
+
sql = "select #{attributes} from #{table_name} #{where}"
|
43
58
|
mdb_sql(mdb_file, sql)
|
44
59
|
end
|
45
60
|
|
61
|
+
def mdb_sql(mdb_file,sql)
|
62
|
+
command = "mdb-sql -Fp -d '#{DELIMITER}' #{mdb_file}\n"
|
63
|
+
array = []
|
64
|
+
IO.popen(command, 'r+') do |pipe|
|
65
|
+
pipe << "#{sql}\ngo\n"
|
66
|
+
pipe.close_write
|
67
|
+
pipe.readline
|
68
|
+
fields = pipe.readline.chomp.split(DELIMITER)
|
69
|
+
pipe.each do |row|
|
70
|
+
hash = {}
|
71
|
+
row = row.chomp.split(DELIMITER)
|
72
|
+
fields.each_index do |i|
|
73
|
+
hash[fields[i]] = row[i]
|
74
|
+
end
|
75
|
+
array << hash
|
76
|
+
end
|
77
|
+
end
|
78
|
+
array
|
79
|
+
end
|
46
80
|
|
47
|
-
def
|
48
|
-
# puts sql
|
81
|
+
def old_mdb_sql(mdb_file, sql)
|
49
82
|
result = `echo -n #{sql} | mdb-sql -Fp -H -d '#{DELIMITER}' #{mdb_file}`.strip
|
50
|
-
|
83
|
+
delimited_to_arrays(result)
|
84
|
+
end
|
85
|
+
|
86
|
+
def field_names_for(mdb_file, table)
|
87
|
+
fields = `echo -n 'select * from #{table} where 1 = 2' | mdb-sql -Fp -d '#{DELIMITER}' #{mdb_file}`.chomp.sub(/^\n+/, '')
|
88
|
+
fields.split(DELIMITER)
|
51
89
|
end
|
52
90
|
|
91
|
+
|
92
|
+
|
53
93
|
def compile_conditions(conditions_hash, *args)
|
54
94
|
conditions = conditions_hash.sort_by{|k,v| k.to_s}.map do |column_name, value|
|
55
95
|
if block_given?
|
@@ -60,6 +100,10 @@ module MDBTools
|
|
60
100
|
end.join(' AND ')
|
61
101
|
end
|
62
102
|
|
103
|
+
def faked_count(*args)
|
104
|
+
sql_select(*args).size
|
105
|
+
end
|
106
|
+
|
63
107
|
def mdb_export(mdb_file, table_name, options = {})
|
64
108
|
defaults = { :format => 'sql',
|
65
109
|
:headers => false,
|
@@ -83,10 +127,8 @@ module MDBTools
|
|
83
127
|
end
|
84
128
|
|
85
129
|
def describe_table(mdb_file, table_name)
|
86
|
-
command = "describe table \"#{table_name}\""
|
87
|
-
|
88
|
-
arrays = delimited_to_arrays(description)
|
89
|
-
arrays_to_hashes(arrays.shift, arrays)
|
130
|
+
command = "describe table \"#{table_name}\""
|
131
|
+
mdb_sql(mdb_file,command)
|
90
132
|
end
|
91
133
|
|
92
134
|
def mdb_schema(mdb_file, table_name)
|
@@ -118,7 +160,7 @@ module MDBTools
|
|
118
160
|
|
119
161
|
|
120
162
|
def methodize(table_name)
|
121
|
-
underscore table_name
|
163
|
+
Inflector.underscore table_name
|
122
164
|
end
|
123
165
|
|
124
166
|
def backends
|
data/test/test_activemdb.rb
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
|
5
|
+
class RealWorldTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
RETREAT = File.join(File.dirname(__FILE__), '..', 'db', 'retreat.mdb')
|
8
|
+
|
9
|
+
class Family < ActiveMDB::Base
|
10
|
+
set_mdb_file RETREAT
|
11
|
+
set_table_name 'tblFamilyData'
|
12
|
+
end
|
13
|
+
|
14
|
+
class Cabin < ActiveMDB::Base
|
15
|
+
set_mdb_file RETREAT
|
16
|
+
set_table_name 'tCabins'
|
17
|
+
end
|
18
|
+
|
19
|
+
def setup
|
20
|
+
@retreat = MDB.new(RETREAT)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_tables
|
24
|
+
tables = ["JobAssignmentsByCabin","Switchboard Items","tblAdultChildCode","tblCities","tblFamilyData","tblGender","tblIndividData","tblStatusChurch","tblStatusIndiv","tCabinAssignments","tCabins","tCampRates","tCampScholarships","tJobs","tJobsR","tParkAreas","tPayments","tRetreatEnrollment","tSponsors","tblStatusFamily"]
|
25
|
+
assert_equal tables, @retreat.tables
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_column_names
|
29
|
+
column_names = ["FamKey","LName", "HisName", "HerName", "HmAddress", "AddressNumber", "StreetDirection", "StreetName", "HmAddress2", "City", "State", "Zip", "HmPhone", "UnLstHmPho?"]
|
30
|
+
assert_equal column_names, Family.column_names
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_columns
|
34
|
+
column = Family.columns[2]
|
35
|
+
assert_kind_of Column, column
|
36
|
+
assert_respond_to column, 'type'
|
37
|
+
assert_respond_to column, 'name'
|
38
|
+
assert_respond_to column, 'size'
|
39
|
+
Family.columns.each do |c|
|
40
|
+
assert_not_nil c.name
|
41
|
+
assert_not_nil c.type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_column_klass
|
46
|
+
column = Family.columns[1]
|
47
|
+
assert_equal String, column.klass
|
48
|
+
Family.columns.each do |c|
|
49
|
+
assert_not_nil c.klass
|
50
|
+
assert_kind_of Class, c.klass
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
end
|
data/test/test_base.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
|
5
|
+
class BaseTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
class NonExistentTable < ActiveMDB::Base
|
8
|
+
set_mdb_file TEST_DB
|
9
|
+
end
|
10
|
+
class Employee < ActiveMDB::Base
|
11
|
+
set_mdb_file TEST_DB
|
12
|
+
set_table_name 'Employee'
|
13
|
+
set_primary_key 'Emp_Id'
|
14
|
+
end
|
15
|
+
class Room < ActiveMDB::Base
|
16
|
+
set_mdb_file TEST_DB
|
17
|
+
set_table_name 'Room'
|
18
|
+
set_primary_key 'Room'
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
def test_setting_mdb_file
|
24
|
+
assert_equal TEST_DB, Employee.mdb_file
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_mdb_creation
|
28
|
+
mdb = Employee.mdb
|
29
|
+
assert_not_nil mdb
|
30
|
+
assert_respond_to mdb, :tables
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_get_table_name
|
34
|
+
assert_equal 'non_existent_tables', NonExistentTable.table_name
|
35
|
+
ActiveMDB::Base.pluralize_table_names = false
|
36
|
+
assert_equal 'non_existent_table', NonExistentTable.table_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_set_table_name
|
40
|
+
Employee.set_table_name('foo')
|
41
|
+
assert_equal 'foo', Employee.table_name
|
42
|
+
assert_equal 'Room', Room.table_name
|
43
|
+
Employee.set_table_name('Employee')
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_table_exists
|
47
|
+
assert !NonExistentTable.table_exists?
|
48
|
+
assert Room.table_exists?
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_get_and_set_primary_key
|
52
|
+
assert_equal 'Emp_Id', Employee.primary_key
|
53
|
+
Employee.set_primary_key 'employee_id'
|
54
|
+
assert_equal 'employee_id', Employee.primary_key
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_count
|
58
|
+
assert_equal 92, Room.count
|
59
|
+
assert_equal 53, Employee.count
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_instantiate
|
63
|
+
hash = [{"Department"=>"Engineering", "Gender"=>"M", "Room"=>"6072", "Title"=>"Programmer", "Emp_Id"=>"1045", "First_Name"=>"Robert", "Last_Name"=>"Weinfeld"}]
|
64
|
+
record = Employee.send(:instantiate, hash)
|
65
|
+
assert_equal hash, record.instance_variable_get('@attributes')
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_sql_search
|
69
|
+
record = Employee.sql_search(:Room => '6072').first
|
70
|
+
assert_kind_of Employee, record
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_attribute_magic
|
74
|
+
record = Employee.sql_search(:Room => '6072').first
|
75
|
+
assert_equal '6072', record.Room
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def test_find_all
|
80
|
+
assert_equal 2, Employee.find_all(:First_Name => 'G').size
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'test/unit'
|
2
|
+
TEST_DB = File.join(File.dirname(__FILE__), '..', 'db', 'sample.mdb')
|
3
|
+
NOT_A_DB = File.join(File.dirname(__FILE__), '..', 'db', 'not_an_mdb.txt')
|
2
4
|
|
3
5
|
class Test::Unit::TestCase
|
4
6
|
|
5
|
-
TEST_DB = File.join(File.dirname(__FILE__), '..', 'db', 'sample.mdb')
|
6
7
|
|
7
8
|
|
8
9
|
protected
|
@@ -11,6 +12,7 @@ class Test::Unit::TestCase
|
|
11
12
|
excluded = options[:exclude]
|
12
13
|
included = options[:include]
|
13
14
|
assert_nothing_raised { @db = MDB.new(TEST_DB, :exclude => excluded, :include => included ) }
|
15
|
+
assert_not_nil @db
|
14
16
|
end
|
15
17
|
|
16
18
|
end
|
data/test/test_mdb.rb
CHANGED
@@ -3,8 +3,6 @@ require 'test/unit'
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
4
|
|
5
5
|
class MDBTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
6
|
|
9
7
|
def setup
|
10
8
|
|
@@ -12,20 +10,15 @@ class MDBTest < Test::Unit::TestCase
|
|
12
10
|
|
13
11
|
def test_table_exclusion
|
14
12
|
create_mdb(:exclude => ['Inventory'])
|
15
|
-
assert !@db.
|
13
|
+
assert !@db.tables.include?('Inventory')
|
16
14
|
end
|
17
15
|
|
18
16
|
def test_table_inclusion
|
19
17
|
create_mdb(:include => ['Inventory', 'Room'])
|
20
|
-
assert_equal ['Inventory', 'Room'], @db.
|
18
|
+
assert_equal ['Inventory', 'Room'], @db.tables.sort
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
create_mdb
|
25
|
-
assert_respond_to @db, 'computer'
|
26
|
-
assert_respond_to @db, 'employee'
|
27
|
-
assert_respond_to @db, 'room'
|
28
|
-
end
|
21
|
+
|
29
22
|
|
30
23
|
|
31
24
|
|
data/test/test_mdb_tools.rb
CHANGED
@@ -28,6 +28,16 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
28
28
|
assert_raise(ArgumentError) { check_file README}
|
29
29
|
end
|
30
30
|
|
31
|
+
def test_valid_file
|
32
|
+
assert valid_file?(TEST_DB)
|
33
|
+
assert !valid_file?(NOT_A_DB)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_mdb_version
|
37
|
+
assert_equal 'JET3', mdb_version(TEST_DB)
|
38
|
+
assert_equal '', mdb_version(NOT_A_DB)
|
39
|
+
end
|
40
|
+
|
31
41
|
def test_check_table
|
32
42
|
assert_nothing_raised { check_table TEST_DB, 'Employee'}
|
33
43
|
assert_raises(ArgumentError) { check_table TEST_DB, 'foobarbaz' }
|
@@ -59,6 +69,28 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
59
69
|
assert_match /DROP TABLE/, @schema
|
60
70
|
end
|
61
71
|
|
72
|
+
def test_describe_table
|
73
|
+
descriptions = describe_table(TEST_DB, 'Employee')
|
74
|
+
assert_kind_of Array, descriptions
|
75
|
+
assert_kind_of Hash, descriptions.first
|
76
|
+
assert_equal 3, descriptions.first.size
|
77
|
+
assert_not_nil descriptions.first['Type']
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_mdb_sql
|
81
|
+
result = [{"Department"=>"Human Resources", "Gender"=>"F", "Room"=>"6150", "Title"=>"Vice President", "Emp_Id"=>"1025", "First_Name"=>"Kathy", "Last_Name"=>"Ragerie"}]
|
82
|
+
assert_equal result, mdb_sql(TEST_DB, "select * from Employee where Room = '6150'")
|
83
|
+
bees = mdb_sql(TEST_DB, "select * from Employee where Last_Name like 'B%'")
|
84
|
+
assert_kind_of Array, bees
|
85
|
+
b = bees.first
|
86
|
+
assert_kind_of Hash, b
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_field_names_for
|
90
|
+
fields = ["Last_Name","First_Name", "Gender", "Title", "Department", "Room", "Emp_Id"]
|
91
|
+
assert_equal fields, field_names_for(TEST_DB, 'Employee')
|
92
|
+
end
|
93
|
+
|
62
94
|
|
63
95
|
# def test_csv_to_hashes
|
64
96
|
# employee_hash = csv_to_hashes(@employees_csv)
|
@@ -66,8 +98,8 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
66
98
|
# end
|
67
99
|
|
68
100
|
def test_sql_select
|
69
|
-
|
70
|
-
|
101
|
+
yo = {"Department"=>"Engineering", "Gender"=>"F", "Room"=>"6044", "Title"=>"Programmer", "Emp_Id"=>"1000", "First_Name"=>"Yolanda", "Last_Name"=>"Torbati"}
|
102
|
+
assert_equal yo, sql_select(TEST_DB, 'Employee', ['*'], "First_Name LIKE 'Yolanda'" ).first
|
71
103
|
end
|
72
104
|
|
73
105
|
def test_compile_conditions
|
@@ -79,6 +111,10 @@ class MDBToolsTest < Test::Unit::TestCase
|
|
79
111
|
sql_select(TEST_DB, 'Employee', nil, compile_conditions(:first_name => 'Yolanda'))
|
80
112
|
end
|
81
113
|
|
114
|
+
def test_count
|
115
|
+
assert_equal 92, faked_count(TEST_DB, 'Room', 'Room', nil)
|
116
|
+
end
|
117
|
+
|
82
118
|
def test_export_table_to_sql
|
83
119
|
# this test is dependent on specific content in the sample database
|
84
120
|
export = mdb_export(TEST_DB, 'Computer', :format => 'sql').split(LINEBREAK)
|
data/test/test_record.rb
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
-
|
5
|
-
class RecordTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
1
|
+
# require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
# require 'test/unit'
|
3
|
+
# require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
#
|
5
|
+
# class RecordTest < Test::Unit::TestCase
|
6
|
+
#
|
7
|
+
# def setup
|
8
|
+
# create_mdb
|
9
|
+
# @employee = @db.employee
|
10
|
+
# @line = ["Torbati","Yolanda", "F", "Programmer", "Engineering", "6044", "1000"]
|
11
|
+
# assert_nothing_raised { @record = Record.new(@employee, @line) }
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def test_reflection
|
15
|
+
# assert_respond_to @record, 'gender'
|
16
|
+
# assert_respond_to @record, 'emp_id'
|
17
|
+
# assert_equal 'Yolanda', @record.first_name
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def test_display
|
21
|
+
#
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# end
|
data/test/test_table.rb
CHANGED
@@ -1,50 +1,50 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
-
|
5
|
-
class TableTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
1
|
+
# require File.join(File.dirname(__FILE__), "..", 'lib', 'active_mdb')
|
2
|
+
# require 'test/unit'
|
3
|
+
# require File.join(File.dirname(__FILE__), 'test_helper')
|
4
|
+
#
|
5
|
+
# class TableTest < Test::Unit::TestCase
|
6
|
+
#
|
7
|
+
#
|
8
|
+
# def setup
|
9
|
+
# create_mdb
|
10
|
+
# @employee = @db.employee
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# def test_columns
|
14
|
+
# columns = @employee.columns
|
15
|
+
# assert_kind_of Array, columns
|
16
|
+
# assert_kind_of Column, columns.first
|
17
|
+
# assert_equal 7, columns.size
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def test_create_record_struct
|
21
|
+
# assert_kind_of Class, @employee.record_struct
|
22
|
+
# members = @employee.record_struct.members
|
23
|
+
# assert_equal 7, members.size
|
24
|
+
# assert members.include?('emp_id')
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def test_to_csv
|
28
|
+
# csv_text = @employee.to_csv
|
29
|
+
# assert_kind_of String, csv_text
|
30
|
+
# arrays = csv_text.split(MDBTools::LINEBREAK)
|
31
|
+
#
|
32
|
+
# # grab the headers and test for content
|
33
|
+
# assert arrays.shift.include?('Emp_Id')
|
34
|
+
# assert_equal 53, arrays.size
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# def test_find_first
|
38
|
+
# y = @employee.find_first(:first_name => 'Yolanda')
|
39
|
+
# assert_kind_of Record, y
|
40
|
+
# assert_equal 'Yolanda', y.first_name
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# def test_find_all
|
44
|
+
# a_names = @employee.find_all(:last_name => 'A')
|
45
|
+
# assert_kind_of Array, a_names
|
46
|
+
# assert_kind_of Record, a_names.first
|
47
|
+
# assert_equal 2, a_names.size
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
metadata
CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activemdb
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
8
|
-
summary:
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-04-05 00:00:00 -05:00
|
8
|
+
summary: ActiveRecordy wrapper around MDB Tools, which lets POSIX platforms read MS Access (.mdb) files
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: automatthew@gmail.com
|
12
12
|
homepage: http://rubyforge.org/projects/activemdb/
|
13
13
|
rubyforge_project: activemdb
|
14
|
-
description: Intended for exploration and migration, not production. ActiveMDB provides a
|
14
|
+
description: Intended for exploration and migration, not production. And it's *READ ONLY*, so don't try to get fresh. ActiveMDB provides a wrapper of varying thickness around the utilities from Brian Bruns's MDB Tools project (http://mdbtools.sourceforge.net/). Kudos to Mr. Bruns.
|
15
15
|
autorequire:
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
@@ -33,9 +33,13 @@ files:
|
|
33
33
|
- Manifest.txt
|
34
34
|
- README.txt
|
35
35
|
- Rakefile
|
36
|
+
- db/.DS_Store
|
37
|
+
- db/not_an_mdb.txt
|
38
|
+
- db/retreat.mdb
|
36
39
|
- db/sample.mdb
|
37
40
|
- irb.rc
|
38
41
|
- lib/active_mdb.rb
|
42
|
+
- lib/active_mdb/base.rb
|
39
43
|
- lib/active_mdb/column.rb
|
40
44
|
- lib/active_mdb/mdb.rb
|
41
45
|
- lib/active_mdb/mdb_tools.rb
|
@@ -43,6 +47,7 @@ files:
|
|
43
47
|
- lib/active_mdb/table.rb
|
44
48
|
- support/a.insert
|
45
49
|
- test/test_activemdb.rb
|
50
|
+
- test/test_base.rb
|
46
51
|
- test/test_helper.rb
|
47
52
|
- test/test_mdb.rb
|
48
53
|
- test/test_mdb_tools.rb
|
@@ -50,6 +55,7 @@ files:
|
|
50
55
|
- test/test_table.rb
|
51
56
|
test_files:
|
52
57
|
- test/test_activemdb.rb
|
58
|
+
- test/test_base.rb
|
53
59
|
- test/test_helper.rb
|
54
60
|
- test/test_mdb.rb
|
55
61
|
- test/test_mdb_tools.rb
|