WSO2 MI Validators and Array query parameters for a Data Service - wso2

I don't know how to create a validator for 2 variables:
Q1. An user code that needs to be checked if exists prior to running the SQL query. I have an endpoint to check if the user code exists or not, how do I make it into a validator?
Q2. An array of dates, the best I could do was to use a pattern validator. I know there's also the possibility to set a parameter with paramType="array" and sqlType="date", but how can I configure this in the query parameters of the resource?
Please check the Data Service definition below:
<data name="APIDataService" serviceNamespace="" serviceGroup="" transports="http https local">
<description />
<config id="postgresDataService">
<property name="carbon_datasource_name">APIPostgres</property>
</config>
<!-- TODO: Q1. Here is the resource I want to use to validate the user code -->
<query id="validateUserCode" useConfig="postgresDataService">
<sql>
SELECT ( EXISTS ( SELECT 1
FROM user
WHERE code ILIKE :user_code ) )::INT AS does_user_exist
</sql>
<param name="user_code" sqlType="string" />
<result element="result">
<element column="does_user_exist" name="doesUserExist" xsdType="integer" />
</result>
</query>
<resource method="GET" path="validateUserCode">
<call-query href="validateUserCode">
<with-param name="user_code" query-param="user_code" />
</call-query>
</resource>
<query id="apiReportUserTotalEventsByDay" useConfig="postgresDataService">
<sql>
SELECT
calendar_date,
record_date,
user_code,
event_type_id,
event_count
FROM user_event
WHERE 1=1
AND calendar_date BETWEEN :calendar_date_start AND :calendar_date_end
AND record_date = ANY( ('{'||:record_date_array||'}')::DATE[] )
AND user_code = :user_code
</sql>
<!-- TODO: Q1. Here is the user code I want to validate -->
<param name="user_code" paramType="scalar" sqlType="string" />
<param name="calendar_date_start" paramType="scalar" sqlType="date" />
<param name="calendar_date_end" paramType="scalar" sqlType="date" />
<!-- TODO: Q2. Here is the array of date that I want to know
how I could convert into an paramType="array" sqlType="date" -->
<param name="record_date_array" paramType="scalar" sqlType="string" >
<validatePattern pattern="\s*\d{4}-\d{2}-\d{2}\s*(,\s*\d{4}-\d{2}-\d{2}\s*)*" />
</param>
<result element="result">
<element column="calendar_date" name="calendar_date" xsdType="string" />
<element column="record_date" name="record_date" xsdType="string" />
<element column="user_code" name="user_code" xsdType="string" />
<element column="event_type_id" name="event_type_id" xsdType="integer" />
<element column="event_count" name="event_count" xsdType="integer" />
</result>
</query>
<resource method="GET" path="apiReportUserTotalEventsByDay">
<call-query href="apiReportUserTotalEventsByDay">
<with-param name="user_code" query-param="user_code" />
<with-param name="calendar_date_start" query-param="calendar_date_start" />
<with-param name="calendar_date_end" query-param="calendar_date_end" />
<with-param name="record_date_array" query-param="record_date_array" />
</call-query>
</resource>
</data>

Related

WSO2 Update SQL Query with optional parameters

I'm writing a sql update query. I have tried to do it both in DbReport and in DataService.
The table has 5 fields (the id + 4 more) and if I only want to update the first parameter, the others will set to null in database.
Example:
Url --> http://localhost/myservice?id=xxx
Body ( only sent "param_1" value:
{
"body":{
"PARAM_1": 1670217
}
}
DataService
<operation name="updateRecargasById">
<call-query href="updateRecargasById">
<with-param name="PARAM_1" query-param="PARAM_1" />
<with-param name="PARAM_2" query-param="PARAM_2" />
<with-param name="PARAM_3" query-param="PARAM_3" />
<with-param name="PARAM_4" query-param="PARAM_4" />
<with-param name="ID" query-param="ID" />
</call-query>
</operation>
<query id="updateQuery" useConfig="configDS">
<sql>UPDATE TABLE SET PARAM_1 = :PARAM_1, PARAM_2= :PARAM_2, PARAM_3= :PARAM_3, PARAM_4= :PARAM_4 WHERE ID</sql>
<param name="PARAM_1" ordinal="1" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_2" ordinal="2" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_3" ordinal="3" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="PARAM_4" ordinal="4" paramType="SCALAR" sqlType="STRING" optional="true" type="IN" />
<param name="ID" ordinal="5" paramType="SCALAR" sqlType="STRING" type="IN" />
</query>
Sequence
<dataServiceCall serviceName="updateDS">
<operations type="single">
<operation name="updateQuery">
<param evaluator="xml" expression="$body//PARAM_1" name="PARAM_1"/>
<param evaluator="xml" expression="$body//PARAM_2" name="PARAM_2"/>
<param evaluator="xml" expression="$body//PARAM_3" name="PARAM_3"/>
<param evaluator="xml" expression="$body//PARAM_4" name="PARAM_4"/>
<param evaluator="xml" expression="get-property('uri.var.id')" name="ID"/>
</operation>
</operations>
<source type="inline"/>
<target type="body"/>
</dataServiceCall>
Is there any way to write this query to set only the fields setting in the request body?
Kind regards!!
......................

WSO2 : Database polling tutorial timestamp is not updating

I followed following sample with one different i used MS SQL database.
http://wso2.com/library/tutorials/2013/11/scheduled-database-polling-with-wso2-data-services-server/
I am observing that polling is working as expected but timestamp (datetime column in sql is not getting updated)
Here is my DSS XML
<data enableBatchRequests="true" name="PollingService" serviceNamespace="http://ws.wso2.org/dataservice/samples/eventing_sample" transports="http https local">
<config enableOData="false" id="Default">
<property name="driverClassName">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<property name="url">jdbc:sqlserver://geoshieldsp3\sqlexpress;databaseName=RahulTest</property>
<property name="username">sa</property>
<property name="password">CSSL#2014</property>
</config>
<query id="pollingQuery" output-event-trigger="pollingTrigger" useConfig="Default">
<sql>select x.[Call Number], x.Priority, x.Call_Type, x.DispatchDate,y.total from CADFeeds as x left join 
(select *,count([Call Number]) over() as total from CADFeeds ) as y on x.[Call Number]=y.[Call Number] 
where x.DispatchDate > (select TIMESTAMP from Timestamp where id=1)</sql>
<result element="Calls" rowName="call">
<element column="Call Number" name="CallNumber" xsdType="string"/>
<element column="Priority" name="Priority" xsdType="float"/>
<element column="Call_Type" name="Call_Type" xsdType="string"/>
<element column="DispatchDate" name="DispatchDate" xsdType="string"/>
<element column="total" name="count" xsdType="integer"/>
</result>
</query>
<query id="UpdateTimeStamp" useConfig="Default">
<sql>update dbo.Timestamp set timestamp = GETDATE() where ID=1</sql>
<param name="timestamp" ordinal="2" sqlType="STRING"/>
</query>
<event-trigger id="pollingTrigger">
<expression>//*[local-name()='count' and namespace-uri()='http://ws.wso2.org/dataservice/samples/eventing_sample']>0</expression>
<target-topic>polling_Topic</target-topic>
<subscriptions>
<subscription>http://localhost:8280/services/PollingProxy</subscription>
</subscriptions>
</event-trigger>
<operation name="PollingOperation">
<call-query href="pollingQuery"/>
</operation>
<operation name="UpdateTimeStamp">
<call-query href="UpdateTimeStamp">
<with-param name="timestamp" query-param="timestamp"/>
</call-query>
</operation>
</data>
Here is the DB schema for timestamp table
CREATE TABLE [dbo].[Timestamp](
[ID] [int] NULL,
[timestamp] [datetime] NULL
) ON [PRIMARY]
I do not see anything in the log or command prompt related to timestamp update.
Any help is greatly appreciated.
Thanks,
Rahul
There seems to be a mismatch between the operation and the query.
For the below SQL, query param is not needed as there are no arguments supplied.
Please try the following.
<operation name="UpdateTimeStamp">
<call-query href="UpdateTimeStamp">
</call-query>
</operation>
<query id="UpdateTimeStamp" useConfig="Default">
<sql>update dbo.Timestamp set timestamp = GETDATE() where ID=1</sql>
</query>

Create Data Service with inner join

I'm trying to create a service with an inner join query but it returns this error:
org.postgresql.util.PSQLException: A result was returned when none was expected.
This is my service:
<data name="consultarPersona" transports="http https local">
<config enableOData="true" id="mi_datasource">
<property name="carbon_datasource_name">fuente_datos</property>
</config>
<query id="contactos_registrados" useConfig="mi_datasource">
<sql>select * from t_contacto inner join t_datos_contacto on t_contacto.id = t_datos_contacto.id</sql>
</query>
<operation name="obtenerDatosContactos">
<call-query href="contactos_registrados"/>
</operation>
</data>
You should specify which columns do you want to return and generate the response, the result is an service like this:
<data name="consultarPersona" transports="http https local">
<config enableOData="true" id="mi_datasource">
<property name="carbon_datasource_name">fuente_datos</property>
</config>
<query id="contactos_registrados" useConfig="mi_datasource">
<sql>select name, age from t_contacto inner join t_datos_contacto on t_contacto.id = t_datos_contacto.id</sql>
<result element="contactoCollection" rowName="contacto">
<element column="name" name="name" xsdType="xs:string"/>
<element column="age" name="age" xsdType="xs:string"/>
</result>
</query>
<operation name="obtenerDatosContactos">
<call-query href="contactos_registrados"/>
</operation>
</data>
I hope this coudl help you.

wso2 dss mysql error

I am getting this error while I am trying to test the data service on the wso2 dss
DS Fault Message: Error in
'SQLQuery.processStoredProcQuery'DS Code: DATABASE_ERRORSource Data
Service:-Name: CustomerDSLocation: \CustomerDS-1.0.0.dbsDescription:
N/ADefault Namespace: http://ws.wso2.org/dataserviceCurrent Request
Name: op1Current Params: {Name=?, NID=?}Nested Exception:-DS Fault
Message: Error in 'createProcessedPreparedStatement'DS Code:
UNKNOWN_ERRORNested Exception:-java.sql.SQLException: Parameter index
of 3 is out of range (1, 0)
any suggestions?
edited: The bds file is as follows, this is a sample case mentioned in the wso2 documentation.
<data name="CustomerDS">
<config id="default">
<property name="org.wso2.ws.dataservice.driver">com.mysql.jdbc.Driver</property>
<property name="org.wso2.ws.dataservice.protocol">jdbc:mysql://localhost:3306/CustomersDatabase</property>
<property name="org.wso2.ws.dataservice.user">root</property>
<property name="org.wso2.ws.dataservice.password">root</property>
</config>
<query id="q1" useConfig="default">
<sql>call getCustomer(?,?,?,?)</sql>
<result element="Entries" rowName="Entry">
<element name="Flag" column="Flag" xsdType="xs:integer" optional="true" />
<element name="Customer" column="Customer" xsdType="xs:string" optional="true" />
</result>
<param name="NID" sqlType="STRING" ordinal="1" />
<param name="Name" sqlType="STRING" ordinal="2" />
<param name="Flag" sqlType="INTEGER" type="OUT" ordinal="3" />
<param name="Customer" sqlType="STRING" type="OUT" ordinal="4" />
</query>
<operation name="op1">
<call-query href="q1">
<with-param name="NID" query-param="NID" />
<with-param name="Name" query-param="Name" />
</call-query>
</operation>
</data>
WHAT WORKED FOR ME!!
I found the reference code at http://svn.wso2.org/repos/wso2/people/kasun/wso2con_2013/starbucks_2.0/dss/StarbucksDataService.dbs
and the procedure call that is finally working for me is (which changes in procedure itself)
<data name="CustomerDS">
<config id="default">
<property name="org.wso2.ws.dataservice.driver">com.mysql.jdbc.Driver</property>
<property name="org.wso2.ws.dataservice.protocol">jdbc:mysql://localhost:3306/CustomersDatabase</property>
<property name="org.wso2.ws.dataservice.user">root</property>
<property name="org.wso2.ws.dataservice.password">root</property>
</config>
<query id="q1" useConfig="default">
<sql>call getCustomer(?,?)</sql>
<result element="Entries" rowName="Entry">
<element name="Flag" column="Flag" xsdType="xs:integer" optional="true" />
<element name="Customer" column="Customer" xsdType="xs:string" optional="true" />
</result>
<param name="NID" sqlType="STRING" ordinal="1" />
<param name="Name" sqlType="STRING" ordinal="2" />
<param name="Flag" sqlType="INTEGER" type="OUT" ordinal="3" />
<param name="Customer" sqlType="STRING" type="OUT" ordinal="4" />
</query>
<operation name="op1">
<call-query href="q1">
<with-param name="NID" query-param="NID" />
<with-param name="Name" query-param="Name" />
</call-query>
</operation>
</data>
And the tentative working procedure call for now is :
DELIMITER //
CREATE procedure getCustomer(NID varchar(200),Name varchar(200))
BEGIN
DECLARE id varchar(200);
DECLARE flag int;
SET Flag = 0;
SET id = CONCAT(NID, '_' , Name);
INSERT INTO Customer(NID, Name, customerID) VALUES(NID, Name, id);
select flag, customerid from customer where customerID = id;
END//
In the query q1 call getCustomer(?,?,?,?) takes 4 arguments and in the input mapping list there are only 2 input params (IN Only). This must be the reason for the this exception. Please refer this tutorial.

Using input parameter as an optional input

Using wso2, DSS version 3.01, I am trying to have an input parameter that could be an optional parameter. A user can say, give me all the info for this specific code, or if a user does not specify any code, I want to give all the rows of data. Can you help?
Instead of creating a query for each optional parameter, you can also do the following:
<query id="selectEmployees" useConfig="default">
<sql>select * from Employees where (:employeeNumber is null or employeeNumber = :employeeNumber)</sql>
<result element="employees" rowName="employee">
<element column="lastName" name="last-name" xsdType="string"/>
<element column="firstName" name="first-name" xsdType="string"/>
<element column="email" name="email" xsdType="string"/>
<element column="salary" name="salary" xsdType="double"/>
</result>
<param defaultValue="#{NULL}" name="employeeNumber" ordinal="1" paramType="SCALAR" sqlType="INTEGER" type="IN"/>
</query>
<operation name="getEmployees">
<call-query href="selectEmployees">
<with-param name="employeeNumber" query-param="employeeNumber"/>
</call-query>
</operation>
Now you can call 'getEmployees' with 'employeeNumber' and get specific employee,
or you can call 'getEmployees' without 'employeeNumber' and get all employees.
(Calling without 'employeeNumber' is by omitting the 'employeeNumber' tag, or using 'xsi:nil="true"'.)
Obviously, you cannot query for the value 'null' this way.
ok soo for example
<query id="employeesByNumberSQL" useConfig="default">
<sql>select * from Employees where employeeNumber = ?</sql>
<result element="employees" rowName="employee">
<element column="lastName" name="last-name" xsdType="string"/>
<element column="firstName" name="first-name" xsdType="string"/>
<element column="email" name="email" xsdType="string"/>
<element column="salary" name="salary" xsdType="double"/>
</result>
<param name="employeeNumber" ordinal="1" paramType="SCALAR" sqlType="INTEGER" type="IN"/>
select * from Employees
You have two queries employeesByNumberSQL, employeesByNumberSQL1 these two are mapped togetemployeesByNumber and getemployeesByNumber2
Well you can make input parameters optional by giving default values to the input parameters. For example
<query id="MyQ" useConfig="myDS">
<sql>select cust_id,name from customer where cust_id = ?</sql>
<result element="Entries" rowName="Entry">
<element column="cust_id" name="cust_id" xsdType="string"/>
<element column="name" name="name" xsdType="string"/>
</result>
<param defaultValue="1" name="cust_id" sqlType="INTEGER"/>
</query>
Here if you do not mention the input parameters it will take the input parameter as one. Or else you need to create two queries and handle them programmatically