При правильной комбинации $ lookup, $ project и $ match вы можете присоединиться к нескольким таблицам по нескольким параметрам. Это связано с тем, что они могут быть связаны несколько раз.
Предположим, что мы хотим сделать следующее ( reference )
SELECT S.* FROM LeftTable S
LEFT JOIN RightTable R ON S.ID =R.ID AND S.MID =R.MID WHERE R.TIM >0 AND
S.MOB IS NOT NULL
Шаг 1: Свяжите все таблицы
, вы можете $ lookup сколько угодно таблиц.
$ lookup - по одному для каждой таблицы в запросе
$ unwind - поскольку данные денормализированы правильно, иначе они завернуты в массивы
Python code ..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "R"}
])
Шаг 2: Определите все условные выражения
$ project: определите здесь все условные операторы и все переменные, которые вы хотите выбрать.
Python Code ..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "R"},
# define conditionals + variables
{"$project": {
"midEq": {"$eq": ["$MID", "$R.MID"]},
"ID": 1, "MOB": 1, "MID": 1
}}
])
Шаг 3: Присоедините все условные обозначения
$ match - присоедините все условия, используя OR или AND и т. д. Их могут быть кратные ,
$ project: undefine all conditionals
Python Code ..
db.LeftTable.aggregate([
# connect all tables
{"$lookup": {
"from": "RightTable",
"localField": "ID",
"foreignField": "ID",
"as": "R"
}},
{"$unwind": "$R"},
# define conditionals + variables
{"$project": {
"midEq": {"$eq": ["$MID", "$R.MID"]},
"ID": 1, "MOB": 1, "MID": 1
}},
# join all conditionals
{"$match": {
"$and": [
{"R.TIM": {"$gt": 0}},
{"MOB": {"$exists": True}},
{"midEq": {"$eq": True}}
]}},
# undefine conditionals
{"$project": {
"midEq": 0
}}
])
Практически любая комбинация таблиц, условных обозначений и объединений может быть выполнена таким образом ,
Я думаю, является ли это TDD или нет, не существенная деталь. Я также немного озадачен вашим подходом.
Решение зависит также от вашей среды тестирования. Самым популярным для React является Jest, поэтому я могу найти решение, которое работает с этим довольно хорошо.
Если бы я был на вашем месте, я бы разделил асинхронную функцию на отдельный файл, что облегчает насмешки.
import axios from 'axios';
const getPosts = async () => axios.get('/api/posts/');
export default getPosts;
Предположим, у вас есть компонент PostList в обычной папке src вместе с файлом index.js .
.
├── src
│ ├── index.js
│ ├── PostList
│ ├── __mocks__
│ ├── GetPosts.js
│ ├── PostList.js
│ ├── PostList.test.js
│ ├── GetPosts.js
Папка __ mocks __ распознается Jest и работает должным образом, при условии соблюдения соглашения об именовании файлов:
Также обратите внимание на использование jest.mock('...')
в тестовом файле.
Исходя из вашего ложного примера, вы можете определить нечто похожее на это в __ mocks __ / GetPosts.js .
const returnedData = [{
id: 1,
title: "Hello",
description: "World"
}];
const getPosts = jest.fn().mockReturnValueOnce(() => returnedData);
export default getPosts;
// PostList.js
...
async componentDidMount() {
const posts = await GetPosts();
this.setState({
posts,
});
}
...
И ваш тестовый файл должен выглядеть примерно так:
import React from 'react';
import { shallow } from 'enzyme';
import PostList from './PostList.js';
jest.mock('./GetPosts.js'); // Here you "tell" to Jest to mock the function.
describe('<PostList />', () => {
let wrapper;
beforeAll(async () => {
wrapper = await shallow(<PostList />);
});
describe('componentDidMount', () => {
it('renders an li tag', () => {
expect(wrapper.find('li')).toHaveLength(1);
});
});
});