How to obtain Entity from Query with Kotlin Exposed DSL? - kotlin

I`d like to use Exposed in Ktor. The simplest question is how can I get an Entity from Query options?
Such as these code:
/**
* get when exist
*/
fun checkExist(phone: String): DbUser? {
return transaction(db) {
addLogger(StdOutSqlLogger)
DbUser
.select { DbUser.phoneNumber eq phone }
.firstOrNull()
.??? // how to converter ResultRow to Entity ?
}
}
I want to check whether the user existing when login and get info when existing. But I can only get the reuslt with type ResultRow, How can I converter it to DbUser object?
I got a way in this Kotlin exposed DSL Query mapping but it is so clumsy and time wasting. How can I accomplish it easily?

Please check wiki article.
In your case it can be resolved in two ways:
DbUser.select { DbUser.phoneNumber eq phone }.firstOrNull()?.let { Entity.wrapRow(it) }
If Entity is mapped to DbUser table:
Entity.find { DbUser.phoneNumber eq phone }.limit(1).firstOrNull()

Related

Can I use TypeOrm's FindOperators inside a base class without getting bad SQL Unknown column '_type' in 'where clause'

I am trying to write a base class for CRUD operations for "typeorm": "~0.2.45" under "#nestjs/typeorm": "~8.0.3" using node v14.19.3.
The base class looks like this:
export class CrudService<T> {
protected repository: Repository<T>;
constructor(repository: Repository<T>) {
this.repository = repository;
}
...
// Minimized code example
async find() {
return this.repository.find({
where: {
created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
}
});
}
}
This generates the following SQL query (which is wrong), it seems to use the Between() object as a literal equality comparison.
query failed: SELECT ... FROM `carts` `CartEntity` WHERE `CartEntity`.`created` = ?
-- PARAMETERS: {
"_type":"between",
"_value":[
"2022-06-21T14:18:00.000Z",
"2022-06-21T14:19:00.000Z"
],
"_useParameter":true,
"_multipleParameters":true
}
If I implement the same code inside the CartsEntity service like this:
#Injectable()
export class CartsService extends CrudService<CartEntity> {
constructor(
#InjectRepository(CartsRepository) repository: CartsRepository
) {
super(repository);
}
...
async find() {
return this.repository.find({
where: {
created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
}
});
}
It works fine and retrieves the data with valid SQL using BETWEEN on MySql.
I am wondering what is wrong here since I am using the same instance of repository in both code examples. I tried looking at the TypeOrm FindOperator logic but could not pinpoint it.
It turns out that the problem is a difference in the typeorm npm versions I was using.
The CrudEntity described above is inside a private npm using typeorm 0.2.45 as are my microservices extending CrudEntity like the CartEntity above.
Since #nestjs/typeorm is tagged to typeorm 0.2.34 the type was not the same for FindOperator and thus returned as an object condition instead of a FindOperator generating the proper BETWEEN SQL statement.
Basically, make sure all typeorm versions are the same across all your projects sharing code.

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

Why association resource is not binding

I am using spring data rest. When I try to create a resource using post method with application/json using following object, association resources are not binded although they are already present in db
{
screeName : 'adsaf',
screenType : {
screenTypeId : 1,
screenTypeName : 'Fixed'
}
}
Why? Is there anyother way of accomplishing this task other than separately setting associations? I am asking this question because if I manually receive this form in a controller and use ObjectMapper to deserialize and then save this object, all associations would be set. Then why its not happening in spring data rest
Spring Data REST works with links to resources so you have to change your payload to something like this:
POST http://localhost:8080/api/screens
{
"screenName": "adsaf",
"screenType": "http://localhost:8080/api/screenTypes/1"
}
If you need to save ScreenType when you POST Screen object too, you should turn off the exporting of your ScreenType repository:
#RepositoryRestResource(exported = false)
public interface ScreenTypeRepo extends JpaRepository<ScreenType, ...> {
}
and add cascading (at least PERSIST) to your screenType field in Screen entity:
public class Screen {
//...
#ManyToOne(cascade = CascadeType.PERSIST)
ScreenType screenType;
}
That's mean that ScreenType will be managed by Screen. In this case you would be able to use a payload like this:
POST http://localhost:8080/api/screens
{
"screenName": "adsaf",
"screenType": {
"screenTypeName": "Fixed"
}
}
to create a new ScreenType simultaneously with Screen.
This can be done using Custom HttpMessageConverter. check following thread.
Creating Resource with references using spring data rest

TYPO3 6.2 get Properties with values of Table

I have the following problem: When I use a Model/Repository with a different mapping, I don't get any property and values.
I've mapped the Repository to fetch the data from table sys_files.
I do get the UID, I also do get the PID. Unfortunately, I do not get any other property or the value.
My Repository is a simple Repository mapped to sys_files.
Unfortunately, I do not get any orther property.
Thanks a lot.
Greetz
Have you defined the mapping in the ext_typoscript_setup.txt?
config.tx_extbase {
persistence {
classes {
Vendor\Package\Domain\Model\MyModel {
mapping {
tableName = sys_file
}
}
}
}
}
You also need to assign the needed fields in your domain model.
namespace Vendor\Package\Domain\Model;
class MyModel
{
/**
* #var string
*/
protected $identifier;
public function getIdentifier()
{
return $this->identifier;
}
public function setIdentifier($identifier)
{
$this->identifier = $identifier;
}
}
There is a checklist when you mapping a model to a table:
1. Create the ext_typoscript_setup.txt file in the extension root path.
There you have to write the following code:
config.tx_extbase{
persistence {
classes {
YourModel.mapping{
table = table_you_want_to_map
}
}
}
}
Avoid to add backslash before model namespace
3. Clear cache from install tool. If nothing happens, then, try to delete the typo3temp/autoload folder.
4. The fields from the model should be camelCase.
Example of field: field_name in your model will be fieldName
5. Check the getters in your model.
Okay, problem solved - almost.
I can't get hash values. I don't know why but it is how it is.
I get the values of each column except "identifier_hash", "folder_hash". These attributes are always NULL.
Now I only have to make a new file_reference record in my db when I add a new relation.

Yii Behaviors and scenario

i have a behavior for my models, the behavior has beforeFind, beforeSave, in methods i override user_id, something like:
...
public functio beforeSave() {
$this->owner->user_id = Yii::app()->user->id
}
I have model User, how can i disable behavior for registration new user?
Saving code:
$user = new User();
$user->id = 1332;
$user->field1 = 'data';
$user->save();
but on save i have null in $user->id (because work behavior).
i tried
$user->disableBehaviors();
$user->detachBehavior();
Without result.
Maybe its not right way? I create behaviors for identify users in system (find only user something, save only with user id...), but that if i have new user with full previegies, i should again detach behaviors?
If condition can be changed in future I just pass it as callback parameter into behavior from model.
This give you a bit more control over the condition. Hence, behavior becomes more reusable - if it is used by several models this condition can be unique for each.
Example below is a bit simplified, but you should get the idea.
Behavior:
class SomeBehavior extends CActiveRecordBehavior
{
public $trigger;
public function beforeSave($event)
{
if(!call_user_func($this->trigger))
return;
// do what you need
$this->owner->user_id = Yii::app()->user->id;
}
}
Model:
class SomeModel extends CActiveRecord
{
public function behaviors()
{
$me=$this;
return array(
'some'=>array(
'class'=>'SomeBehavior',
'trigger'=>function() use($me){
return $me->scenario=='some-scenario';
}
)
);
}
}
Also I use PHP 5.3. So, I use closure for trigger callback.
If your PHP version is less than 5.3 - anything callable can be used instead. Check here http://www.php.net/manual/en/function.is-callable.php
Because of behavior is a method, you can declare your own logic inside.
The model knows about its scenario, so there is no problem to return different arrays for different conditions:)
Hope it be helpful for somebody.
You can check Yii::app()-user->isGuest to determine if the user is logged in or not. or you can just try looking for the null. Like this:
if (!Yii::app()->user->isGuest)
$this->owner->user_id = Yii::app()->user->id;
or
if (null !== Yii::app()->user->id)
$this->owner->user_id = Yii::app()->user->id;