I have one Groovy expression. (stored in master table but let's consider it as an individual string for this question)
Example of Groovy expression: if(shortName.equals("do not include")){return false;}; return true;
I want to use it in my oracle SQL query to consider this groovy expression to filter the records. Please note that the shortName is the column of the database table.
I want something like this:
SELECT * FROM MYTABLE
WHERE SOME_FFUNCTION_TO_EVALUATE_GROOVY(<GROOVY_EXPRESSION>);
Thanks in advance.
Perhaps easiest way to do is using javax.script.ScriptEngine and javax.script.ScriptEngineManager classes.
Step 1 : Download the jar files from maven repository for latest stable version of groovy libraries.
https://repo1.maven.org/maven2/org/codehaus/groovy/groovy-all/2.5.10/groovy-all-2.5.10-sources.jar
Step 2 : Load the jar file to schema using loadjava utility. Post import check data dictionary to ensure the java source is loaded to the database to appropriate schema. https://docs.oracle.com/cd/A87860_01/doc/java.817/a81358/02_load3.htm
Step 3: Create java source with a method for groovy expression evaluation.The method accepts string as input and returns 1 if expression evaluates to true and 0 when evaluated to false.This method creates instance of ScriptEngine and calls eval method to evaluate the input expression.
create or replace and resolve java source named
"GroovyEval" as
import java.math.*;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
* Java class to Evaluate Groovy String
*/
public class GroovyEval {
/**
* #param String
* #return 1 if True else 0 if False
*/
public static int evalGroovyExpr(String expr) throws ScriptException{
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("groovy");
Object result = engine.eval(expr);
int lv_output = 0;
if (result.toString().equals("true"))
{
lv_output = 1;
}
if (result.toString().equals("false"))
{
lv_output = 0;
}
return lv_output;
}
};
/
Step 4 : Create a Stored function to call the java source.
create or replace function evaluateGroovyExpr
(n number)
return number
as language java
name 'GroovyEval.evaluateGroovyExpr(String) return int';
/
Step 5: Fire the SQL query to call the function.You might use table columns to build groovy expression, but this is just a demo.
with exprtab as
(select '''do not include''.equals(''do not include'')' expr from dual)
SELECT evaluateGroovyExpr(expr) from exprtab;
Result
1
PS :
Using single quotes to frame the expression will be ideal as that wouldn't confuse JVM.
This is not one solution for all, but works for all expression that evaluates to boolean.
Tips: Idea approach to develop/debug would be to create the class in java and evaluate your expressions and then integrate it to the database.
You can use Eval function in groovy library of java using java stored procedure in DB
A simple example of Eval is given here
The documentation of Eval is given here
If you want to know how to use java stored procedure in oracle DB an example is given here
Also You have to use loadjava to load the groovy library in oracle DB
Related
How can we convert a List into HashBasedTable in Java8?
Current Code is like:
import org.glassfish.jersey.internal.guava.HashBasedTable;
import org.glassfish.jersey.internal.guava.Table;
List<ApplicationUsage> appUsageFromDB = computerDao.findAllCompAppUsages(new HashSet<>(currentBatch));
Table<String, String, Integer> table = HashBasedTable.create();
for(ApplicationUsage au: appUsageFromDB) {
table.put(au.getId(), au.getName(), au);
}
I need to store composite key in this and later fetch the same.
If those internals are guava-21 at least, you could do via their own collector, but I do not see anything wrong with what you are doing with a simple loop.
Table<String, String, ApplicationUsage> result =
appUsageFromDB.stream()
.collect(ImmutableTable.toImmutableTable(
ApplicationUsage::getId,
ApplicationUsage::getName,
Function.identity()
));
First, you should never rely on internal packages, just add Guava to you project explicitly. You can use Tables#toTable collector, if you want to have mutable table as a result, otherwise immutable one as presented in #Eugene's answer is just fine:
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.common.collect.Tables;
// ...
Table<String, String, ApplicationUsage> table2 = appUsageFromDB.stream()
.collect(Tables.toTable(
ApplicationUsage::getId,
ApplicationUsage::getName,
au -> au,
HashBasedTable::create
));
Also, your code doesn't compile, because it expects Integer as table value, but you're adding ApplicationUsage in your loop. Change types and third argument in table collector accordingly if needed.
From inside jShell script, is it possible to access or register variables that are defined in code that's also creating JShell?
Currently there seems to be no mechanism to either access or register a variable to Shell instance, or return none string types from inside JShell (like objects or lambda etc.)
ex:
import jdk.jshell.JShell;
import jdk.jshell.JShellException;
import jdk.jshell.SnippetEvent;
import java.util.List;
public class Main {
public static void main(String[] args) throws JShellException {
var localVar = 1;
JShell shell = JShell.create();
// How to register localVar variable with shell instance or access variables from scope
List events = shell.eval("var x = localVar;");
SnippetEvent event = events.get(0);
System.out.println("Kind: " + event.snippet().kind() + ", Value: " + event.value());
}
}
While you can't access local names like in your example, you can create a JShell instance that executes in the same JVM that created it. For this you would use the LocalExecutionControl. Using this execution control you could move localVar to a static field in your Main class and then access it from "inside" the JShell code with Main.localVar.
Unfortunately as the API is designed to support execution providers that could be in a different process or even a different machine, the return type is a string. If you are interested in a hack, the IJava jupyter kernel needed to an implementation of eval that returned an Object which ended up using an ExecutionControl implementation based on the DirectExecutionControl that stored the result of an eval call in a map and returned a unique id to reference that result. Then using the shell you would have to lookup the result from the id returned by eval (think of something like results.get(eval(sourceCode))). That implementation is on github in IJavaExecutionControl.java and IJavaExecutionControlProvider.java with a sample usage in CodeEvaluator.java#L72 if you are interested in taking any of it (MIT license).
For whatever reason, I cannot use a "for" construct within a query expression. What I get is the following error. The code I just what I picked that used to work -->
"error: This control construct may only be used if the computation expression builder defines a 'For' method"
#r "System.Data.Linq.dll"
#r "FSharp.Data.TypeProviders.dll"
open FSharp.Linq
open FSharp.Data.TypeProviders
[<Literal>]
let connectionString' = #"
data source = ...;
initial catalog = NORTHWND;
Integrated Security = SSPI"
type NorthwndDb =
SqlDataConnection<connectionString', Pluralize = true>
let db' = NorthwndDb.GetDataContext()
let curstomerSortedByCountry =
query { for c in db'.Customers do
sortBy c.Country
select (c.Country, c.CompanyName) }
|> Seq.cache
I was not able to test this with your code snippet (don't have a database to test this against), but I think the kind of error you are reporting would happen if you defined a variable named query somewhere in your code snippet before the query expression. For example:
let query = "oops!"
let curstomerSortedByCountry =
query { for c in [1 .. 10] do
sortBy c
select c }
error FS0708: This control construct may only be used if the computation expression builder defines a 'For' method
The reason for this is that the identifier query in query { .. } is just a variable declared in the standard F# library that has various members including query.For. If you hide this with your own declaration, then the member will not be found.
In my base-repository class
i wrote this function to make possible to retrive a sorted data collection from the DB.
T is a generic defined at Class level
public abstract class RepositoryBase<T>
where T : class
The code is this:
public IList<T> GetAll<TKey>(Expression<Func<T, bool>> whereCondition, Expression<Func<T, TKey>> sortCondition, bool sortDesc = false)
{
if (sortDesc)
return this.ObjectSet.Where(whereCondition).OrderByDescending(sortCondition).ToList<T>();
return this.ObjectSet.Where(whereCondition).OrderBy(sortCondition).ToList<T>() ;
}
My goal was to introduce a generic sort parameter so that i could call the function in this way:
repo.GetAll (model=>model.field>0, model=>model.sortableField, true)
i mean that i could specify the sorting field directly via anonymous function and so using Intellisense...
Unfortunately this function doesn't work as the last code line generate errors at compile time.
I tried also to call:
repo.GetAll<Model> (model=>model.field>0, model=>model.sortableField, true)
but this don't work.
How should i write the function to meet my goal?
i'm working with EF 5, c#, .NET 4.5
You're using ObjectSet which implements IQueryable<T>. That is extended by methods on System.Linq.Queryable, which accept Expression<Func< parameters. It is correct to use those Expression parameters, as you intend for execution to occur in the database, not locally.
A Func is an anonymous delegate, a .net method.
An Expression is a tree, which may be compiled into a Func, or may be translated into Sql or something else.
You showed us a really abstract use of the method, but not an actual use of the method, or the compiler error. I suspect the error you may be making is confusing the two type parameters.
You said:
repo.GetAll<Model> (model=>model.field>0, model=>model.sortableField, true)
But this generic parameter for this method represents the type of sortableField. If sortableField isn't a Model - this is wrong.
Instead, you should be doing something like this:
Repository<Person> myRepo = new Repository<Person>();
myRepo.GetAll<DateTime>(p => p.Friends.Count() > 3, p => p.DateOfBirth, true);
If specifying the sort type breaks your intended pattern of usage, consider hiding that key by using an IOrderer: Store multi-type OrderBy expression as a property
I am an experienced programmer learning Ruby (and liking it a lot).
I'm working on setting up a database using SQLite3.
In order to better learn Ruby, I'm tracing into SQLite3.
What I don't understand is, where is the code for #new for the Database and Statement classes.
Actually, I expect not a #new method, but a #initialize method.
SQLite3::Database.new(file, options = {})
SQLite3::Statement.new(db, sql)
The above two statements are from the documentation.
But in my code when I try to trace into this
$db = SQLite3::Database.new"MyDBfile"
it just steps over.
Then later on when I try to trace into
#$db.execute
I do get into the #execute method in the Database.rb file, but then it calls the #prepare method where I try to step into
stmt = SQLite3::Statement.new( self, sql )
but again no luck. It just steps over it.
I've scoured the source code, done searches etc but I cannot locate the initialize methods that are being called. Where are they ?
Thank you for considering this question.
The initialize method for SQLite3::Database is implemented in C:
/* call-seq: SQLite3::Database.new(file, options = {})
*
* Create a new Database object that opens the given file. If utf16
* is +true+, the filename is interpreted as a UTF-16 encoded string.
*
* By default, the new database will return result rows as arrays
* (#results_as_hash) and has type translation disabled (#type_translation=).
*/
static VALUE initialize(int argc, VALUE *argv, VALUE self)
Similarly for SQLite3::Statement:
/* call-seq: SQLite3::Statement.new(db, sql)
*
* Create a new statement attached to the given Database instance, and which
* encapsulates the given SQL text. If the text contains more than one
* statement (i.e., separated by semicolons), then the #remainder property
* will be set to the trailing text.
*/
static VALUE initialize(VALUE self, VALUE db, VALUE sql)
The Ruby debugger doesn't know how to step into C functions (assuming the SQLite3 extensions have even been compiled with debugging support) so it skips over them.