intersys 0.1 → 0.2
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/Makefile +9 -9
- data/lib/callable.rb +86 -0
- data/lib/database.c +21 -1
- data/lib/extconf.rb +33 -9
- data/lib/global.c +66 -0
- data/lib/intersys.c +24 -3
- data/lib/intersys.h +29 -2
- data/lib/intersys.rb +59 -350
- data/lib/intersys_adapter.rb +132 -0
- data/lib/object.rb +163 -0
- data/lib/query.c +143 -3
- data/lib/reflection.rb +113 -0
- data/lib/sql_include/iodbcunix.h +149 -0
- data/lib/sql_include/sql.h +1189 -0
- data/lib/sql_include/sqlext.h +2566 -0
- data/lib/sql_include/sqltypes.h +421 -0
- data/lib/sql_include/sqlucode.h +812 -0
- data/test/adapter.rb +19 -0
- data/test/global.rb +12 -0
- data/test/query.rb +5 -0
- data/test/reflection.rb +7 -6
- data/test/strings.rb +2 -1
- metadata +15 -3
- data/lib/test.rb +0 -30
data/lib/intersys.rb
CHANGED
@@ -11,10 +11,15 @@ module Intersys
|
|
11
11
|
extend DL::Importable
|
12
12
|
begin
|
13
13
|
dlload("libcbind.dylib")
|
14
|
-
rescue
|
14
|
+
rescue StandardError => e
|
15
|
+
puts e
|
15
16
|
end
|
16
17
|
|
17
18
|
require File.dirname(__FILE__) + '/intersys_cache'
|
19
|
+
require 'object'
|
20
|
+
require 'callable'
|
21
|
+
require 'reflection'
|
22
|
+
|
18
23
|
|
19
24
|
class Method
|
20
25
|
def description
|
@@ -30,264 +35,51 @@ module Intersys
|
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
def
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
# returns list of methods for this class
|
40
|
-
def intersys_methods
|
41
|
-
@methods ||= intersys_reflector._methods
|
42
|
-
end
|
43
|
-
|
44
|
-
# returns list of properties for current class
|
45
|
-
def intersys_properties
|
46
|
-
@properties ||= intersys_reflector.properties
|
47
|
-
end
|
48
|
-
|
49
|
-
#protected
|
50
|
-
# Loads property definition with required name for required object
|
51
|
-
# for internal use only
|
52
|
-
def intersys_property(name)
|
53
|
-
Property.new(database, class_name, name.to_s, self)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Loads method definition with required name for required object
|
57
|
-
# for internal use only
|
58
|
-
def intersys_method(name)
|
59
|
-
Method.new(database, class_name, name.to_s, self)
|
60
|
-
end
|
61
|
-
|
62
|
-
public
|
63
|
-
# call class method
|
64
|
-
def intersys_call(method_name, *args)
|
65
|
-
intersys_method(method_name).call!(args)
|
66
|
-
end
|
67
|
-
alias :call :intersys_call
|
68
|
-
|
69
|
-
def intersys_has_property?(property)
|
70
|
-
self.intersys_reflector.properties.to_a.include?(property)
|
71
|
-
end
|
72
|
-
|
73
|
-
def intersys_has_method?(method)
|
74
|
-
self.intersys_reflector._methods.to_a.include?(method)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Get the specified property
|
78
|
-
def intersys_get(property)
|
79
|
-
intersys_property(property).get
|
80
|
-
end
|
81
|
-
|
82
|
-
# Set the specified property
|
83
|
-
def intersys_set(property, value)
|
84
|
-
intersys_property(property).set(value)
|
85
|
-
end
|
86
|
-
|
87
|
-
def method_missing(method, *args)
|
88
|
-
method_name = method.to_s.camelize
|
89
|
-
if match_data = method_name.match(/intersys_(.*)/)
|
90
|
-
# Protection from errors in this method
|
91
|
-
return super(method, *args)
|
92
|
-
end
|
93
|
-
if match_data = method_name.match(/(\w+)=/)
|
94
|
-
return intersys_set(match_data.captures.first, args.first)
|
95
|
-
end
|
96
|
-
return intersys_get(method_name) if intersys_has_property?(method_name) && args.empty?
|
97
|
-
begin
|
98
|
-
return intersys_call(method_name, *args)
|
99
|
-
rescue NoMethodError => e
|
100
|
-
end
|
101
|
-
begin
|
102
|
-
return intersys_call("%"+method_name, *args)
|
103
|
-
rescue NoMethodError => e
|
104
|
-
end
|
105
|
-
super(method, *args)
|
38
|
+
|
39
|
+
module ActiveRecordEmulation
|
40
|
+
def append_features(base)
|
41
|
+
base.extend ClassMethods
|
106
42
|
end
|
107
43
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
#
|
113
|
-
# By default prefix "User" is selected. If Cache class has another prefix, it must
|
114
|
-
# be provided explicitly via method "prefix":
|
115
|
-
# class List < Intersys::Object
|
116
|
-
# prefix "%Library"
|
117
|
-
# end
|
118
|
-
#
|
119
|
-
# By default name of Cache class is taken the same as name of ruby class.
|
120
|
-
# Thus in this example this class List will be marshalled to Cache class
|
121
|
-
# %Library.List
|
122
|
-
#
|
123
|
-
class Object
|
124
|
-
|
125
|
-
class << self
|
126
|
-
protected
|
127
|
-
def class_names
|
128
|
-
common_get_or_set("@class_names", {})
|
129
|
-
end
|
130
|
-
|
131
|
-
def prefix=(name)
|
132
|
-
@prefix = name
|
133
|
-
@class_name = @prefix + "." + (@class_name ? @class_name.split(".").last : self.to_s)
|
134
|
-
register_name!
|
135
|
-
end
|
136
|
-
|
137
|
-
def class_name=(name)
|
138
|
-
if name.index(".")
|
139
|
-
self.prefix = name.split(".").first
|
140
|
-
@class_name = name
|
44
|
+
module ClassMethods
|
45
|
+
def create(attributes = nil)
|
46
|
+
if attributes.is_a?(Array)
|
47
|
+
attributes.collect { |attr| create(attr) }
|
141
48
|
else
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
# Register class name of current class in global list
|
148
|
-
def register_name!
|
149
|
-
if i = class_names.index(self)
|
150
|
-
class_names.delete(i)
|
49
|
+
object = intersys_call("%New")
|
50
|
+
attributes.each { |att,value| object.send("#{att}=", value) }
|
51
|
+
object.save
|
52
|
+
object
|
151
53
|
end
|
152
|
-
class_names[class_name] = self
|
153
|
-
class_name
|
154
54
|
end
|
155
55
|
|
156
|
-
|
157
|
-
|
158
|
-
# Maybe, later, it will be possible even to generate IDL, using this code
|
159
|
-
def intersys_description
|
160
|
-
"class #{class_name} { \n" + intersys_reflector.all_methods.map do |mtd|
|
161
|
-
begin
|
162
|
-
"\t"+intersys_method(mtd).description+";\n"
|
163
|
-
rescue
|
164
|
-
"\tundefined #{mtd}\n"
|
165
|
-
end
|
166
|
-
end.join("") + "};"
|
167
|
-
end
|
168
|
-
|
169
|
-
# Help to work with instance variables of Intersys::Object class
|
170
|
-
# required, because list of registered descendants of Intersys::Object,
|
171
|
-
# database connection etc. should be in one place
|
172
|
-
def common_get_or_set(name, default_value = nil)
|
173
|
-
unless var = Intersys::Object.instance_variable_get(name)
|
174
|
-
default = block_given? ? yield : default_value
|
175
|
-
var = Intersys::Object.instance_variable_set(name, default)
|
176
|
-
end
|
177
|
-
var
|
178
|
-
end
|
179
|
-
|
180
|
-
# Takes Cache class name and try to resolve it to Ruby class
|
181
|
-
def lookup(class_name)
|
182
|
-
class_names[class_name] || raise(UnMarshallError, "Couldn't find registered class with Cache name '#{class_name}'")
|
183
|
-
end
|
184
|
-
|
185
|
-
# Each Cache class has prefix before it's name: namespace.
|
186
|
-
# this method set's prefix for current class is provided,
|
187
|
-
# or just returns current prefix
|
188
|
-
def prefix(name = nil)
|
189
|
-
self.prefix = name if name
|
190
|
-
@prefix ||= "User"
|
56
|
+
def exists?(id)
|
57
|
+
exists_id(id)
|
191
58
|
end
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
self.class_name = (prefix + "." + to_s) unless @class_name
|
197
|
-
@class_name
|
198
|
-
end
|
199
|
-
|
200
|
-
# Returns database, if called without parameters, or sets one, if passed
|
201
|
-
# Once established, it is not possible now to connect to another database
|
202
|
-
def database(db_options = {})
|
203
|
-
common_get_or_set("@database") do
|
204
|
-
Intersys::Database.new({:user => "_SYSTEM", :password => "SYS", :namespace => "User"}.merge(db_options))
|
205
|
-
end
|
59
|
+
|
60
|
+
def find_by_sql(sql)
|
61
|
+
warn "Nop, no find_by_sql in Object interface"
|
62
|
+
nil
|
206
63
|
end
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
# In case of exception ROLLBACK TRANSACTION is called
|
212
|
-
def transaction
|
213
|
-
return unless block_given?
|
214
|
-
database.start
|
215
|
-
begin
|
216
|
-
yield
|
217
|
-
database.commit
|
218
|
-
rescue StandardError => e
|
219
|
-
database.rollback
|
220
|
-
raise e
|
64
|
+
|
65
|
+
def find(*args)
|
66
|
+
if args.size == 1
|
67
|
+
return open(args.first)
|
221
68
|
end
|
69
|
+
warn "No idea, how to implement method find"
|
70
|
+
nil
|
222
71
|
end
|
223
|
-
|
224
|
-
|
225
|
-
def inherited(klass)
|
226
|
-
class_names[klass.class_name] = klass
|
227
|
-
end
|
228
|
-
|
229
|
-
# Look into Cache documentation for what is concurrency. I don't know
|
230
|
-
def concurrency
|
231
|
-
1
|
232
|
-
end
|
233
|
-
|
234
|
-
# timeout for connection
|
235
|
-
def timeout
|
236
|
-
5
|
237
|
-
end
|
238
|
-
|
239
|
-
# Nice method, that deletes all instances of class.
|
240
|
-
# You can just Person.delete_extent, but Person.delete_all looks more like ActiveRecord
|
241
|
-
def delete_all
|
242
|
-
intersys_call("%DeleteExtent")
|
243
|
-
end
|
244
|
-
|
245
|
-
end
|
246
|
-
|
247
|
-
# You can ask for database from instance
|
248
|
-
def database
|
249
|
-
self.class.database
|
250
|
-
end
|
251
|
-
|
252
|
-
# You can ask from instance it's Cache class name
|
253
|
-
def class_name
|
254
|
-
self.class.class_name
|
255
|
-
end
|
256
|
-
|
257
|
-
# Returns id of current object.
|
258
|
-
# You can remove this method and You will get string ID, so leave it here
|
259
|
-
# However, if You ask reflector for id, it will give incorrect answer,
|
260
|
-
# because Cache allows id to be string
|
261
|
-
def id
|
262
|
-
intersys_call("%Id").to_i
|
263
|
-
end
|
264
|
-
|
265
|
-
# Destroys current object
|
266
|
-
def destroy
|
267
|
-
self.class.intersys_call("%DeleteId", id)
|
72
|
+
|
73
|
+
|
268
74
|
end
|
269
|
-
|
270
|
-
include Callable
|
271
75
|
end
|
272
|
-
|
76
|
+
|
273
77
|
|
274
78
|
# Class representing one query
|
275
79
|
# You shouldn't create it yourself
|
276
80
|
class Query
|
277
81
|
attr_reader :database
|
278
82
|
|
279
|
-
def initialize(database, query)
|
280
|
-
@database = database
|
281
|
-
native_initialize(database, query.to_wchar)
|
282
|
-
end
|
283
|
-
|
284
|
-
def each
|
285
|
-
while (row = self.fetch) && row.size > 0
|
286
|
-
#puts "Loaded row #{row}"
|
287
|
-
yield row
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
83
|
def to_a
|
292
84
|
data = []
|
293
85
|
self.each {|row| data << row}
|
@@ -302,131 +94,48 @@ module Intersys
|
|
302
94
|
|
303
95
|
# Class representing Cache database connection
|
304
96
|
class Database
|
97
|
+
protected
|
98
|
+
def strip_param(query, name)
|
99
|
+
if match_data = query.match(/#{name}(\s*)(\d+)/i)
|
100
|
+
query[match_data.to_s] = ""
|
101
|
+
match_data.captures.last
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
public
|
305
106
|
def create_query(query)
|
306
|
-
|
107
|
+
@limit = strip_param(query, "LIMIT")
|
108
|
+
@offset = strip_param(query, "OFFSET")
|
109
|
+
q = Query.new(self, query)
|
110
|
+
q.limit = @limit if @limit
|
111
|
+
q.offset = @offset if @offset
|
112
|
+
q
|
307
113
|
end
|
308
114
|
|
309
115
|
# This method creates SQL query, runs it, restores data
|
310
116
|
# and closes query
|
311
|
-
def query(query)
|
117
|
+
def query(query, params = [])
|
312
118
|
data = []
|
313
|
-
q = create_query(query).execute.fill(data).close
|
119
|
+
q = create_query(query).bind_params(params).execute.fill(data).close
|
314
120
|
#1.upto(data.first.size) do |i|
|
315
121
|
# puts q.column_name(i)
|
316
122
|
#end
|
317
123
|
data
|
318
124
|
end
|
319
|
-
end
|
320
|
-
|
321
|
-
# Module reflection keeps classes required to get information
|
322
|
-
# about methods and properties of Cache classes
|
323
|
-
module Reflection
|
324
125
|
|
325
|
-
|
326
|
-
|
327
|
-
# this class, representing its internals
|
328
|
-
#
|
329
|
-
# Usually creates via Intersys::Object.reflector
|
330
|
-
#
|
331
|
-
# Then it is possible to call such methods as _methods, properties
|
332
|
-
# to get access to methods and properties of Cache class
|
333
|
-
class ClassDefinition < Intersys::Object
|
334
|
-
class_name "%Dictionary.ClassDefinition"
|
335
|
-
|
336
|
-
# After all changes to class definition required to call save
|
337
|
-
def save
|
338
|
-
intersys_call("%Save")
|
339
|
-
end
|
340
|
-
|
341
|
-
# short alias to intersys_get("Methods")
|
342
|
-
def _methods
|
343
|
-
@methods ||= intersys_get("Methods")
|
344
|
-
end
|
345
|
-
|
346
|
-
def properties
|
347
|
-
@properties ||= intersys_get("Properties")
|
348
|
-
end
|
349
|
-
|
350
|
-
def all_methods
|
351
|
-
_methods.to_a + self.super.split(",").map do |klass|
|
352
|
-
klass = klass.strip
|
353
|
-
if match_data = klass.match(/^%([^\.]+)$/)
|
354
|
-
klass = "%Library.#{match_data.captures.first}"
|
355
|
-
end
|
356
|
-
self.class.open(klass).all_methods
|
357
|
-
end.flatten
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
class PropertyDefinition < Intersys::Object
|
362
|
-
class_name "%Dictionary.PropertyDefinition"
|
126
|
+
def execute(query, params = [])
|
127
|
+
create_query(query).bind_params(params).execute.close
|
363
128
|
end
|
364
129
|
|
365
|
-
|
366
|
-
|
130
|
+
# TODO: /csp/docbook/DocBook.UI.Page.cls?KEY=RSQL_variables
|
131
|
+
# Somehow, I should extract from Cache %ROWCOUNT and %ROWID
|
132
|
+
def affected_rows
|
133
|
+
query("select %ROWCOUNT")
|
367
134
|
end
|
368
135
|
|
369
|
-
|
370
|
-
|
371
|
-
class RelationshipObject < Intersys::Object
|
372
|
-
class_name "%Library.RelationshipObject"
|
373
|
-
|
374
|
-
def empty?
|
375
|
-
@empty ||= intersys_call("IsEmpty")
|
376
|
-
end
|
377
|
-
|
378
|
-
def count
|
379
|
-
@count ||= intersys_call("Count")
|
380
|
-
end
|
381
|
-
alias :size :count
|
382
|
-
|
383
|
-
def [](index)
|
384
|
-
return @list[index] if @loaded
|
385
|
-
intersys_call("GetAt", index.to_s)
|
386
|
-
end
|
387
|
-
|
388
|
-
def each
|
389
|
-
1.upto(count) do |i|
|
390
|
-
yield self[i]
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
include Enumerable
|
395
|
-
|
396
|
-
def to_a
|
397
|
-
load_list
|
398
|
-
end
|
399
|
-
|
400
|
-
def include?(obj)
|
401
|
-
load_list.include?(obj)
|
402
|
-
end
|
403
|
-
|
404
|
-
def inspect
|
405
|
-
load_list.inspect
|
406
|
-
end
|
407
|
-
alias :to_s :inspect
|
408
|
-
|
409
|
-
def <<(object)
|
410
|
-
intersys_call("Insert", object)
|
411
|
-
end
|
412
|
-
alias :insert :<<
|
413
|
-
|
414
|
-
def reload
|
415
|
-
@list = nil
|
416
|
-
@loaded = nil
|
417
|
-
@empty = nil
|
418
|
-
@count = nil
|
419
|
-
end
|
420
|
-
|
421
|
-
protected
|
422
|
-
def load_list
|
423
|
-
@list ||= []
|
424
|
-
self.each do |prop|
|
425
|
-
@list << prop.intersys_get("Name")
|
426
|
-
end unless @loaded
|
427
|
-
@loaded = true
|
428
|
-
@list
|
429
|
-
end
|
136
|
+
def insert_id
|
137
|
+
0
|
430
138
|
end
|
431
139
|
end
|
140
|
+
|
432
141
|
end
|