Skip to content

Instantly share code, notes, and snippets.

@codyfet
Last active September 16, 2018 17:57
Show Gist options
  • Save codyfet/618d4f12c03cd0613225f43fa30b7d7b to your computer and use it in GitHub Desktop.
Save codyfet/618d4f12c03cd0613225f43fa30b7d7b to your computer and use it in GitHub Desktop.
Решение задачи про query и операторы.
const friends = [
{
name: 'Сэм',
age: 29,
gender: 'Мужской',
email: 'luisazamora@example.com',
phone: '+7 (555) 505-3570',
favoriteFruit: 'Мороженое'
},
{
name: 'Эмили',
age: 30,
gender: 'Женский',
email: 'roachpugh@example.com',
phone: '+7 (555) 539-2625',
favoriteFruit: 'Яблоко'
},
{
name: 'Иван',
age: 32,
gender: 'Мужской',
email: 'ivan@example.com',
phone: '+7 (555) 539-2625',
favoriteFruit: 'Груша'
},
{
name: 'Мария',
age: 25,
gender: 'Женский',
email: 'masha@example.com',
phone: '+7 (555) 539-2625',
favoriteFruit: 'Тыква'
},
{
name: 'Сергей',
age: 19,
gender: 'Мужской',
email: 'sg@example.com',
phone: '+7 (555) 539-2625',
favoriteFruit: 'Котлета'
}
];
const index = {
/**
* Выполняет запрос.
*
* @prop {Object[]} collection Исходная коллекция. Во время выполнения не изменяется.
* @prop {Function[]} operators Функции-операторы, выполняемые в запросе.
*/
query: function (collection, ...operators) {
// Если операторов нет, то возвращаем клон исходного массива.
if (operators.length === 0) {
return JSON.parse(JSON.stringify(collection));
}
// Складываем исходную коллекцию в this для доступа из методов (initialCollection).
// Создаём переменную, где будет храниться результат выполнения запроса (resultCollection).
this.initialCollection = collection;
this.resultCollection;
// Последовательно выполняем функции-операторы запроса. Промежуточные результаты складываем в resultCollection.
operators.forEach(
(operator) => this.resultCollection = operator.call()
);
// Распечатываем результат.
console.log('Результат выполнения запроса:');
console.log(this.resultCollection);
},
/**
* Возвращает функцию-оператор select, фильтруюущую объекты по заданным атрибутам.
*
* @param {string[]} attributes Атрибуты записи, которые попадают в выборку.
* @returns {Function} Функция-оператор select.
*/
select: function (...attributes) {
return () => this.filterByAttributes(this.initialCollection, attributes);
},
/**
* Возвращает функцию-оператор filterIn, фильтруюущую объекты исходной коллекции по значениям заданного атрибута.
*
* @param {string} attribute Атрибут, по значениям которого будет происходить фильтрация.
* @param {string[]} values Допустимые значения атрибута.
* @returns {Function} Функция-оператор filterIn.
*/
filterIn: function (attribute, values) {
return () => {
// Фильтруем исходную коллекцию по переданным значениям.
const filtered = this.initialCollection.filter(
(item) => {
return values.indexOf(item[attribute]) !== -1
}
);
// Оставляем только те атрибуты, которые сейчас лежат в результирующей коллекции (после всех селектов, выполненных ранее).
// Атрибуты (ключи) результирующей коллекции берём из первой записи результирующей коллекции.
return this.filterByAttributes(filtered, Object.keys(this.resultCollection[0]));
}
},
/**
* Возвращает функцию-оператор sortBy, сортирующую коллекцию.
* Функция-оператор sortBy возвращает новую результирующую коллекцию.
*
* @param {string} attribute Атрибут, по значениями которого будет происходить фильтрация.
* @param {string[]} values Допустимые значения атрибута.
* @returns {Function} Функция-оператор filterIn.
*/
sortBy: function (attribute, by) {
return () => {
// Функция-компаратор, описывающая алгоритм сортировки.
const compare = function compare(a, b) {
if (a[attribute] < b[attribute])
return by === 'asc' ? -1 : 1;
if (a[attribute] > b[attribute])
return by === 'asc' ? 1 : -1;
return 0;
}
// Сортируем коллекцию согласно функции-компаратору. Исходную коллекцию менять нельзя, поэтому делаем копию.
const sortred = Object.assign([], this.initialCollection).sort(compare);
// Оставляем только те атрибуты, которые сейчас лежат в результирующей коллекции (после всех селектов, выполненных ранее).
// Атрибуты (ключи) результирующей коллекции берём из первой записи результирующей коллекции.
return this.filterByAttributes(sortred, Object.keys(this.resultCollection[0]));
}
},
/**
* Возвращает функцию-оператор format, форматирующую значение заданного атрибута согласно форматирующей функции.
* Функция-оператор format возвращает новую коллекцию, созданную на базе результирующей коллекции, но с отформатированными значениями.
*
* @param {string} attribute Атрибут, значение которого будет форматироваться.
* @param {Function} formatter Функция, форматирующая значение.
* @returns {Function} Функция-оператор format.
*/
format: function (attribute, formatter) {
return () => this.resultCollection.map(
(item) => {
item[attribute] = formatter(item[attribute]);
return item;
}
);
},
/**
* Возвращает функцию-оператор limit, ограничивающую количество записей в результирующей выборке.
* Функция-оператор format оставляет в результирующей коллекции количество записей равное number.
*
* @param {number} number Допустимое количество записей в выборке.
* @returns {Function} Функция-оператор limit.
*/
limit: function (number) {
return () => this.resultCollection.slice(0, number);
},
/**
* Фильтрует записи переданной коллекции. Оставляет толко атрибуты, переданные в attributes.
*
* @param {Object[]} collection Коллекция объектов.
* @returns {Object[]} Отфильтрованная по атрибутам коллекция.
*/
filterByAttributes: function (collection, attributes) {
let mergedAttributes = attributes;
// Нам необходимо объединить все селекты, чтобы в выборку попали атрибуты из разных селектов.
// Для этого мы проверяем есть ли результирующая коллекция и если есть - объединяем attributes с теми атрибутами,
// которые уже есть в результате (т.к. там лежат результаты предыдущих селектов).
// Дубликаты удаляются, т.к. используется Set.
if (this.resultCollection) {
mergedAttributes = [...new Set(
attributes.concat(...Object.keys(this.resultCollection[0]))
)];
}
return collection.map(
(item) => {
const filteredItem = {};
mergedAttributes.forEach(
(attribute) => {
// Если в фильтруемой записи нет переданного атрибута, то игнорируем этот атрибут.
if (item.hasOwnProperty(attribute)) {
filteredItem[attribute] = item[attribute];
}
}
);
return filteredItem;
}
);
}
}
index.query(
friends,
index.select('name', 'email', 'fdfd'),
index.select('name', 'gender'),
index.filterIn('favoriteFruit', ['Яблоко', 'Мороженое']),
index.sortBy('age', 'asc'),
index.format('name', function (value) {
return value[0];
}),
index.limit(4)
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment