TypeORM ManyToMany with createsQueryBuilder - node.js-typeorm

I have, three entities, services, accounts, and the union of the two, contasservices:
Services:
#Entity({ name: 'services' })
export class ServiceEntity {
#PrimaryGeneratedColumn()
public id: number;
#OneToMany(type => AccountServiceEntity, x => x.service)
accountAndServices: AccountServiceEntity[];
#Column({ nullable: false, length: 150 })
public name: string;
}
Accounts:
#Entity({ name: 'accounts' })
export class AccountEntity {
#PrimaryGeneratedColumn()
public id: number;
#OneToMany(type => AccountServiceEntity, x => x.account)
accountAndServices: AccountServiceEntity[];
#Column({ nullable: false })
public account_type: number;
}
AccountsServices :
#Entity({ name: 'accounts_services' })
export class AccountServiceEntity {
#PrimaryGeneratedColumn()
public id: number;
#ManyToOne(() => ServiceEntity, x => x.accountAndServices,
{ primary: true, nullable: false })
service: ServiceEntity;
#ManyToOne(() => AccountEntity, x => x.accountAndServices,
{ primary: true, nullable: false })
account: AccountEntity;
#Column({ nullable: false })
public date_initial: Date;
}
How do I run a createQueryBuilder in my repository and get the following json back:
const query = this.repository.createQueryBuilder("...")
[
{
"account_name": "Gladson",
"serices": [
{
"description": "xxxx",
"date_initial": "31/07/2021"
"value": 10,00
},
{
"description": "yyy",
"date_initial": "31/07/2021"
"value": 2,00
}
]
}
]

Try this:
const queryBuilder = repository.createQueryBuilder('Account')
queryBuilder
.leftJoinAndSelect('Account.accountAndServices', 'accountAndServices')
.leftJoinAndSelect('accountAndServices.service', 'service')
.select(['Account.id', 'accountAndServices.id', 'service.description'])
await queryBuilder.getMany()

Related

How to custom GridJs pagination with supabase?

I'm software engineer in Cambodia.
I want to custom Grid.js pagination with supanase, but I faced a problem.
I don't know the solution because it's not in the documentation.
I'm using Nuxt 3
Please tell me how to implement.
The Code is below:
onMounted(() => {
grid.updateConfig({
columns: [
{ name: 'Avatar', id: 'avatar' },
{ name: 'name', id: 'name' },
{ name: 'gender', id: 'gender' },
{ name: 'email', id: 'email' },
{ name: 'phone', id: 'phone' },
{ name: 'address', id: 'address' },
],
pagination: {
enabled: true,
limit: 5,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: true,
},
server: {
keepalive: true,
data: async (opt) => {
console.log(opt)
const { data: customers, error, count } = await supabase
.from('customers')
.select('id, name, gender, email, phone, address, avatar', { count: 'exact' })
.is('deleted_at', null)
.order('created_at', { ascending: false })
return {
data: customers.map((customer) => [
customer.avatar,
customer.name,
customer.gender,
customer.email,
customer.phone,
customer.address,
]),
total: count,
}
},
},
width: '100%',
search: true,
pagination: true,
fixedHeader: true,
className: {
td: 'sr-td-class',
table: 'sr-table',
},
})
grid.render(table.value)
})
I found resolve:
GridJs configuration:
onMounted(() => {
grid.updateConfig({
columns: [
{ name: 'Avatar', id: 'avatar' },
{ name: 'name', id: 'name' },
{ name: 'gender', id: 'gender' },
{ name: 'email', id: 'email' },
{ name: 'phone', id: 'phone' },
{ name: 'address', id: 'address' },
],
pagination: {
enabled: true,
limit: 5,
server: {
url: (prev, page, limit) => `${prev}&limit=${limit}&offset=${page * limit}`
},
summary: true,
},
server: {
keepalive: true,
data: async (opt) => {
console.log(opt)
const { data: customers, error, count } = await supabase
.from('customers')
.select('id, name, gender, email, phone, address, avatar', { count: 'exact' })
.is('deleted_at', null)
.order('created_at', { ascending: false })
return {
data: customers.map((customer) => [
customer.avatar,
customer.name,
customer.gender,
customer.email,
customer.phone,
customer.address,
]),
total: count,
}
},
},
width: '100%',
fixedHeader: true,
className: {
td: 'sr-td-class',
table: 'sr-table',
},
})
grid.render(table.value)
})
Then create server/api directory
after create file customers.ts in server/api/ directory
This is code in customers.ts file
import { serverSupabaseUser, serverSupabaseClient } from '#supabase/server'
export default defineEventHandler(async (event) => {
const user = await serverSupabaseUser(event)
const client = serverSupabaseClient(event)
const query = useQuery(event)
const from = query.page ? parseInt(query.page) * parseInt(query.limit) : 0
const to = query.page ? from + parseInt(query.limit) : query.limit
if (!user) {
throw createError({ statusCode: 401, message: 'Unauthorized' })
}
const { data, error, count } = await client
.from('customers')
.select('id, name, gender, email, phone, address, avatar', {
count: 'exact',
})
.is('deleted_at', null)
.order('created_at', { ascending: false })
.range(from, to)
return { customers: data, count }
})

sanity-algolia get error when using pt::text

I'm trying to integrate algolia search with sanity CMS using the sanity-algolia library (ref https://www.sanity.io/plugins/sanity-algolia)
But when i try to get the plain text from Portable Text rich text content using the pt::text function.
i get expected '}' following object body , and i dont really know where im missing a bracket.
(another note: since im hosting sanity by using sanity start, I am using nextjs (my frontend) to run the function instead using the /api routes in nextJS) So sanity has a webhook to this route.
details about the error:
details: {
description: "expected '}' following object body",
end: 174,
query: '* [(_id in $created || _id in $updated) && _type in $types] {\n' +
' _id,\n' +
' _type,\n' +
' _rev,\n' +
' _type == "post" => {\n' +
' title,\n' +
' "path": slug.current,\n' +
' "body": pt::text(body)\n' +
' }\n' +
'}',
start: 107,
type: 'queryParseError'
}
this is the serverless function im running:
export default async function handler(req, res) {
if (req.headers["content-type"] !== "application/json") {
res.status(400);
res.json({ message: "Bad request" });
return;
}
const algoliaIndex = algolia.initIndex("dev_kim_miles");
const sanityAlgolia = indexer(
{
post: {
index: algoliaIndex,
projection: `{
title,
"path": slug.current,
"body": pt::text(body)
}`,
},
},
(document) => {
console.log(document);
return document;
},
(document) => {
if (document.hasOwnProperty("isHidden")) {
return !document.isHidden;
}
return true;
}
);
return sanityAlgolia
.webhookSync(sanityClient, req.body)
.then(() => res.status(200).send("ok"));
}
and my post schema from sanity:
export default {
name: 'post',
title: 'Post',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'author',
title: 'Author',
type: 'reference',
to: {type: 'author'},
},
{
name: 'mainImage',
title: 'Main image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [{type: 'reference', to: {type: 'category'}}],
},
{
name: 'publishedAt',
title: 'Published at',
type: 'datetime',
},
{
name: 'body',
title: 'Body',
type: 'blockContent',
},
{
name: 'extra',
title: 'extra',
type: 'blockContent',
},
],
preview: {
select: {
title: 'title',
author: 'author.name',
media: 'mainImage',
},
prepare(selection) {
const {author} = selection
return Object.assign({}, selection, {
subtitle: author && `by ${author}`,
})
},
},
}
sanity api v1 doesnt work with functions, I was using
const sanityClient = client({
dataset: "production",
useCdn: true,
projectId: "project_id",
});
which defaults to v1, but in order to use function i added a apiVersion parameter, which made it use later api version:
const sanityClient = client({
dataset: "production",
useCdn: true,
projectId: "9dz8b3g1",
apiVersion: "2021-03-25",
});

Asp Core net Kendo ui Cannot pass decimal value to model

I'm using kendo ui to create a grid on my project. My problem is that i cannot pass a decimal value to my c# class model.
My class:
public class BlocCoefficientSettings
{
public int BlocCoefficientKey { get; set; }
public string BlocName { get; set; }
public string Category { get; set; }
public string MinMaxFloor { get; set; }
public int Rooms { get; set; }
public decimal CoefficientValue { get; set; }
public int GroupNumber { get; set; }
}
And this is my code that renders the grid
#section Scripts{
<script>
function grid_init() {
var dataSearch = {
classifierSearchKey: document.getElementById('classifierSearchKey').value
}
if (!dataSearch.classifierSearchKey == "") {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/BlocCoefficientsSettings?handler=Json",
dataType: "json",
data: dataSearch
},
update: {
url: "/Common/UpdateBlocCoefficientsSettings",
type: "POST",
dataType: "json"
}
},
batch: true,
sort: [{ field: "groupNumber", dir: "asc" }, { field: "rooms", dir: "asc" }],
schema: {
data: "results",
total: "total",
model: {
id: "blocCoefficientKey",
fields: {
blocName: { editable: false },
rooms: { editable: false, type: "number" },
minMaxFloor: { editable: false },
coefficientValue: { editable: true, type: "number", nullable: true }
}
},
},
page: 1,
serverPaging: false,
group: { field: "category" }
});
$("#grid").empty();
$("#grid").kendoGrid({
dataSource: dataSource,
editable: true,
height: 700,
sortable: true,
groupable: false,
toolbar: [{ name: "save", text: "Сохранить" }],
columns: [
{ field: "blocName", title: "Блок", width: "200px" },
{ field: "minMaxFloor", title: "Этаж", width: "70px" },
{ field: "rooms", title: "Комнат", width: "50px" },
{ field: "coefficientValue", title: "Коэффициент этажности", width: "50px" },
{ field: "category", hidden: true, groupHeaderTemplate: "Категория недвижимости: #= value #" }
]
});
}
else {
alert("Выберите застройку!");
}
}
$("#btnSearch").click(function () {
grid_init();
});
</script>
All works fine when put a whole number in the coefficientValue field. The whole number is passed to my model. But when i put a decimal number to my model is passed 0(In my example the value should be 1.5 for models[1])
How can i pass a decimal number?
I'm not sure how you are prompting for a number here, but be careful with culture settings. JSON does not support comma decimal separation, only point. Thus, you the JSON being posted has to show the value as 1.5, not 1,5 or it isn't going to parse correctly on server side.

ASP Web API - Kendo Grid and Model State

I'm using Kendo Grid and ModelState.IsValid condition on my Web API post method. When I create a new record on the grid (in fact I'm using the popup option of the grid to create a new record), it's sending the Id of my class as null, then when it comes to my controller the ModelState is always invalid because it expects the Id of my class to be 0. I solved it by changing the value of the Id on the parameterMap of the datasource when the operation is 'create' (see code below), but I really don't know if it's the best solution as it seems to me like a poor way. Is there another option to solve this issue? Thanks.
View:
$(document).ready(function () {
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "/api/products",
dataType: "json"
},
update: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "PUT"
},
destroy: {
url: function (data) {
return "/api/products/" + data.id;
},
dataType: "json",
type: "DELETE"
},
create: {
url: "/api/products",
dataType: "json",
type: "POST"
},
parameterMap: function (options, operation) {
// THIS IS MY FIX FOR NOW
if (operation === "create") {
options.id = 0;
}
return kendo.stringify(options);
},
type: "json"
},
batch: false,
pageSize: 20,
schema: {
model: {
id: "id",
fields: {
id: { editable: false, nullable: true },
name: { validation: { required: true } },
description: { validation: { required: true } }
}
}
}
});
$("#grid").kendoGrid({
dataSource: dataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "name", title: "Name" },
{ field: "description", title: "Description" },
{ command: ["edit", "destroy"], title: " ", width: "250px"
}],
editable: "popup"
});
});
Controller (I put only the post method as it was the one that got the issue):
[HttpPost]
public IHttpActionResult CreateProduct(Product product)
{
if (!ModelState.IsValid)
return BadRequest();
_productRepository.CreateProduct(product);
_productRepository.SaveProduct();
return Ok(product);
}
Model:
public class Product
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(255)]
public string Description { get; set; }
}
Repository:
public void CreateProduct(Product product)
{
_context.Products.Add(product);
}
public void SaveProduct()
{
_context.SaveChanges();
}
It might be that id field is nullable: true.
Could you remove it and add type: "number"?
fields: {
id: { editable: false, type: "number" },
name: { validation: { required: true } },
description: { validation: { required: true } }
}

Handlebars Nested Each Statement

I am attempting nest an each statement to handle the two objects that are available within my view. There is a relationship between the two objects with the userId on the card as the connection to the userId on the user table, which might be how this could work. I figure that I might have to end up registering a helper to have this work, but I'm not sure where to start. I attempted to bypass this process with the following handlebars syntax, but I get TypeError: inverse is not a function:
{{#each this.fullNameSlug ../user.fullNameSlug}}
<h5>{{this.fullNameSlug}}</h5>
{{/each}}
Here is the full view:
{{#each card}}
<div class="row">
<div class="card col-md-6 col-md-offset-3">
<div class="card-date">
<p class="card-date">{{this.cardDateSlug}}</p>
</div>
<div class="card-header">
<h3 class="card-title">{{this.title}}</h3>
{{#each this.fullNameSlug ../user.fullNameSlug}}
<h5>{{this.fullNameSlug}}</h5>
{{/each}}
</div>
<div class="card-body">
{{/each}}
Here is the route with the two objects (card, user) that are accessible in the view:
/*==== / ====*/
appRoutes.route('/')
.get(function(req, res){
models.Card.findAll({
order: 'annotationDate DESC',
include: [{
model: models.User,
where: { organizationId: req.user.organizationId },
attributes: ['organizationId', 'userId', 'fullNameSlug']
}],
limit: limitAmount.limit
}).then(function(annotation){
res.render('pages/app/activity-feed.hbs',{
card: card,
user: req.user
});
});
})
Card object:
module.exports = function(sequelize, DataTypes) {
var path = require('path');
var moment = require('moment');
var Card = sequelize.define('card', {
cardId: {
type: DataTypes.INTEGER,
field: 'card_id',
autoIncrement: true,
primaryKey: true
},
cardDate: {
type: DataTypes.DATE,
field: 'card_date',
isDate: true
},
reportLink: {
type: DataTypes.TEXT,
field: 'report_link'
},
fileAttachment: {
type: DataTypes.STRING,
field: 'file_attachment'
},
userId: {
type: DataTypes.INTEGER,
field: 'user_id'
},
discoverySourceId: {
type: DataTypes.INTEGER,
field: 'discovery_source_id'
}
},
{
freezeTableName: true,
getterMethods: {
cardDateSlug: function(){
var date = new Date(this.getDataValue('annotationDate'));
var momentDate = moment(date).utc().format("MM/DD/YYYY");
return momentDate;
}
},
classMethods: {
associate: function(db) {
Card.belongsTo(db.User, {foreignKey: 'user_id'}),
}
}
});
return Card;
}
User object:
var bcrypt = require('bcrypt-nodejs');
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('user', {
userId: {
type: DataTypes.INTEGER,
field:'user_id',
autoIncrement: true,
primaryKey: true
},
firstName: {
type: DataTypes.STRING,
field: 'first_name'
},
lastName: {
type: DataTypes.STRING,
field: 'last_name'
},
email: {
type: DataTypes.STRING,
isEmail: true,
unique: true,
set: function(val) {
this.setDataValue('email', val.toLowerCase());
}
},
password: DataTypes.STRING,
organizationId: {
type: DataTypes.INTEGER,
field: 'organization_id',
allowNull: true
},
authenticationToken: {
type: DataTypes.STRING,
field: 'authentication_token'
},
resetPasswordToken: {
type: DataTypes.STRING,
field: 'reset_password_token'
},
resetPasswordExpires: {
type: DataTypes.DATE,
field: 'reset_password_expires'
}
}, {
freezeTableName: true,
getterMethods: {
fullNameSlug: function(){
var fullName = this.getDataValue('firstName') + ' ' + this.getDataValue('lastName');
return fullName;
}
},
classMethods: {
associate: function(db) {
User.belongsToMany(db.Organization, { through: 'member', foreignKey: 'user_id'})
},
generateHash: function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
},
},
instanceMethods: {
validPassword: function(password) {
return bcrypt.compareSync(password, this.password);
},
},
});
return User;
}

Resources