Intersystems caché - relationale mapping (custom sql storage) - odbc

I have more globals in caché db with same data structure. For each global I defined class with SQL storage map, but I need to do it generically for all globals. Is it possible to define one class with sql storage map which will be used for mapping before every SQL query execution? I need to avoid class declaration for each global which I need to be accessible via SQL. I use ODBC for execute SQL statements.
If someone can help me, i will very appreciate it
My globals looks like this:
^glob1("x","y","SL",1) = "Name"
^glob1("x","y","SL",1,"Format") = "myFormat"
^glob1("x","y","SL",1,"Typ") = "my Type"
^glob1("x","y","SL",2) = "Name2"
^glob1("x","y","SL",2,"Format") = "myFormat2"
^glob1("x","y","SL",2,"Typ") = "Type2"
^nextGlob("x","y","SL",1) = "Next Name"
^nextGlob("x","y","SL",1,"Format") = "Next myFormat"
^nextGlob("x","y","SL",1,"Typ") = "my Type"
^another("x","y","SL",13) = "Another Name"
^another("x","y","SL",13,"Format") = "Another myFormat"
^another("x","y","SL",13,"Typ") = "Another Type"
I want to have sql access to globals using one ObjectScript class.

If you needed only read data from Caché by ODBC. So, in ODBC you can use CALL statement. And you can write some SqlProc, which can be called by ODBC.
As I can see, all of your globals with the same structure. If it so, it will be easy. You can put something like this, in your class.
Query Test() As %Query(ROWSPEC = "ID:%String,Global:%String,Name:%String,Typ:%String,Format:%String") [ SqlProc ]
{
}
ClassMethod TestExecute(ByRef qHandle As %Binary) As %Status
{
#; Initial settings
#; List of Globals
set $li(qHandle,1)=$lb("glob1","nextGlob","another")
#; Current Global index
set $li(qHandle,2)=1
#; Current ID in global
set $li(qHandle,3)=""
Quit $$$OK
}
ClassMethod TestClose(ByRef qHandle As %Binary) As %Status [ PlaceAfter = TestExecute ]
{
Quit $$$OK
}
ClassMethod TestFetch(ByRef qHandle As %Binary, ByRef Row As %List, ByRef AtEnd As %Integer = 0) As %Status [ PlaceAfter = TestExecute ]
{
set globals=$lg(qHandle,1)
set globalInd=$lg(qHandle,2)
set id=$lg(qHandle,3)
set AtEnd=1
for {
set global=$lg(globals,globalInd)
quit:global=""
set globalData="^"_global
set globalData=$na(#globalData#("x","y","SL"))
set id=$o(#globalData#(id),1,name)
if id'="" {
set AtEnd=0
set typ=$get(#globalData#(id,"Typ"))
set format=$get(#globalData#(id,"Format"))
set Row=$lb(id,global,name,typ,format)
set $li(qHandle,3)=id
quit
} elseif $i(globalInd) {
set id=""
set $li(qHandle,2)=globalInd
}
}
Quit $$$OK
}
And then you can execute statement like this
CALL pkg.classname_test()
And as a result it will be something like on this picture

If all of the globals are the same then you could do this but it is likely that your globals are all different making a single storage map unlikely. Do you already have a data dictionary/meta data system that describes your existing globals? If so I would consider writing a conversion from your existing data dictionary definition to cache classes.

Related

Using non-scalar variables in BuildMaster otter-script plans

I'm pulling my hair out trying to get some very basic iteration working using non-execution set variables (ie setting things at Global with potential to override at lower scope).
Setting a $variable to some value works fine but I need to do something like...
foreach $DeployConfigKey in #MapKeys(%DeployConfigs)
{
...
}
So far I'm getting nowhere fast with execution errors saying "Invalid value for property Map; expected map."
Further doing something like set %executionvar = %DeployConfigs complains that a map cannot be set to a scaler value.
The variable, DeployConfigs looks like ...
%{"Web.config": ["Web.Beta.config", "Web.Release.config"]}
and is defined at Global scope.
What am I doing wrong?
I'm using buildmaster 5.7.3
Maps are specified as %(key: value), here is an example plan that should help:
set %map = %(Web.config: #("Web.Beta.config", "Web.Release.config"));
foreach $key in #MapKeys(%map)
{
set #values = %map[$key];
Log-Information `$key = $key;
Log-Information `#values = $Join(", ", #values);
}
Sleep 3;

Upper and/lower queriable values jdeveloper

I have a query form in a jspx file and i'm trying to define some of the values as case sensitive, meaning that i want to be able to find, for example, a name with all letters upper case and/or lower case and obtain the values that i would obtain if i've inserted the name correctly.
Can someone indicate me where can i find something to accomplish that?
Thanks in advance
--------Update
Code from my jspx file
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#bindings.ImplicitViewCriteriaQuery.processQuery}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"
binding="#{backingBeanScope.backing_SearchCustomer.qryId1}"
maxColumns="3" rows="2" fieldWidth="30%"
displayMode="compact" saveResultsLayout="never"
saveQueryMode="hidden" modeChangeVisible="false"/>
In a view criteria, for each criteria item there is a check box Ignore Case. Uncheck it if you want to make that search field case sensitive.
If you are using All Queriable Attributes to create your search then you can set it in queryListner method of the query component. Here are the steps:
Create a queryListener method for your query component
<af:query id="qryId1" headerText="Search" disclosed="true"
value="#{bindings.ImplicitViewCriteriaQuery.queryDescriptor}"
model="#{bindings.ImplicitViewCriteriaQuery.queryModel}"
queryListener="#{backingBeanScope.searchBean.queryListener}"
queryOperationListener="#{bindings.ImplicitViewCriteriaQuery.processQueryOperation}"
resultComponentId="::resId1"/>
Make query attributes case insensitive in queryListener method
public void queryListener(QueryEvent queryEvent)
{
QueryDescriptor qdesc = (QueryDescriptor) queryEvent.getDescriptor();
ConjunctionCriterion conCrit = qdesc.getConjunctionCriterion();
//access the list of search fields
List<Criterion> criterionList = conCrit.getCriterionList();
for (Criterion criterion: criterionList)
{
((AttributeCriterion) criterion).setMatchCase(false);
}
invokeMethodExpression( "#{bindings.ImplicitViewCriteriaQuery.processQuery}", queryEvent);
}
private void invokeMethodExpression(String expr, QueryEvent queryEvent)
{
FacesContext fctx = FacesContext.getCurrentInstance();
ELContext elContext = fctx.getELContext();
ExpressionFactory eFactory =
fctx.getApplication().getExpressionFactory();
MethodExpression mexpr =
eFactory.createMethodExpression(elContext, expr, Object.class,
new Class[]
{ QueryEvent.class });
mexpr.invoke(elContext, new Object[]
{ queryEvent });
}

ScalikeJDBC + SQlite: Cannot change read-only flag after establishing a connection

Trying to get working ScalikeJDBC and SQLite. Have a simple code based on provided examples:
import scalikejdbc._, SQLInterpolation._
object Test extends App {
Class.forName("org.sqlite.JDBC")
ConnectionPool.singleton("jdbc:sqlite:test.db", null, null)
implicit val session = AutoSession
println(sql"""SELECT * FROM kv WHERE key == 'seq' LIMIT 1""".map(identity).single().apply()))
}
It fails with exception:
Exception in thread "main" java.sql.SQLException: Cannot change read-only flag after establishing a connection. Use SQLiteConfig#setReadOnly and QLiteConfig.createConnection().
at org.sqlite.SQLiteConnection.setReadOnly(SQLiteConnection.java:447)
at org.apache.commons.dbcp.DelegatingConnection.setReadOnly(DelegatingConnection.java:377)
at org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.setReadOnly(PoolingDataSource.java:338)
at scalikejdbc.DBConnection$class.readOnlySession(DB.scala:138)
at scalikejdbc.DB.readOnlySession(DB.scala:498)
...
I've tried both scalikejdbc 1.7 and 2.0, error remains. As sqlite driver I use "org.xerial" % "sqlite-jdbc" % "3.7.+".
What can I do to fix the error?
The following will create two separate connections, one for read-only operations and the other for writes.
ConnectionPool.add("mydb", s"jdbc:sqlite:${db.getAbsolutePath}", "", "")
ConnectionPool.add(
"mydb_ro", {
val conf = new SQLiteConfig()
conf.setReadOnly(true)
val source = new SQLiteDataSource(conf)
source.setUrl(s"jdbc:sqlite:${db.getAbsolutePath}")
new DataSourceConnectionPool(source)
}
)
I found that the reason is that you're using "org.xerial" % "sqlite-jdbc" % "3.7.15-M1". This version looks still unstable.
Use "3.7.2" as same as #kawty.
Building on #Synesso's answer, I expanded slightly to be able to get config value from config files and to set connection settings:
import scalikejdbc._
import scalikejdbc.config.TypesafeConfigReader
case class SqlLiteDataSourceConnectionPool(source: DataSource,
override val settings: ConnectionPoolSettings)
extends DataSourceConnectionPool(source)
// read settings for 'default' database
val cpSettings = TypesafeConfigReader.readConnectionPoolSettings()
val JDBCSettings(url, user, password, driver) = TypesafeConfigReader.readJDBCSettings()
// use those to create two connection pools
ConnectionPool.add("db", url, user, password, cpSettings)
ConnectionPool.add(
"db_ro", {
val conf = new SQLiteConfig()
conf.setReadOnly(true)
val source = new SQLiteDataSource(conf)
source.setUrl(url)
SqlLiteDataSourceConnectionPool(source, cpSettings)
}
)
// example using 'NamedDB'
val name: Option[String] = NamedDB("db_ro") readOnly { implicit session =>
sql"select name from users where id = $id".map(rs => rs.string("name")).single.apply()
}
This worked for me with org.xerial/sqlite-jdbc 3.28.0:
String path = ...
SQLiteConfig config = new SQLiteConfig();
config.setReadOnly(true);
return DriverManager.getConnection("jdbc:sqlite:" + path, config.toProperties());
Interestingly, I wrote a different solution on the issue on the xerial repo:
PoolProperties props = new PoolProperties();
props.setDriverClassName("org.sqlite.JDBC");
props.setUrl("jdbc:sqlite:...");
Properties extraProps = new Properties();
extraProps.setProperty("open_mode", SQLiteOpenMode.READONLY.flag + "");
props.setDbProperties(extraProps);
// This line can be left in or removed; it no longer causes a problem
// as long as the open_mode code is present.
props.setDefaultReadOnly(true);
return new DataSource(props);
I don't recall why I needed the second, and was then able to simplify it back to the first one. But if the first doesn't work, you might try the second. It uses a SQLite-specific open_mode flag that then makes it safe (but unnecessary) to use the setDefaultReadOnly call.

Getting a cmdlet's dynamic parameters via reflection

Powershell exposes some parameters, "dynamic parameters", based on context. The MSDN page explains the mechanism pretty well, but the skinny is that to find out about these one must call GetDynamicParameters(), which returns a class containing the additional parameters. I need to get these parameters via reflection, and (here's the crux of it), in a ReflectionOnly context (that is, the types are loaded with ReflectionOnlyLoadFrom). So, no Assembly.InvokeMember("GetDynamicParameters").
Can this be done?
No. Reflection works against static assembly metadata. Dynamic parameters in powershell are added at runtime by the command or function itself.
Perhaps this helps:
1: Defintion of the dynamic parameters
#===================================================================================
# DEFINITION OF FREE FIELDS USED BY THE CUSTOMER
#-----------------------------------------------------------------------------------
# SYNTAX: #{ <FF-Name>=#(<FF-Number>,<isMandatory_CREATE>,<isMandatory_UPDATE>); }
$usedFFs = #{
"defaultSMTP"=#(2,1,0); `
"allowedSMTP"=#(3,1,0); `
"secondName"=#(100,1,0); `
"orgID"=#(30001,1,0); `
"allowedSubjectTypeIDs"=#(30002,1,0); `
}
# FF-HelpMessage for input
$usedFFs_HelpMSG = #{ 2="the default smtp domain used by the organizaiton. Sampel:'algacom.ch'"; `
3="comma seperated list of allowed smtp domains. Sampel:'algacom.ch,basel.algacom.ch'"; `
100="an additional organization name. Sampel:'algaCom AG')"; `
30001="an unique ID (integer) identifying the organization entry"; `
30002="comma seperated list of allowed subject types. Sampel:'1,2,1003,10040'"; `
}
2: definition of function that builds the dynamic parameters
#-------------------------------------------------------------------------------------------------------
# Build-DynParams : Used to build the dynamic input parameters based on $usedFFs / $usedFFs_HelpMSG
#-------------------------------------------------------------------------------------------------------
function Build-DynParams($type) {
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
foreach($ffName in $usedFFs.Keys) {
$ffID = $usedFFs.Item($ffName)[0]
$dynAttribCol = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$dynAttrib = New-Object System.Management.Automation.ParameterAttribute
$dynAttrib.ParameterSetName = "__AllParameterSets"
$dynAttrib.HelpMessage = $usedFFs_HelpMSG.Item($ffID)
switch($type) {
"CREATE" { $dynAttrib.Mandatory = [bool]($usedFFs.Item($ffName)[1]) }
"UPDATE" { $dynAttrib.Mandatory = [bool]($usedFFs.Item($ffName)[2]) }
}
$dynAttribCol.Add($dynAttrib)
$dynParam = New-Object -Type System.Management.Automation.RuntimeDefinedParameter($ffName, [string], $dynAttribCol)
$paramDictionary.Add($ffName, $dynParam)
}
return $paramDictionary
}
3. Function that makes use of the dynamic params
#-------------------------------------------------------------------------------------------------------
# aAPS-OrganizationAdd : This will add a new organization entry
#-------------------------------------------------------------------------------------------------------
Function aAPS-OrganizationAdd {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true,HelpMessage="The name of the new organization")]
[String]$Descr,
[Parameter(Mandatory=$false,HelpMessage="The name of the parent organization")]
[String]$ParentDescr=$null,
[Parameter(Mandatory=$false,HelpMessage="The status of the new organization [1=Active|2=Inactive]")]
[int]$Status = 1,
[Parameter(Mandatory=$false,HelpMessage="If you want to see the data of the deactivated object")]
[switch]$ShowResult
)
DynamicParam { Build-DynParams "CREATE" }
Begin {}
Process {
# do what oyu want here
}
End {}
}

Dynamic properties in Scala

Does Scala support something like dynamic properties? Example:
val dog = new Dynamic // Dynamic does not define 'name' nor 'speak'.
dog.name = "Rex" // New property.
dog.speak = { "woof" } // New method.
val cat = new Dynamic
cat.name = "Fluffy"
cat.speak = { "meow" }
val rock = new Dynamic
rock.name = "Topaz"
// rock doesn't speak.
def test(val animal: Any) = {
animal.name + " is telling " + animal.speak()
}
test(dog) // "Rex is telling woof"
test(cat) // "Fluffy is telling meow"
test(rock) // "Topaz is telling null"
What is the closest thing from it we can get in Scala? If there's something like "addProperty" which allows using the added property like an ordinary field, it would be sufficient.
I'm not interested in structural type declarations ("type safe duck typing"). What I really need is to add new properties and methods at runtime, so that the object can be used by a method/code that expects the added elements to exist.
Scala 2.9 will have a specially handled Dynamic trait that may be what you are looking for.
This blog has a big about it: http://squirrelsewer.blogspot.com/2011/02/scalas-upcoming-dynamic-capabilities.html
I would guess that in the invokeDynamic method you will need to check for "name_=", "speak_=", "name" and "speak", and you could store values in a private map.
I can not think of a reason to really need to add/create methods/properties dynamically at run-time unless dynamic identifiers are also allowed -and/or- a magical binding to an external dynamic source (JRuby or JSON are two good examples).
Otherwise the example posted can be implemented entirely using the existing static typing in Scala via "anonymous" types and structural typing. Anyway, not saying that "dynamic" wouldn't be convenient (and as 0__ pointed out, is coming -- feel free to "go edge" ;-).
Consider:
val dog = new {
val name = "Rex"
def speak = { "woof" }
}
val cat = new {
val name = "Fluffy"
def speak = { "meow" }
}
// Rock not shown here -- because it doesn't speak it won't compile
// with the following unless it stubs in. In both cases it's an error:
// the issue is when/where the error occurs.
def test(animal: { val name: String; def speak: String }) = {
animal.name + " is telling " + animal.speak
}
// However, we can take in the more general type { val name: String } and try to
// invoke the possibly non-existent property, albeit in a hackish sort of way.
// Unfortunately pattern matching does not work with structural types AFAIK :(
val rock = new {
val name = "Topaz"
}
def test2(animal: { val name: String }) = {
animal.name + " is telling " + (try {
animal.asInstanceOf[{ def speak: String }).speak
} catch { case _ => "{very silently}" })
}
test(dog)
test(cat)
// test(rock) -- no! will not compile (a good thing)
test2(dog)
test2(cat)
test2(rock)
However, this method can quickly get cumbersome (to "add" a new attribute one would need to create a new type and copy over the current data into it) and is partially exploiting the simplicity of the example code. That is, it's not practically possible to create true "open" objects this way; in the case for "open" data a Map of sorts is likely a better/feasible approach in the current Scala (2.8) implementation.
Happy coding.
First off, as #pst pointed out, your example can be entirely implemented using static typing, it doesn't require dynamic typing.
Secondly, if you want to program in a dynamically typed language, program in a dynamically typed language.
That being said, you can actually do something like that in Scala. Here is a simplistic example:
class Dict[V](args: (String, V)*) extends Dynamic {
import scala.collection.mutable.Map
private val backingStore = Map[String, V](args:_*)
def typed[T] = throw new UnsupportedOperationException()
def applyDynamic(name: String)(args: Any*) = {
val k = if (name.endsWith("_=")) name.dropRight(2) else name
if (name.endsWith("_=")) backingStore(k) = args.first.asInstanceOf[V]
backingStore.get(k)
}
override def toString() = "Dict(" + backingStore.mkString(", ") + ")"
}
object Dict {
def apply[V](args: (String, V)*) = new Dict(args:_*)
}
val t1 = Dict[Any]()
t1.bar_=("quux")
val t2 = new Dict("foo" -> "bar", "baz" -> "quux")
val t3 = Dict("foo" -> "bar", "baz" -> "quux")
t1.bar // => Some(quux)
t2.baz // => Some(quux)
t3.baz // => Some(quux)
As you can see, you were pretty close, actually. Your main mistake was that Dynamic is a trait, not a class, so you can't instantiate it, you have to mix it in. And you obviously have to actually define what you want it to do, i.e. implement typed and applyDynamic.
If you want your example to work, there are a couple of complications. In particular, you need something like a type-safe heterogenous map as a backing store. Also, there are some syntactic considerations. For example, foo.bar = baz is only translated into foo.bar_=(baz) if foo.bar_= exists, which it doesn't, because foo is a Dynamic object.

Resources