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

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.

Related

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}]
}

Where do I execute native SQL queries in Loopback 4?

I'm new to Loopback 4 and I've been trying to execute a native SQL query. I found how to do it, the thing is that don't have any clue of WHERE to put it in my code in order for it to work... here's the documentation I found.
I need to know where should I put this:
const result = await repository.execute('SELECT * FROM Products');
in my Loopback project, which has many files. My goal is to make a REST endpoint like /products/[name] with [name] being a parameter inserted dynamically to the SQL query.
You can do it in your controller class as per loopback docs https://loopback.io/doc/en/lb4/Controller.html. As you will define the REST endpoint in the controller itself you can also do the insertion there using repository.execute() e.g.
#get('/products/{name}')
async doSomething(
#param.path.string('name') name: string,
): Promise<Product> {
const sql = `SELECT * FROM some_table WHERE some_field="${name}"`;
await this.productRepository.execute(sql)
--- other lines of code & return value --
}
Personally, I would implement it as a new Repository method.
Let's say your model is called Product, then you should have src/repositories/product.repository.ts file exporting ProductRepository class already present in your project. (You can run lb4 repository to create it.)
export class Product extends DefaultCrudRepository<
Product,
typeof Product,
Product Relations
> {
constructor(#inject('datasources.db') dataSource: DbDataSource) {
super(Product, dataSource);
}
// your custom method
async selectByName(name: string): Promise<Product[]> {
const rawItems = await repository.execute('SELECT * FROM Products');
// would you like to convert raw data into Product instances?
return rawItems.map(it => new Product(it));
}
}
Then you can call this new custom repository method from your controller in the same way as you would call e.g. repository.find(filter).

Express custom GET/POST parameter binding nestjs / routing-controllers

I have a Controller (nestjs / routing-controllers) and I'm passing a GET request the following way: /collect?t=My-name
t is actually a full name which I can't change.
Bellow im injecting #QueryParams() data: CollectData, Im looking for a way (like java strong and .net) to tell the controller that fullName is actually t.
Something like
export interface CollectData{
#PropertyName('t')
fullName: string
}
I'm expecting fullName to represent the t variable.
#JsonController()
export class CollectController {
#Get('/collect')
collect(#QueryParams() data: CollectData){
return data.fullName;
}
}
You could use some sort of solution using the class-transformer library and the ValidationPipe given by Nest (it also does transformations!) and have your CollectionData class (use a class so that the data can be serialized after transpiling, interfaces go away in JavaScript) look like this:
// CollectData.ts
export class CollectData{
#Expose({ name: 'fullName' })
t: string
}
//Collect.controller.ts
#Controller() // Changed from JSONController to Controller
export class CollectController {
#Get('/collect')
collect(#Query(new ValidationPipe({ tranform: true }) data: CollectData){ //Changed from QueryParams to Query
return data.fullName;
}
}
OR in your main.ts add the app.useGlobalPipes(new ValidationPipe({ tranform: true }) to set the validation pipe to run against all your incoming requests

Introspection query for EnumValues as a GraphQL fragment in react-component

I'm building a React Native application using GraphQL (Hosted on graph.cool) with a Relay Schema.
I have a QueryRenderer in the top-level component, fetching data for the presentational components using fragments, which is working fine.
My problem: I want to do an introspection query to fetch possible enum values as a list, for a specific field in my schema and fetch these alongside the fragments.
My current query with fragments:
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
}
The MainList_items fragment:
fragment AnimalList_items on Viewer {
allAnimalCategories {
edges {
node{
id
...AnimalListRow_item
}
}
}
}
I got the following query working for fetching enumValues via introspection (using: https://www.graph.cool/forum/t/how-to-access-the-possible-values-of-an-enum-type-created-inside-the-console/23/2):
query {
__type(name: "JOURNAL_ENTRY_GENDER") {
enumValues {
name
}
}
}
But i can't seem to find a way to create a fragment that can be added to the top-level query.
I could just paste the introspection directly into the top-level query, but that would kind of work against the relay framework, as far as I understand it. Since doing it this way I would have to explicitly pass the result down as a props, instead of letting the presentational component specify what it needs and supplying that as a fragment to the QueryRenderer at the top-level and letting the relay framework implicitly pass the query result down to the component.
After some tinkering around i found a way to solve it - it leaves two places to maintain the fragments query, but it was the only way I found that solved it. :)
In my component i defined the following fragment:
fragment GenderTile_items on __Type {
enumValues{
name
}
}
Then in my main container, i expanded the query in the QueryRenderer with the following
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
__type(name: "JOURNAL_ENTRY_GENDER"){
...GenderTile_items
}
}
The resulting enum data from the QueryRenderer is then available in the successblock by passing 'props.__type' down to the component with the corresponding fragment and from there accessing props.items.enumValues (As the prop for the data was defined as 'items' in the fragment (e.g GenderTile_items when following the naming convention 'FileName_propName'. (https://facebook.github.io/relay/docs/fragment-container.html#data-dependencies-with-graphql)).
I then ran into the problem where i wanted to fetch more than one type of enums and the query returned an error with duplicate __type assignments. This can be fixed this by using alias' like this:
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
genderEnums: __type(name: "JOURNAL_ENTRY_GENDER"){
...GenderTile_items
}
otherEnums: __type(name: "JOURNAL_ENTRY_OTHER"){
...OtherComponent_items
}
}
The data is then available via props.[alias] (e.g. 'props.genderEnums' and 'props.otherEnums'), which you then pass to the component with the fragment and as above access it via props.items.enumValues.
Hope that made sense for anyone else running into the same problem as me. :D

What is "bw_and" in hibernate query

I found a strange query implemented in my project, when I debug and inspect the persistance.query Object just before it call getResultList() method, the queryString I found is :
FROM AuthorityTbl a WHERE bw_and(a.setupFiltersIn, :setupFiltersIn) <> 0
This query is working fine and fetching all data from authority table where setupFiltersIn = :setupFiltersIn.
I am not able to understand yet what is bw_and in this query syntax.
Could anyone have any idea?
I am using sqlServer2014 and direct query with bw_and is not acceptable by sqlServer.
In My application below class is used which register bw_and as bitwise operator
public class ExtendedMSSQLServerDialect extends SQLServerDialect {
public ExtendedMSSQLServerDialect() {
super();
registerFunction("bw_and", new BitwiseSQLFunction(BitwiseSQLOperator.AND, "bw_and"));
registerFunction("bw_or", new BitwiseSQLFunction(BitwiseSQLOperator.OR, "bw_or"));
registerFunction("cast_text_to_varchar_of_length", new CastTextToVarcharSQLFunction("cast_text_to_varchar_of_length"));
}
}