Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 60 additions & 42 deletions lib/plsql/package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,34 @@ module PLSQL

module PackageClassMethods #:nodoc:
def find(schema, package)
if schema.select_first(
"SELECT object_name FROM all_objects
WHERE owner = :owner
AND object_name = :package
AND object_type = 'PACKAGE'",
schema.schema_name, package.to_s.upcase)
new(schema, package)
# search for synonym
elsif (row = schema.select_first(
"SELECT o.owner, o.object_name
FROM all_synonyms s, all_objects o
WHERE s.owner IN (:owner, 'PUBLIC')
AND s.synonym_name = :synonym_name
AND o.owner = s.table_owner
AND o.object_name = s.table_name
AND o.object_type = 'PACKAGE'
ORDER BY DECODE(s.owner, 'PUBLIC', 1, 0)",
schema.schema_name, package.to_s.upcase))
new(schema, row[1], row[0])
else
nil
end
package_name = package.to_s.upcase
find_in_schema(schema, package_name) || find_by_synonym(schema, package_name)
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice separation of responsibility. I like the way you got rid of the If/else

def find_in_schema(schema, package_name)
row = schema.select_first(<<-SQL, schema.schema_name, package_name)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgebal is it better now? Or did I miss something?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@flash-gordon Thanks, I'll review it over the weekend - too tired to think clear now.

SELECT object_name
FROM all_objects
WHERE owner = :owner
AND object_name = :package
AND object_type = 'PACKAGE'
SQL
new(schema, package_name) if row
end

def find_by_synonym(schema, package_name)
row = schema.select_first(<<-SQL, schema.schema_name, package_name)
SELECT o.object_name, o.owner
FROM all_synonyms s,
all_objects o
WHERE s.owner IN (:owner, 'PUBLIC')
AND s.synonym_name = :synonym_name
AND o.owner = s.table_owner
AND o.object_name = s.table_name
AND o.object_type = 'PACKAGE'
ORDER BY DECODE(s.owner, 'PUBLIC', 1, 0)
SQL
new(schema, row[0], row[1]) if row
end
end

Expand All @@ -41,29 +47,41 @@ def procedure_defined?(name)
PLSQL::Procedure.find(@schema, name, @package) ? true : false
end

def [](object_name)
object_name = object_name.to_s.downcase
@package_objects[object_name] ||= [Procedure, Variable].inject(nil) do |res, object_type|
res || object_type.find(@schema, object_name, @package, @override_schema_name)
end
end

private

def method_missing(method, *args, &block)
if assignment = (method.to_s[-1,1] == '=')
method = method.to_s.chop.to_sym
end
object = (@package_objects[method] ||=
Procedure.find(@schema, method, @package, @override_schema_name) ||
Variable.find(@schema, method, @package, @override_schema_name))
case object
when Procedure
raise ArgumentError, "Cannot assign value to package procedure '#{method.to_s.upcase}'" if assignment
object.exec(*args, &block)
when Variable
if assignment
raise ArgumentError, "Just one value can be assigned to package variable '#{method.to_s.upcase}'" unless args.size == 1 && block == nil
object.value = args[0]
method = method.to_s
method.chop! if (assignment = method[/=$/])

case (object = self[method])
when Procedure
if assignment
raise ArgumentError, "Cannot assign value to package procedure '#{method.upcase}'"
end
object.exec(*args, &block)
when Variable
if assignment
unless args.size == 1 && block.nil?
raise ArgumentError, "Just one value can be assigned " \
"to package variable '#{method.upcase}'"
end
object.value = args[0]
else
unless args.size == 0 && block.nil?
raise ArgumentError, "Cannot pass arguments when getting " \
"package variable '#{method.upcase}' value"
end
object.value
end
else
raise ArgumentError, "Cannot pass arguments when getting package variable '#{method.to_s.upcase}' value" unless args.size == 0 && block == nil
object.value
end
else
raise ArgumentError, "No PL/SQL procedure or variable '#{method.to_s.upcase}' found"
raise ArgumentError, "No PL/SQL procedure or variable '#{method.upcase}' found"
end
end

Expand Down
12 changes: 12 additions & 0 deletions spec/plsql/package_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@
expect(plsql.test_package.procedure_defined?(:inexistent_procedure)).to be_falsey
end

it "should search objects via []" do
package = PLSQL::Package.find(plsql, :test_package)

[:Test_Procedure, :test_procedure, 'test_procedure', 'TEST_PROCEDURE'].each do |name_variant|
expect(package[name_variant]).to be_a PLSQL::Procedure
end

[:Test_Variable, :test_variable, 'test_variable', 'TEST_VARIABLE'].each do |name_variant|
expect(package[name_variant]).to be_a PLSQL::Variable
end
end

describe "variables" do
it "should set and get package variable value" do
plsql.test_package.test_variable = 1
Expand Down