spreadsheet_db_refi 0.0.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.
- data/lib/spreadsheet_db_refi.rb +332 -0
- metadata +78 -0
@@ -0,0 +1,332 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'sqlite3'
|
4
|
+
|
5
|
+
module Refi
|
6
|
+
|
7
|
+
# stores spreadsheet data in a sqlite database
|
8
|
+
class SpreadsheetDb
|
9
|
+
@@std_create_tbls_strs = {
|
10
|
+
metadata: %q(
|
11
|
+
create table metadata(
|
12
|
+
nam text,
|
13
|
+
val text,
|
14
|
+
|
15
|
+
primary key(nam)
|
16
|
+
);
|
17
|
+
),
|
18
|
+
sheet: %q(
|
19
|
+
create table sheet(
|
20
|
+
id integer,
|
21
|
+
nam text,
|
22
|
+
pos integer,
|
23
|
+
|
24
|
+
primary key(id),
|
25
|
+
unique(nam),
|
26
|
+
unique(pos)
|
27
|
+
);
|
28
|
+
),
|
29
|
+
typ: %q(
|
30
|
+
create table typ(
|
31
|
+
id integer,
|
32
|
+
nam text,
|
33
|
+
mcv text,
|
34
|
+
|
35
|
+
primary key(id),
|
36
|
+
unique(nam)
|
37
|
+
);
|
38
|
+
),
|
39
|
+
cell: %q(
|
40
|
+
create table cell(
|
41
|
+
sheet_id integer,
|
42
|
+
row integer,
|
43
|
+
col integer,
|
44
|
+
val text,
|
45
|
+
typ_id integer,
|
46
|
+
|
47
|
+
primary key(sheet_id, row, col),
|
48
|
+
foreign key(sheet_id) references sheet(id),
|
49
|
+
foreign key(typ_id) references typ(id)
|
50
|
+
);
|
51
|
+
)
|
52
|
+
}.inject({}){|memo,(k,v)| memo[k] = v.strip_a_lot ; memo}
|
53
|
+
@@std_tbl_create_order = [:metadata, :sheet, :typ, :cell]
|
54
|
+
@@std_stmts_strs = {
|
55
|
+
metadata_set_nam_val: "insert or replace into metadata(nam,val) values(?,?);",
|
56
|
+
metadata_get_all: "select * from metadata;",
|
57
|
+
metadata_get_val_by_nam: "select val from metadata where nam=?;",
|
58
|
+
metadata_del_val_by_nam: "delete from metadata where nam=?;",
|
59
|
+
metadata_wipe: "delete from metadata;",
|
60
|
+
sheet_set_id_nam_pos: "insert or replace into sheet(id,nam,pos) values(?,?,?);",
|
61
|
+
sheet_get_id_by_nam: "select id from sheet where nam=?;",
|
62
|
+
sheet_get_nam_by_id: "select nam from sheet where id=?",
|
63
|
+
sheet_get_all: "select * from sheet;",
|
64
|
+
typ_set_id_nam_mcv: "insert or replace into typ(id,nam,mcv) values(?,?,?);",
|
65
|
+
typ_get_all_by_nam: "select * from typ where nam=?",
|
66
|
+
cell_set_sheet_row_col_val_typ: "insert or replace into cell(sheet_id,row,col,val,typ_id) values(?,?,?,?,?);",
|
67
|
+
cell_get: "select val,typ_id from cell where sheet_id=? and row=? and col=?;",
|
68
|
+
get_min_col: "select min(col) from cell where sheet_id=?;",
|
69
|
+
get_max_col: "select max(col) from cell where sheet_id=?;",
|
70
|
+
get_min_row: "select min(row) from cell where sheet_id=?;",
|
71
|
+
get_max_row: "select max(row) from cell where sheet_id=?;",
|
72
|
+
get_row: "select col,val,typ_id from cell where sheet_id=? and row=?;",
|
73
|
+
get_col: "select row,val,typ_id from cell where sheet_id=? and col=?;",
|
74
|
+
sqlite_get_tbl_nam_by_nam: "select name from sqlite_master where name=?;",
|
75
|
+
}
|
76
|
+
attr_accessor :db
|
77
|
+
def initialize(db_pn=nil)
|
78
|
+
@create_tbls_strs = @@std_create_tbls_strs
|
79
|
+
@stmts_strs = @@std_stmt_strs
|
80
|
+
@tbl_create_order = @@std_tbl_create_order
|
81
|
+
init2(db_pn)
|
82
|
+
end
|
83
|
+
def init2(db_pn=nil)
|
84
|
+
@is_open = false
|
85
|
+
reset
|
86
|
+
if(db_pn)
|
87
|
+
@db_pn = db_pn
|
88
|
+
open
|
89
|
+
end
|
90
|
+
end
|
91
|
+
def reset
|
92
|
+
if @is_open
|
93
|
+
@prep_stmts.each{|sym,prep_stmt| prep_stmt.close }
|
94
|
+
@db.close
|
95
|
+
end
|
96
|
+
@prep_stmts = {}
|
97
|
+
@db = nil
|
98
|
+
@is_open = false
|
99
|
+
@empty_cell_default_value = ''
|
100
|
+
end
|
101
|
+
def open
|
102
|
+
exist_prior = File.exist?(@db_pn)
|
103
|
+
if(exist_prior)
|
104
|
+
if(File.zero?(@db_pn))
|
105
|
+
File.delete(@db_pn)
|
106
|
+
exist_prior = false
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@db = SQLite3::Database.new(@db_pn)
|
110
|
+
enhance_db_funcs
|
111
|
+
|
112
|
+
if(exist_prior)
|
113
|
+
assert_db_well_formed({exist_prior: exist_prior,on_err_exit: true})
|
114
|
+
prepare_statements
|
115
|
+
else
|
116
|
+
@db.transaction{|foo|
|
117
|
+
create_tables
|
118
|
+
prepare_statements
|
119
|
+
insert_minimum_records
|
120
|
+
}
|
121
|
+
assert_db_well_formed({exist_prior: exist_prior,on_err_exit: true})
|
122
|
+
end
|
123
|
+
@is_open = true
|
124
|
+
end
|
125
|
+
def create_tables
|
126
|
+
@tbl_create_order.each{|tbl_nam|
|
127
|
+
db.execute(@create_tbls_strs[tbl_nam])
|
128
|
+
}
|
129
|
+
end
|
130
|
+
def insert_minimum_records # requires prepared statements
|
131
|
+
@prep_stmts[:typ_set_id_nam_mcv].execute([nil,'std','{}'])
|
132
|
+
end
|
133
|
+
def assert_db_well_formed(p={}) # requires good tables(with minimum records) and prepared statements
|
134
|
+
exist_prior = p[:exist_prior] || false
|
135
|
+
on_err_exit = p[:on_err_exit] || true
|
136
|
+
good = true
|
137
|
+
@tbl_create_order.each{|sym|
|
138
|
+
nam = sym.to_s
|
139
|
+
# @prep_stmts is not ready yet
|
140
|
+
found_table = @db.execute(@stmts_strs[:sqlite_get_tbl_nam_by_nam],nam)[0] == [nam]
|
141
|
+
#found_table = @prep_stmts[:sqlite_get_tbl_name_by_name].execute(sym.to_s).size == 1
|
142
|
+
if(!found_table)
|
143
|
+
good = false
|
144
|
+
# missing table
|
145
|
+
$Log.tlog({id: 'err1122',table:sym.to_s})
|
146
|
+
end
|
147
|
+
}
|
148
|
+
if(!good)
|
149
|
+
if(exist_prior)
|
150
|
+
dperr(120,"existing db not well formed (pn:#{db_pn})",true,on_err_exit)
|
151
|
+
else
|
152
|
+
dperr(121,"new db not well formed (pn:#{db_pn})",true,on_err_exit)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
return good
|
156
|
+
end
|
157
|
+
def enhance_db_funcs
|
158
|
+
$sqlite_enhance_funcs.each{|func_nam,func|
|
159
|
+
@db.create_function(func_nam,func[:func_body].arity + 1,func[:return_type], &func[:func_body])
|
160
|
+
}
|
161
|
+
end
|
162
|
+
def prepare_statements
|
163
|
+
@stmts_strs.each{|sym,stmt_str|
|
164
|
+
@prep_stmts[sym] = @db.prepare(stmt_str)
|
165
|
+
}
|
166
|
+
end
|
167
|
+
def get_metadata
|
168
|
+
if @db
|
169
|
+
return Hash[ @prep_stmts[:metadata_get_all].execute!() ]
|
170
|
+
else
|
171
|
+
return nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
def create_sheet(sheet_name,pos_ix)
|
175
|
+
@prep_stmts[:sheet_set_id_nam_pos].execute(nil,sheet_name,pos_ix)
|
176
|
+
new_sheet_id = @prep_stmts[:sheet_get_id_by_nam].execute!(sheet_name).flatten[0]
|
177
|
+
return new_sheet_id
|
178
|
+
end
|
179
|
+
def get_sheet_id_from_xid(sheet_xid)
|
180
|
+
if(sheet_xid.is_a?(String))
|
181
|
+
return @prep_stmts[:sheet_get_id_by_nam].execute!(sheet_xid).flatten[0]
|
182
|
+
elsif(sheet_xid.is_a?(Fixnum))
|
183
|
+
return sheet_xid
|
184
|
+
end
|
185
|
+
end
|
186
|
+
def get_sheet_name_from_xid(sheet_xid)
|
187
|
+
if(sheet_xid.is_a?(String))
|
188
|
+
return sheet_xid
|
189
|
+
elsif(sheet_xid.is_a?(Fixnum))
|
190
|
+
return @prep_stmts[:sheet_get_nam_by_id].execute!(sheet_xid).flatten[0]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
def prep_ex(sym,p_ary=[])
|
194
|
+
return @prep_stmts[sym].execute!(p_ary)
|
195
|
+
end
|
196
|
+
def get_sheet_name_by_id(sheet_id)
|
197
|
+
return prep_ex(:sheet_get_nam_by_id,[sheet_id])[0]
|
198
|
+
end
|
199
|
+
def set_cell(sheet_id,row,col,value,type)
|
200
|
+
prep_ex(:cell_set_sheet_row_col_val_typ,[sheet_id,row,col,value,type])
|
201
|
+
end
|
202
|
+
def import_sheet(sheet_id,ss)
|
203
|
+
$Log.tlog({id: 'info1045'})
|
204
|
+
$Log.indent
|
205
|
+
#dputi("import all rows of sheet into cache")
|
206
|
+
#metadata = get_metadata
|
207
|
+
# CUR
|
208
|
+
row_a = ss.first_row
|
209
|
+
row_e = ss.last_row
|
210
|
+
col_a = ss.first_column
|
211
|
+
col_e = ss.last_column
|
212
|
+
@db.transaction{|dbi|
|
213
|
+
row_a.upto(row_e){|row_i|
|
214
|
+
col_a.upto(col_e){|col_i|
|
215
|
+
#pp ss
|
216
|
+
#puts row_i
|
217
|
+
#puts col_i
|
218
|
+
cell_value = ss.cell(row_i,col_i)
|
219
|
+
value = ''
|
220
|
+
# TODO use hash?
|
221
|
+
if(cell_value == nil)
|
222
|
+
# TODO
|
223
|
+
#dparn(117,"empty cell (#{@ss_pn}:#{sheet_id}:#{row_i}:#{col_i}) using default value:'#{@empty_cell_default_value}'")
|
224
|
+
if(@empty_cell_default_value==nil)
|
225
|
+
dparn(777,"no empty cell default value using builtin string of the form 'XXX_empty_cell(...)'")
|
226
|
+
value = "XXX_empty_cell(#{@ss_pn}:#{sheet_id}:#{row_i}:#{col_i})"
|
227
|
+
else
|
228
|
+
value = @empty_cell_default_value
|
229
|
+
end
|
230
|
+
elsif(cell_value.is_a?(String))
|
231
|
+
value = cell_value
|
232
|
+
elsif(cell_value.is_a?(Date))
|
233
|
+
value = cell_value.iso8601
|
234
|
+
elsif(cell_value.is_a?(Float))
|
235
|
+
value = cell_value
|
236
|
+
elsif(cell_value.is_a?(NilClass))
|
237
|
+
dperr(113,"NilClass in cell")
|
238
|
+
else
|
239
|
+
dpev cell_value.class
|
240
|
+
dperr(1375, "#{__FILE__} #{__LINE__}")
|
241
|
+
end
|
242
|
+
type = 1
|
243
|
+
set_cell(sheet_id,row_i,col_i,value,type)
|
244
|
+
}
|
245
|
+
print 'c'
|
246
|
+
}
|
247
|
+
#dput
|
248
|
+
$Log.undent
|
249
|
+
}
|
250
|
+
#dpun
|
251
|
+
$Log.undent
|
252
|
+
end
|
253
|
+
def get_sheet(sheet_xid)
|
254
|
+
sheet_id = get_sheet_id_from_xid(sheet_xid)
|
255
|
+
new_sheet = SsDbSheet.new(self,sheet_id)
|
256
|
+
return new_sheet
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class SsDbCellValue
|
261
|
+
attr_accessor :value
|
262
|
+
attr_accessor :type_id
|
263
|
+
def initialize(value,type_id)
|
264
|
+
dperr(131,"'value' is not of type 'String' (type:'#{value.class}'") if !value.is_a?(String)
|
265
|
+
dperr(132,"'type_id' is not of type 'Fixnum' (type:'#{type_id.class}'") if !type_id.is_a?(Fixnum)
|
266
|
+
@value = value
|
267
|
+
@type_id = type_id
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
class SsDbSheet
|
272
|
+
def initialize(ss_db,sheet_id)
|
273
|
+
@ss_db = ss_db
|
274
|
+
@sheet_id = sheet_id
|
275
|
+
end
|
276
|
+
def prep_ex(sym,p_ary=[])
|
277
|
+
@ss_db.prep_ex(sym,p_ary)
|
278
|
+
end
|
279
|
+
def get_dims
|
280
|
+
{
|
281
|
+
col: {
|
282
|
+
min: prep_ex(:get_min_col,[@sheet_id])[0][0],
|
283
|
+
max: prep_ex(:get_max_col,[@sheet_id])[0][0],
|
284
|
+
},
|
285
|
+
row: {
|
286
|
+
min: prep_ex(:get_min_row,[@sheet_id])[0][0],
|
287
|
+
max: prep_ex(:get_max_row,[@sheet_id])[0][0],
|
288
|
+
},
|
289
|
+
}
|
290
|
+
end
|
291
|
+
def get_row(i,t=false)
|
292
|
+
q = if(t)
|
293
|
+
:get_col
|
294
|
+
else
|
295
|
+
:get_row
|
296
|
+
end
|
297
|
+
row = prep_ex(q,[@sheet_id,i]).inject({}){|memo,j|
|
298
|
+
memo[ j[0] ] = SsDbCellValue.new( j[1], j[2])
|
299
|
+
memo
|
300
|
+
}
|
301
|
+
return row
|
302
|
+
end
|
303
|
+
def get_cell(r,c,t=false) # row col transpose
|
304
|
+
r,c = c,r if t
|
305
|
+
value,type_id = *prep_ex(:cell_get,[@sheet_id,r,c])[0]
|
306
|
+
return SsDbCellValue.new(value,type_id)
|
307
|
+
end
|
308
|
+
def get_col(i,transpose=false)
|
309
|
+
return get_row(i,!transpose)
|
310
|
+
end
|
311
|
+
|
312
|
+
# if t is true rows and columns are transposed
|
313
|
+
def get_first_row(t=false)
|
314
|
+
return get_first_col if t
|
315
|
+
return prep_ex(:get_min_row)
|
316
|
+
end
|
317
|
+
def get_last_row(t=false)
|
318
|
+
return get_last_col if t
|
319
|
+
return prep_ex(:get_max_row)
|
320
|
+
end
|
321
|
+
def get_first_col(t=false)
|
322
|
+
return get_first_row if t
|
323
|
+
return prep_ex(:get_min_col)
|
324
|
+
end
|
325
|
+
def get_last_col(t=false)
|
326
|
+
return get_last_row if t
|
327
|
+
return prep_ex(:get_max_col)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
|
332
|
+
end # module Refi
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: spreadsheet_db_refi
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 0.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Robert Fey
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-07-26 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sqlite3-ruby
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - "="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 3
|
31
|
+
- 3
|
32
|
+
version: 1.3.3
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: store spreadsheet data in a sqilte db
|
36
|
+
email: feyrob@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/spreadsheet_db_refi.rb
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://rubygems.org/gems/spreadsheet_db_refi
|
47
|
+
licenses: []
|
48
|
+
|
49
|
+
post_install_message:
|
50
|
+
rdoc_options: []
|
51
|
+
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
segments:
|
68
|
+
- 0
|
69
|
+
version: "0"
|
70
|
+
requirements: []
|
71
|
+
|
72
|
+
rubyforge_project: nowarning
|
73
|
+
rubygems_version: 1.3.7
|
74
|
+
signing_key:
|
75
|
+
specification_version: 3
|
76
|
+
summary: ""
|
77
|
+
test_files: []
|
78
|
+
|