1 | (ns com.github.kyleburton.sandbox.mdb |
2 | (:import (com.healthmarketscience.jackcess |
3 | Database TableBuilder |
4 | ColumnBuilder DataType Table) |
5 | (java.io File)) |
6 | (:require [com.github.kyleburton.sandbox.utils :as kutils] |
7 | [clojure.contrib.duck-streams :as ds] |
8 | [clojure.contrib.str-utils :as str])) |
9 |
|
10 | (defn new-col [name type] |
11 | (let [cb (ColumnBuilder. name)] |
12 | (.setSQLType cb (.getSQLType type)) |
13 | (.toColumn cb))) |
14 |
|
15 | (defmacro with-database [[var location] & body] |
16 | `(let [location# (ds/file (str ~location)) |
17 | exists# (.exists location#)] |
18 | (with-open [~var (if exists# |
19 | (Database/open location#) |
20 | (Database/create location#))] |
21 | (let [res# (do ~@body)] |
22 | (.flush ~var) |
23 | res#)))) |
24 |
|
25 | (defn- ->safe-name [thing] |
26 | (.replaceAll |
27 | (cond (keyword? thing) |
28 | (.substring (str thing) 1) |
29 | (string? thing) |
30 | thing |
31 | true |
32 | (str thing)) |
33 | "[^a-zA-Z0-9]" "_")) |
34 |
|
35 | (defn create-table [#^Database db #^String table-name & cols] |
36 | (let [builder (TableBuilder. table-name)] |
37 | (loop [[[name type] & cols] (partition 2 cols)] |
38 | (if name |
39 | (do |
40 | (.addColumn builder (new-col (->safe-name name) type)) |
41 | (recur cols)))) |
42 | (.toTable builder db))) |
43 |
|
44 | (defn create-or-get-table [#^Database db #^String table-name & cols] |
45 | (if (.contains (.getTableNames db) |
46 | table-name) |
47 | (.getTable db table-name) |
48 | (apply create-table db table-name cols))) |
49 |
|
50 |
|
51 | ;; (kutils/doc-class |
52 | ;; (with-database [db (kutils/$HOME "test.mdb")] |
53 | ;; (.getTableNames db))) |
54 |
|
55 |
|
56 | (defn insert-row [tbl & fields] |
57 | (.addRow tbl (to-array fields))) |
58 |
|
59 | ;; (class (with-database [db (kutils/$HOME "test.mdb")] db)) |
60 |
|
61 | (defn row->seq [cols row] |
62 | (map #(get row (.getName %)) cols)) |
63 |
|
64 | (defn for-each-row |
65 | ([#^Table tbl fn] |
66 | (let [cols (.getColumns tbl)] |
67 | (.reset tbl) |
68 | (loop [row (.getNextRow tbl)] |
69 | (if row |
70 | (do |
71 | (fn (row->seq cols row)) |
72 | (recur (.getNextRow tbl))))))) |
73 | ([#^Database db #^String tbl fn] |
74 | (for-each-row (.getTable db tbl) fn))) |
75 |
|
76 | (defn table->tab-file |
77 | [#^String mdb-file #^String table-name #^String tab-file] |
78 | (with-database [db mdb-file] |
79 | (with-open [out (ds/writer tab-file)] |
80 | (binding [*out* out] |
81 | (for-each-row |
82 | db |
83 | table-name |
84 | (fn [row] |
85 | (println (str/str-join "\t" row)))))))) |
86 |
|
87 |
|
88 | (defn- ->map [m] |
89 | (reduce (fn [r k] |
90 | (assoc r (keyword (.toLowerCase k)) (.get m k))) |
91 | {} |
92 | (keys m))) |
93 |
|
94 | ;; (with-database [db (kutils/$HOME "test.mdb")] |
95 | ;; (prn (format "tables: %s" (.getTableNames db))) |
96 | ;; (let [tbl (create-or-get-table |
97 | ;; db |
98 | ;; "TABLE_A" |
99 | ;; :id DataType/INT |
100 | ;; :fname DataType/TEXT |
101 | ;; :lname DataType/TEXT |
102 | ;; :addr1 DataType/TEXT |
103 | ;; :addr2 DataType/TEXT |
104 | ;; :city DataType/TEXT |
105 | ;; :state DataType/TEXT |
106 | ;; :zip DataType/TEXT)] |
107 | ;; (insert-row tbl 1 "Kyle" "Burton" "2700 Horizon Drive" "STE 200" "King of Prussia" "PA" "19401") |
108 | ;; (insert-row tbl 1 "Kyle" "Burton" "625 W. Rdige Pike" "STE 400" "Conshohocken" "PA" "19401") |
109 | ;; (insert-row tbl 1 "Kyle" "Burton" "123 Main St" "" "Wayne" "PA" "19401"))) |
110 |
|
111 | (defn mdb->tables [mdb] |
112 | (with-database [db mdb] |
113 | (seq (.getTableNames db)))) |
114 |
|
115 | ;; (mdb->tables (kutils/$HOME "test.mdb")) |
116 |
|
117 |
|
118 | ;; (table->tab-file |
119 | ;; (kutils/$HOME "test.mdb") |
120 | ;; "TABLE_A" |
121 | ;; (kutils/$HOME "table_a.tab")) |
122 |
|
123 | (defn tab-file->table [mdb table file] |
124 | (with-database [db mdb] |
125 | (.importFile db table (ds/file file) "\t"))) |
126 |
|
127 | ;; (tab-file->table (kutils/$HOME "test.mdb") |
128 | ;; "TABLE_B" |
129 | ;; (kutils/$HOME "table_a.tab")) |
130 |
|
131 | (defn display-table [mdb tbl] |
132 | (with-database [db mdb] |
133 | (.display (.getTable db tbl)))) |
134 |
|
135 | ;; (print (display-table (kutils/$HOME "test.mdb") "TABLE_A")) |
136 |
|
137 | ;; (with-database [db (kutils/$HOME "test.mdb")] |
138 | ;; (prn (format "tables: %s" (.getTableNames db))) |
139 | ;; (let [tbl (.getTable db "TABLE_A")] |
140 | ;; (prn (format "columns[%s]: %s" |
141 | ;; (.getName tbl) |
142 | ;; (map #(.getName %) (seq (.getColumns tbl))))) |
143 | ;; (do |
144 | ;; (.reset tbl) |
145 | ;; (loop [row (.getNextRow tbl)] |
146 | ;; (if row |
147 | ;; (do |
148 | ;; (prn (format "row: %s" row)) |
149 | ;; ;(prn (format " %s" (->map row))) |
150 | ;; ;(prn (format " id: %s" (:id (->map row)))) |
151 | ;; (recur (.getNextRow tbl)))))))) |
152 |
|
153 | (defmulti truncate-table (fn [& args] (map class args))) |
154 |
|
155 | (defmethod truncate-table [String String] [mdb table] |
156 | (prn "S,S; opening db and delegating") |
157 | (with-database [db mdb] |
158 | (truncate-table db table))) |
159 |
|
160 | (defmethod truncate-table [File String] [mdb table] |
161 | (prn "F,S; opening db and delegating") |
162 | (with-database [db mdb] |
163 | (truncate-table db table))) |
164 |
|
165 | (defmethod truncate-table [Database String] [db table] |
166 | (prn "D,S; getting table and delegating") |
167 | (truncate-table db (.getTable db table))) |
168 |
|
169 | ;; probably faster to drop/create the table...but I don't see how to |
170 | ;; delete a table in the api? deleteCurrentRow doesn't seem to |
171 | ;; work... |
172 | (defmethod truncate-table [Database Table] [db table] |
173 | (prn "D,T; rubber meets the road") |
174 | (.reset table) |
175 | (loop [row (.getNextRow table)] |
176 | (prn "in loop, row:" row) |
177 | (if row |
178 | (do |
179 | (prn "deleting row: " row) |
180 | (.deleteCurrentRow table) |
181 | (recur (.getNextRow table)))))) |
182 |
|
183 |
|
184 | ;; (mdb->tables (kutils/$HOME "tmp" "test.mdb")) |
185 | ;; (truncate-table (kutils/$HOME "tmp" "test.mdb") "TABLE_B") |
186 |
|
187 | ;; (print (display-table (kutils/$HOME "test.mdb") "TABLE_A")) |
188 | ;; (print (display-table (kutils/$HOME "test.mdb") "TABLE_B")) |
189 |
|
190 | ;; (with-database [db (kutils/$HOME "test.mdb")] |
191 | ;; (for-each-row db "TABLE_B" |
192 | ;; (fn [row] (prn "row=" row)))) |
193 |
|