[loopbackjs]how to do where not in (select xxx) query - loopbackjs

I'd love to use loopback 4 whereBuilder to build a query like 'select * from file where id not in (select fileId from workFile where workId='xxxxx')' and I tried this:
const fileIdArray = await this.workFileRepository.find({
where: {
fileId: {
eq: xxx
}
}
});
const ret = await this.fileRepository.find({
where: {
id: {
nin: fileIdArray
}
}
})
and
const ret = await this.fileRepository.find({
where: {
id: {
nin: () => {
return await this.workFileRepository.find({
where: {
fileId: {
eq: id
}
}
})
}
}
}
})
but both of them are wrong , what should i do ?
this is the error:
error TS2345: Argument of type '{ where: { id: { nin: () => (WorkFile & WorkFileRelations)[]; }; }; }' is not assignable to parameter of type 'Filter<File>'.
Types of property 'where' are incompatible.
Type '{ id: { nin: () => (WorkFile & WorkFileRelations)[]; }; }' is not assignable to type 'Condition<File> | AndClause<File> | OrClause<File> | undefined'.
Type '{ id: { nin: () => (WorkFile & WorkFileRelations)[]; }; }' is not assignable to type 'Condition<File>'.
Types of property 'id' are incompatible.
Type '{ nin: () => (WorkFile & WorkFileRelations)[]; }' is not assignable to type 'string | (string & Date) | PredicateComparison<string> | undefined'.
Type '{ nin: () => (WorkFile & WorkFileRelations)[]; }' is not assignable to type 'PredicateComparison<string>'.
Types of property 'nin' are incompatible.
Type '() => (WorkFile & WorkFileRelations)[]' is missing the following properties from type 'string[]': pop, push, concat, join, and 25 more.
86 const ret = await this.fileRepository.find({
~
87 where: {
the correct format is like this:
const ret = await this.fileRepository.find({
where: {
id: {
nin: ["xxxxxx2","xxxxxx3"]
}
}
})
but if i change to
const ret = await this.fileRepository.find({
where: {
id: {
nin: ()=>{
return ['xxxxx2','xxxx3']
}
}
}
})
its wrong, i don't know if someone know and use this framework

i found the solution , first i fetch the included ids:
const inqFileCollectionss = await this.workFileRepository.find({
where: {
workId: {
eq: id
}
}
});
const inqFileIds = inqFileCollectionss.map(item => item.fileId)
and then i fetch like this:
const data = await this.fileRepository.find({
where: {
id: {
nin: inqFileIds
}
},
limit: pageSize,
skip: pageIndex
})

Related

failed mock stripe on lambda function : TypeError: stripe_1.default is not a constructor

i want to mock stripe sdk on lambda function, this is how i create instance of stripe on config
export const stripe = new Stripe(STRIPE_SECRET_KEY, {
apiVersion: '2020-08-27',
typescript: true,
maxNetworkRetries: 2,
});
and this is how i use the stripe instance on my lambda function
import { stripe, STRIPE_TEST_USERS } from '../config';
await stripe.invoices.retrieve(id)
and this is what i got
TypeError: stripe_1.default is not a constructor
36 | });
37 |
> 38 | export const stripe = new Stripe(STRIPE_SECRET_KEY, {
| ^
39 | apiVersion: '2020-08-27',
40 | typescript: true,
41 | maxNetworkRetries: 2,
dont get me wrong , i have tried all thing i can do, i have tried this method
1st
jest.mock("stripe", () => {
return jest.fn().mockImplementation(()=> {
return {
invoices: {
retrieve: () =>jest.fn(),
},
};
});
});
2nd
jest.mock('stripe', () =>
jest.fn().mockImplementation(() => ({
invoices: {
retrieve: () => jest.fn()
},
}))
);
3rd
jest.mock('stripe', () => ({
...jest.mock('stripe'),
Stripe: jest.fn().mockImplementation(() => {
return {
invoices: jest.fn().mockImplementation(() => {
return {
retrieve: jest.fn(),
};
}),
};
}),
}));
but none of those work, any solution?
i think you can use this, u need to import module first
jest.mock("stripe", () => {
return {
__esModule: true,
default: jest.fn().mockImplementation(() => {
return {
subscriptions: {
update: () => updateMock(),
},
};
}),
};
});
update is what you want to mock

Chart.js - add gradient instead of solid color

I'm using chart.js but I cannot figure out how to make a background color with a gradient looking like that: http://jsfiddle.net/4vobe59a/
I read a few questions here on Stack Overflow but with my knowledge I'm still not able to implement them to my case. What can I try next?
import React, { useMemo } from 'react'
import { ChartOptions } from 'chart.js'
import { LineChart as BaseLineChart } from '../base/LineChart'
import { colorScheme } from './colors'
const formatter = (
ranges: any[],
data: any,
labelKey: string,
dataKey: string
) => {
const result = []
for (const range of ranges) {
const item = data.find((item: any) => item[labelKey] === range)
if (item) {
result.push(item[dataKey])
} else {
result.push(null)
}
}
return result
}
const getDefaultLabels = (data: any, labelKey: string) => {
const labels: { [key: string]: string } = {}
for (const key of Object.keys(data)) {
for (const item of data[key]) {
labels[item[labelKey]] = item[labelKey]
}
}
return Object.values(labels)
}
const buildData = ({
data,
dataKey,
labelFormatter,
labelKey,
getLabels,
}: {
data: any
dataKey: string
labelFormatter?: (value: string) => string
labelKey: string
getLabels?: (value: any, labelKey: string) => string[] | number[]
}) => {
const labels =
getLabels && typeof getLabels === 'function'
? getLabels(data, labelKey)
: getDefaultLabels(data, labelKey)
return {
labels,
datasets: Object.keys(data).map((key: string, index) => ({
label: labelFormatter ? labelFormatter(key) : key,
data: formatter(labels, data[key], labelKey, dataKey),
backgroundColor: colorScheme[index],
borderColor: colorScheme[index],
})),
}
}
function LineChart({
options = {},
data,
dataKey,
labelKey,
labelFormatter,
getLabels,
}: {
options?: Partial<ChartOptions<'line'>>
data: any
dataKey: string
labelKey: string
labelFormatter?: (value: string) => string
getLabels?: (value: any, labelKey: string) => string[] | number[]
}) {
const chartData = useMemo(
() => buildData({ data, dataKey, labelKey, labelFormatter, getLabels }),
[data, dataKey, labelFormatter, labelKey, getLabels]
)
return <BaseLineChart options={options} data={chartData} />
}
export default LineChart

How to write unit test case for JWT strategy

I am new to passport.js and trying to cover the unit test case for my JWT strategy. Can anyone suggest how to do that?
// Setup JWT strategy for all requests
passport.use(
new JWTStrategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: JWT_PRIVATE_KEY,
},
async (jwtPayload: any, done: any) => {
const isUser = jwtPayload.type === EntityType.User;
const model = isUser ? userModel : vendorModel;
try {
const document = await model.findOne({ _id: jwtPayload.id });
if (document) {
return done(null, jwtPayload);
} else {
return done(null, false);
}
} catch (err) {
return done(err, false);
}
},
),
);
Unit test solution:
index.ts:
import passport from 'passport';
import { Strategy as JWTStrategy, ExtractJwt } from 'passport-jwt';
import { userModel, vendorModel, EntityType } from './models';
const JWT_PRIVATE_KEY = 'secret 123';
passport.use(
new JWTStrategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: JWT_PRIVATE_KEY,
},
async (jwtPayload: any, done: any) => {
console.log('123123');
const isUser = jwtPayload.type === EntityType.User;
const model = isUser ? userModel : vendorModel;
try {
const document = await model.findOne({ _id: jwtPayload.id });
if (document) {
return done(null, jwtPayload);
} else {
return done(null, false);
}
} catch (err) {
return done(err, false);
}
},
),
);
models.ts:
export enum EntityType {
User = 'User',
}
export const userModel = {
async findOne(opts) {
return 'real user document';
},
};
export const vendorModel = {
async findOne(opts) {
return 'real vendor document';
},
};
index.test.ts:
import { Strategy as JWTStrategy, ExtractJwt, VerifyCallback, StrategyOptions } from 'passport-jwt';
import passport from 'passport';
import { userModel, vendorModel } from './models';
jest.mock('passport-jwt', () => {
const mJWTStrategy = jest.fn();
const mExtractJwt = {
fromAuthHeaderAsBearerToken: jest.fn(),
};
return { Strategy: mJWTStrategy, ExtractJwt: mExtractJwt };
});
jest.mock('passport', () => {
return { use: jest.fn() };
});
describe('62125872', () => {
let verifyRef;
beforeEach(() => {
const mJwtFromRequestFunction = jest.fn();
(ExtractJwt.fromAuthHeaderAsBearerToken as jest.MockedFunction<
typeof ExtractJwt.fromAuthHeaderAsBearerToken
>).mockReturnValueOnce(mJwtFromRequestFunction);
(JWTStrategy as jest.MockedClass<any>).mockImplementation((opt: StrategyOptions, verify: VerifyCallback) => {
verifyRef = verify;
});
});
it('should verify using user model and call done with jwtpayload if user document exists', async () => {
const payload = { type: 'User', id: 1 };
const mDone = jest.fn();
jest.spyOn(userModel, 'findOne').mockResolvedValueOnce('mocked user document');
await import('./');
await verifyRef(payload, mDone);
expect(passport.use).toBeCalledWith(expect.any(Object));
expect(JWTStrategy).toBeCalledWith(
{ jwtFromRequest: expect.any(Function), secretOrKey: 'secret 123' },
expect.any(Function),
);
expect(ExtractJwt.fromAuthHeaderAsBearerToken).toBeCalledTimes(1);
expect(userModel.findOne).toBeCalledWith({ _id: 1 });
expect(mDone).toBeCalledWith(null, { type: 'User', id: 1 });
});
it("should verify using user model and call done with false if user document doesn't exist", async () => {
const payload = { type: 'User', id: 1 };
const mDone = jest.fn();
jest.spyOn(userModel, 'findOne').mockResolvedValueOnce('');
await import('./');
await verifyRef(payload, mDone);
expect(passport.use).toBeCalledWith(expect.any(Object));
expect(JWTStrategy).toBeCalledWith(
{ jwtFromRequest: expect.any(Function), secretOrKey: 'secret 123' },
expect.any(Function),
);
expect(ExtractJwt.fromAuthHeaderAsBearerToken).toBeCalledTimes(1);
expect(userModel.findOne).toBeCalledWith({ _id: 1 });
expect(mDone).toBeCalledWith(null, false);
});
// you can do the rest parts
});
Unit test results:
PASS stackoverflow/62125872/index.test.ts
62125872
✓ should verify using user model and call done with jwtpayload if user document exists (11ms)
✓ should verify using user model and call done with false if user document doesn't exist (2ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 85 | 83.33 | 60 | 84.21 |
index.ts | 92.86 | 75 | 100 | 92.31 | 24
models.ts | 66.67 | 100 | 33.33 | 66.67 | 6,11
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.716s, estimated 10s
Using supertest to verify full cycle
import request from 'supertest';
import express from 'express';
import jwt from 'jsonwebtoken'
export const createAuthToken = (userId) => {
const body = {
type: EntityType.User,
id: userId,
};
return jwt.sign(body, JWT_PRIVATE_KEY);
};
// this function should configure express app
const appLoader = async app => {
(await import('../app/loaders/express')).expressLoader({ app }); // express bindings and routes
await import('./'); // passport config
}
describe('passport-jwt auth', () => {
const app = express();
const token = createAuthToken('user1')
beforeAll(async () => {
await appLoader({ app });
});
it('should verify auth', async () => {
jest.spyOn(userModel, 'findOne').mockResolvedValueOnce('mocked user document');
await request(app)
.get('/protected-endpoint')
.set('Authorization', `Bearer ${token}`)
.expect(200);
});
it('should verify auth - failure', async () => {
await request(app)
.get('/protected-endpoint')
.set('Authorization', `Bearer wrong-token`)
.expect(401);
});
});

Mocking ApolloClient's client.query method with Jest

Update January 22nd 2020
The solution from #slideshowp2 is correct, but I could not get it to work at all, due to this TypeError:
TypeError: Cannot read property 'query' of undefined
Well it turned out to be my jest configuration that had resetMocks: true set. After I removed it, the test did pass. (I don't know why though)
Original question:
I need to execute a graphql query in a helper function outside of a React component using Apollo Client and after a bit of trial and error I went for this approach which is working as it is supposed to:
setup.ts
export const setupApi = (): ApolloClient<any> => {
setupServiceApi(API_CONFIG)
return createServiceApolloClient({ uri: `${API_HOST}${API_PATH}` })
}
getAssetIdFromService.ts
import { setupApi } from '../api/setup'
const client = setupApi()
export const GET_ASSET_ID = gql`
query getAssetByExternalId($externalId: String!) {
assetId: getAssetId(externalId: $externalId) {
id
}
}
`
export const getAssetIdFromService = async (externalId: string) => {
return await client.query({
query: GET_ASSET_ID,
variables: { externalId },
})
return { data, errors, loading }
}
Now I am trying to write test tests for the getAssetIdFromService function, but I have trouble figuring out how to get the client.query method to work in tests.
I have tried the approach below including many others that did not work.
For this particular setup, jest throws
TypeError: client.query is not a function
import { setupApi } from '../../api/setup'
import { getAssetIdFromService } from '../getAssetIdFromService'
jest.mock('../../api/setup', () => ({
setupApi: () => jest.fn(),
}))
describe('getAssetIdFromService', () => {
it('returns an assetId when passed an externalId and the asset exists in the service', async () => {
const { data, errors, loading } = await getAssetIdFromService('e1')
// Do assertions
})
}
I assume I am missing something in relation to this part:
jest.mock('../../api/setup', () => ({
setupApi: () => jest.fn(),
}))
...but I cannot see it.
You didn't mock correctly. Here is the correct way:
getAssetIdFromService.ts:
import { setupApi } from './setup';
import { gql } from 'apollo-server';
const client = setupApi();
export const GET_ASSET_ID = gql`
query getAssetByExternalId($externalId: String!) {
assetId: getAssetId(externalId: $externalId) {
id
}
}
`;
export const getAssetIdFromService = async (externalId: string) => {
return await client.query({
query: GET_ASSET_ID,
variables: { externalId },
});
};
setup.ts:
export const setupApi = (): any => {};
getAssetIdFromService.test.ts:
import { getAssetIdFromService, GET_ASSET_ID } from './getAssetIdFromService';
import { setupApi } from './setup';
jest.mock('./setup.ts', () => {
const mApolloClient = { query: jest.fn() };
return { setupApi: jest.fn(() => mApolloClient) };
});
describe('59829676', () => {
it('should query and return data', async () => {
const client = setupApi();
const mGraphQLResponse = { data: {}, loading: false, errors: [] };
client.query.mockResolvedValueOnce(mGraphQLResponse);
const { data, loading, errors } = await getAssetIdFromService('e1');
expect(client.query).toBeCalledWith({ query: GET_ASSET_ID, variables: { externalId: 'e1' } });
expect(data).toEqual({});
expect(loading).toBeFalsy();
expect(errors).toEqual([]);
});
});
Unit test results with 100% coverage:
PASS apollo-graphql-tutorial src/stackoverflow/59829676/getAssetIdFromService.test.ts (8.161s)
59829676
✓ should query and return data (7ms)
--------------------------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
--------------------------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
getAssetIdFromService.ts | 100 | 100 | 100 | 100 | |
--------------------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.479s
Source code: https://github.com/mrdulin/apollo-graphql-tutorial/tree/master/src/stackoverflow/59829676
Use blow mock class:
class ApolloClient {
constructor(uri: string, fetch: any, request: any) {}
setupApi() {
return {
query: jest.fn(),
};
}
query() {
return jest.fn();
}
}
module.exports = ApolloClient;
and add below line to jest.cofig.ts
moduleNameMapper: {
'apollo-boost': '<rootDir>/.jest/appolo-client.ts',
},

How can i parse express query param to mongodb regex query?

I try to build a test backend with express.
And got a problem that i cannot seem to overcome.
Trying to give the query object $regex param a value from the req.query.name. But it only returns an empty array. When i console.log(laptopName) it outputs the right value that is being given as a query param.
If i just replace $regex: laptopName with a concrete value $regex: 'vivobook' i do get results.
With $regex: laptopName console.log looks like this { name: { '$regex': '"vivobook"', '$options': 'i' } }
With $regex: 'vivobook' console.log looks like this: { name: { '$regex': 'vivobook', '$options': 'i' } }
app.get("/api/v1/laptops", (req, res) => {
MongoClient.connect(mongo_url, { useNewUrlParser: true }, (err, client) => {
const db = client.db("laptop_backend");
const collection = db.collection("laptops");
let laptopName = req.query.name;
let query = {
name: {
$regex: laptopName,
$options: 'i'
}
};
collection
.find(query)
.toArray()
.then(response => res.status(200).json(response))
.catch(err => console.error(err));
});
});
Try getting laptop name directly from params such as
let { name } = req.query;
let query = {
name: {
$regex: name,
$options: 'i',
}
};
if you are to modify completely i suggest changing code without promise.
app.get("/api/v1/laptops", async (req, res) => {
try {
const client = await MongoClient.connect(mongo_url, { useNewUrlParser: true });
const db = client.db('laptop_backend');
const collection = db.collection('laptops');
const { name } = req.query;
const query = {
name: {
$regex: name,
$options: 'i',
},
};
const result = await collection.find(query);
res.status(200).json({ result });
} catch (e) {
console.log(e);
res.status(400).json({ error: true });
}
});