-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Дубровин Алексей #16
base: master
Are you sure you want to change the base?
Дубровин Алексей #16
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,15 @@ const Cart = sequelize.import('models/cart'); | |
const User = sequelize.import('models/user'); | ||
|
||
// Ваши relations между моделями :) | ||
Cart.belongsTo(User); | ||
Cart.belongsToMany(Souvenir, { through: 'cart_souvenirs' }); | ||
Review.belongsTo(Souvenir); | ||
Review.belongsTo(User); | ||
User.hasOne(Cart); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Уже есть |
||
User.hasMany(Review); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Также с |
||
Souvenir.hasMany(Review); | ||
Souvenir.belongsTo(Country); | ||
Souvenir.belongsToMany(Tag, { through: 'souvenir_tags' }); | ||
|
||
module.exports.sequelize = sequelize; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель корзины | ||
return sequelize.define('cart', { | ||
id: { | ||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
userId: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true | ||
} | ||
}, { | ||
timestamps: true | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нет необходимости явным образом определять что либо в этой модели. |
||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель страны | ||
return sequelize.define('country', { | ||
id: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Аналогично про |
||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
name: { | ||
type: DataTypes.TEXT, | ||
allowNull: true | ||
} | ||
}, { | ||
timestamps: true | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,35 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель отзыва | ||
return sequelize.define('review', { | ||
id: { | ||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
text: { | ||
type: DataTypes.TEXT, | ||
allowNull: true | ||
}, | ||
rating: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true | ||
}, | ||
isApproved: { | ||
type: DataTypes.BOOLEAN, | ||
allowNull: true, | ||
default: false | ||
}, | ||
souvenirId: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true | ||
}, | ||
userId: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true | ||
} | ||
}, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Аналогично про |
||
timestamps: true | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,48 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель сувенира | ||
return sequelize.define('souvenir', { | ||
id: { | ||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
name: { | ||
type: DataTypes.TEXT, | ||
allowNull: false | ||
}, | ||
image: { | ||
type: DataTypes.TEXT, | ||
allowNull: true | ||
}, | ||
price: { | ||
type: DataTypes.DOUBLE, | ||
allowNull: false | ||
}, | ||
rating: { | ||
type: DataTypes.DOUBLE, | ||
allowNull: true | ||
}, | ||
amount: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true, | ||
default: 0 | ||
}, | ||
isRecent: { | ||
type: DataTypes.BOOLEAN, | ||
allowNull: true | ||
}, | ||
countryId: { | ||
type: DataTypes.INTEGER, | ||
allowNull: true | ||
} | ||
}, { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Всё также, много лишних явных объявлений |
||
timestamps: true, | ||
indexes: [ | ||
{ | ||
fields: ['countryId', 'rating', 'price'] | ||
} | ||
] | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель тэга | ||
return sequelize.define('tag', { | ||
id: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Аналогично |
||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
name: { | ||
type: DataTypes.TEXT, | ||
allowNull: true | ||
} | ||
}, { | ||
timestamps: true | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,18 @@ | ||
'use strict'; | ||
|
||
module.exports = (sequelize, DataTypes) => { | ||
// Ваша модель юзера | ||
return sequelize.define('user', { | ||
id: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Тоже |
||
type: DataTypes.INTEGER, | ||
allowNull: false, | ||
primaryKey: true, | ||
autoIncrement: true | ||
}, | ||
login: { | ||
type: DataTypes.TEXT, | ||
allowNull: true | ||
} | ||
}, { | ||
timestamps: true | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,114 @@ | ||
'use strict'; | ||
const Sequelize = require('sequelize'); | ||
|
||
class Queries { | ||
constructor(models) { | ||
// Что-нибудь инициализируем в конструкторе | ||
constructor({ sequelize, Country, Tag, Review, Souvenir, Cart, User }) { | ||
this.sequelize = sequelize; | ||
this.Country = Country; | ||
this.Tag = Tag; | ||
this.Review = Review; | ||
this.Souvenir = Souvenir; | ||
this.Cart = Cart; | ||
this.User = User; | ||
} | ||
|
||
// Далее идут методы, которые вам необходимо реализовать: | ||
|
||
getAllSouvenirs() { | ||
// Данный метод должен возвращать все сувениры. | ||
return this.Souvenir.findAll(); | ||
} | ||
|
||
getCheapSouvenirs(price) { | ||
// Данный метод должен возвращать все сувениры, цена которых меньше или равна price. | ||
return this.Souvenir.findAll({ | ||
where: { | ||
price: { [Sequelize.Op.lte]: price } | ||
} | ||
}); | ||
} | ||
|
||
getTopRatingSouvenirs(n) { | ||
// Данный метод должен возвращать топ n сувениров с самым большим рейтингом. | ||
return this.Souvenir.findAll({ | ||
order: [ | ||
['rating', 'DESC'] | ||
], | ||
limit: n | ||
}); | ||
} | ||
|
||
getSouvenirsByTag(tag) { | ||
// Данный метод должен возвращать все сувениры, в тегах которых есть tag. | ||
// Кроме того, в ответе должны быть только поля id, name, image, price и rating. | ||
return this.Souvenir.findAll({ | ||
attributes: ['id', 'name', 'image', 'price', 'rating'], | ||
include: { | ||
model: this.Tag, | ||
where: { name: tag }, | ||
attributes: [] | ||
} | ||
}); | ||
} | ||
|
||
getSouvenirsCount({ country, rating, price }) { | ||
// Данный метод должен возвращать количество сувениров, | ||
// из страны country, с рейтингом больше или равной rating, | ||
// и ценой меньше или равной price. | ||
|
||
// Важно, чтобы метод работал очень быстро, | ||
// поэтому учтите это при определении моделей (!). | ||
return this.Souvenir.count({ | ||
where: { | ||
rating: { | ||
[Sequelize.Op.gte]: rating | ||
}, | ||
price: { | ||
[Sequelize.Op.lte]: price | ||
} | ||
}, | ||
include: { | ||
model: this.Country, | ||
where: { name: country } | ||
} | ||
}); | ||
} | ||
|
||
searchSouvenirs(substring) { | ||
// Данный метод должен возвращать все сувениры, в название которых входит | ||
// подстрока substring. Поиск должен быть регистронезависимым. | ||
return this.Souvenir.findAll({ | ||
where: { | ||
name: { [Sequelize.Op.contains]: substring } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
}); | ||
} | ||
|
||
getDisscusedSouvenirs(n) { | ||
// Данный метод должен возвращать все сувениры, имеющих >= n отзывов. | ||
// Кроме того, в ответе должны быть только поля id, name, image, price и rating. | ||
return this.Review.findAll({ | ||
attributes: ['souvenir.id'], | ||
group: ['souvenir.id'], | ||
include: { | ||
model: this.Souvenir, | ||
attributes: ['name', 'image', 'price', 'rating'] | ||
}, | ||
having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col('souvenir.id')), '>=', n) | ||
}).then(s => s.map(x => x.souvenir)); | ||
} | ||
|
||
deleteOutOfStockSouvenirs() { | ||
// Данный метод должен удалять все сувениры, которых нет в наличии | ||
// (то есть amount = 0). | ||
|
||
// Метод должен возвращать количество удаленных сувениров в случае успешного удаления. | ||
return this.Souvenir.destroy({ where: { amount: 0 } }); | ||
} | ||
|
||
addReview(souvenirId, { login, text, rating }) { | ||
// Данный метод должен добавлять отзыв к сувениру souvenirId | ||
// содержит login, text, rating - из аргументов. | ||
// Обратите внимание, что при добавлении отзыва рейтинг сувенира должен быть пересчитан, | ||
// и всё это должно происходить за одну транзакцию (!). | ||
async addReview(souvenirId, { login, text, rating }) { | ||
const user = await this.User.findOne({ where: { login } }); | ||
await this.Review.create({ text, rating, souvenirId, userId: user.id }); | ||
|
||
const souvenir = await this.Souvenir.findOne({ where: { souvenirId } }); | ||
const ratings = await this.Review.findAll({ where: { souvenirId } }).then(r => r.rating); | ||
souvenir.rating = ratings.reduce((a, b) => a + b, 0) / ratings.length; | ||
|
||
await souvenir.save(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Оберни в транзакцию |
||
|
||
getCartSum(login) { | ||
// Данный метод должен считать общую стоимость корзины пользователя login | ||
// У пользователя может быть только одна корзина, поэтому это тоже можно отразить | ||
// в модели. | ||
return this.Cart.sum('souvenirs.price', { | ||
group: 'carts.id', | ||
include: [ | ||
{ | ||
model: this.User, | ||
where: { login } | ||
}, | ||
{ model: this.Souvenir } | ||
] | ||
}); | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Souvenir.hasMany(Review)
достаточно