Change offset of list notification to integer instead of id

And add sortBy function to list notification of Hibernate ORM.

Change-Id: I112725c0e2ef6ceceb2d7be31ed36defa9d77d50
This commit is contained in:
Shinya Kawabata 2016-06-15 16:28:05 +09:00
parent c1ab9792f6
commit 4119917bb4
11 changed files with 87 additions and 49 deletions

View File

@ -13,10 +13,6 @@
*/
package monasca.api.domain.model.notificationmethod;
import java.util.List;
import monasca.api.domain.model.common.Link;
import monasca.api.domain.model.common.Linked;
import monasca.common.model.domain.common.AbstractEntity;
public class NotificationMethodType extends AbstractEntity{

View File

@ -20,6 +20,7 @@ import java.util.UUID;
import javax.inject.Inject;
import javax.inject.Named;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.hibernate.Query;
@ -34,7 +35,6 @@ import monasca.api.domain.exception.EntityExistsException;
import monasca.api.domain.exception.EntityNotFoundException;
import monasca.api.domain.model.notificationmethod.NotificationMethod;
import monasca.api.domain.model.notificationmethod.NotificationMethodRepo;
import monasca.api.resource.exception.Exceptions;
import monasca.common.hibernate.db.NotificationMethodDb;
import monasca.common.model.alarm.AlarmNotificationMethodType;
@ -44,6 +44,7 @@ import monasca.common.model.alarm.AlarmNotificationMethodType;
public class NotificationMethodSqlRepoImpl
extends BaseSqlRepo
implements NotificationMethodRepo {
private static final Joiner COMMA_JOINER = Joiner.on(',');
private static final Logger LOG = LoggerFactory.getLogger(NotificationMethodSqlRepoImpl.class);
@Inject
@ -204,27 +205,35 @@ public class NotificationMethodSqlRepoImpl
@SuppressWarnings("unchecked")
public List<NotificationMethod> find(String tenantId, List<String> sortBy, String offset,
int limit) {
if (sortBy != null && !sortBy.isEmpty()) {
throw Exceptions.unprocessableEntity(
"Sort_by is not implemented for the hibernate database type");
}
Session session = null;
List<NotificationMethodDb> resultList;
List<NotificationMethod> notificationList = Lists.newArrayList();
final String rawQuery = "from NotificationMethodDb where tenant_id = :tenantId %1$s order by id";
final String rawQuery = "from NotificationMethodDb where tenant_id = :tenantId %1$s";
try {
session = sessionFactory.openSession();
final String offsetPart = offset != null ? String.format("and id > '%s'", offset) : "";
final String queryHql = String.format(rawQuery, offsetPart);
final StringBuilder orderByPart = new StringBuilder();
if (sortBy != null && !sortBy.isEmpty()) {
orderByPart.append(" order by ").append(COMMA_JOINER.join(sortBy));
if (!sortBy.contains("id")) {
orderByPart.append(",id");
}
} else {
orderByPart.append(" order by id ");
}
final String queryHql = String.format(rawQuery, orderByPart);
final Query query = session.createQuery(queryHql).setString("tenantId", tenantId);
if (limit > 0) {
query.setMaxResults(limit + 1);
}
if (offset != null && !offset.isEmpty()) {
query.setFirstResult(Integer.parseInt(offset));
}
resultList = query.list();
if (CollectionUtils.isEmpty(resultList)) {

View File

@ -142,11 +142,6 @@ public class NotificationMethodMySqlRepoImpl implements NotificationMethodRepo {
+ "FROM notification_method as nm "
+ "WHERE tenant_id = :tenantId %1$s %2$s %3$s";
String offsetPart = "";
if (offset != null) {
offsetPart = "and nm.id > :offset";
}
String orderByPart = "";
if (sortBy != null && !sortBy.isEmpty()) {
orderByPart = " order by " + COMMA_JOINER.join(sortBy);
@ -162,20 +157,25 @@ public class NotificationMethodMySqlRepoImpl implements NotificationMethodRepo {
limitPart = " limit :limit";
}
String query = String.format(rawQuery, offsetPart, orderByPart, limitPart);
String offsetPart = "";
if (offset != null && !offset.isEmpty()) {
offsetPart = " offset :offset ";
}
String query = String.format(rawQuery, orderByPart, limitPart, offsetPart);
Query<?> q = h.createQuery(query);
q.bind("tenantId", tenantId);
if (offset != null) {
q.bind("offset", offset);
}
if (limit > 0) {
q.bind("limit", limit + 1);
}
if (offset != null && !offset.isEmpty()) {
q.bind("offset", Integer.parseInt(offset));
}
return q.map(new BeanMapper<>(NotificationMethod.class)).list();
}

View File

@ -14,6 +14,7 @@
package monasca.api.resource;
import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Strings;
import java.io.UnsupportedEncodingException;
import java.net.URI;
@ -97,6 +98,9 @@ public class NotificationMethodResource {
@QueryParam("limit") String limit) throws UnsupportedEncodingException {
List<String> sortByList = Validation.parseAndValidateSortBy(sortByStr, ALLOWED_SORT_BY);
if (!Strings.isNullOrEmpty(offset)) {
Validation.parseAndValidateNumber(offset, "offset");
}
final int paging_limit = this.persistUtils.getLimit(limit);
final List<NotificationMethod> resources = repo.find(tenantId, sortByList, offset,

View File

@ -24,8 +24,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
@ -126,11 +124,23 @@ public class NotificationMethodSqlRepositoryImplTest {
assertEquals(nms1, Arrays.asList(new NotificationMethod("123", "MyEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0), new NotificationMethod("124",
"OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
List<NotificationMethod> nms2 = repo.find("444", null, "123", 1);
List<NotificationMethod> nms2 = repo.find("444", null, "1", 1);
assertEquals(nms2, Collections.singletonList(new NotificationMethod("124", "OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
}
@Test(groups = "orm")
public void shouldSortBy() {
// null sorts by will sort by ID
List<NotificationMethod> nms1 = repo.find("444", null, null, 1);
assertEquals(nms1, Arrays.asList(new NotificationMethod("123", "MyEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0),
new NotificationMethod("124", "OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
List<NotificationMethod> nms2 = repo.find("444", Arrays.asList("name desc", "address"), null, 1);
assertEquals(nms2, Arrays.asList(new NotificationMethod("124", "OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0),
new NotificationMethod("123", "MyEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
}
@Test(groups = "orm")
public void shouldUpdate() {
repo.update("444", "123", "Foo", NOTIFICATION_METHOD_EMAIL, "abc", 0);
@ -171,9 +181,4 @@ public class NotificationMethodSqlRepositoryImplTest {
repo.update("444", "124", "MyEmail", NOTIFICATION_METHOD_EMAIL, "abc", 0);
}
@Test(groups = "orm", expectedExceptions = WebApplicationException.class)
public void shouldFindThrowException() {
repo.find("444", Arrays.asList("name", "address"), null, 1);
}
}

View File

@ -153,11 +153,27 @@ public class NotificationMethodMySqlRepositoryImplTest {
}
public void shouldFind() {
List<NotificationMethod> nms = repo.find("444", null, null, 1);
List<NotificationMethod> nms1 = repo.find("444", null, null, 1);
assertEquals(nms, Arrays.asList(new NotificationMethod("123", "MyEmail",
NOTIFICATION_METHOD_EMAIL, "a@b", 0),new NotificationMethod("124", "OtherEmail",
NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
assertEquals(nms1, Arrays.asList(new NotificationMethod("123", "MyEmail",
NOTIFICATION_METHOD_EMAIL, "a@b", 0),new NotificationMethod("124", "OtherEmail",
NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
List<NotificationMethod> nms2 = repo.find("444", null, "1", 1);
assertEquals(nms2, Arrays.asList(new NotificationMethod("124", "OtherEmail",
NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
}
public void shouldSortBy() {
// null sorts by will sort by ID
List<NotificationMethod> nms1 = repo.find("444", null, null, 1);
assertEquals(nms1, Arrays.asList(new NotificationMethod("123", "MyEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0),
new NotificationMethod("124", "OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
List<NotificationMethod> nms2 = repo.find("444", Arrays.asList("name desc", "address"), null, 1);
assertEquals(nms2, Arrays.asList(new NotificationMethod("124", "OtherEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0),
new NotificationMethod("123", "MyEmail", NOTIFICATION_METHOD_EMAIL, "a@b", 0)));
}
public void shouldUpdate() {

View File

@ -83,10 +83,6 @@ class NotificationsRepository(mysql_repository.MySQLRepository,
parms = [tenant_id]
if offset:
query += " and id > %s "
parms.append(offset.encode('utf8'))
if sort_by:
query += " order by " + ','.join(sort_by)
if 'id' not in sort_by:
@ -99,6 +95,9 @@ class NotificationsRepository(mysql_repository.MySQLRepository,
query += " limit %s "
parms.append(limit + 1)
if offset:
query += ' offset {}'.format(offset)
rows = self._execute_query(query, parms)
return rows

View File

@ -130,12 +130,6 @@ class NotificationsRepository(sql_repository.SQLRepository,
else:
order_columns = [nm.c.id]
if offset:
select_nm_query = (select_nm_query
.where(nm.c.id > bindparam('b_offset')))
parms['b_offset'] = offset.encode('utf8')
select_nm_query = select_nm_query.order_by(*order_columns)
select_nm_query = (select_nm_query
@ -144,6 +138,10 @@ class NotificationsRepository(sql_repository.SQLRepository,
parms['b_limit'] = limit + 1
if offset:
select_nm_query = select_nm_query.offset(bindparam('b_offset'))
parms['b_offset'] = offset
rows = conn.execute(select_nm_query, parms).fetchall()
return [dict(row) for row in rows]

View File

@ -159,7 +159,7 @@ class TestNotificationMethodRepoDB(testtools.TestCase, fixtures.TestWithFixtures
def test_should_find(self):
nms = self.repo.list_notifications('444', None, None, 1)
self.assertEqual(nms, self.default_nms)
nms = self.repo.list_notifications('444', None, 'z', 1)
nms = self.repo.list_notifications('444', None, 2, 1)
self.assertEqual(nms, [])
def test_update(self):

View File

@ -19,6 +19,7 @@ from oslo_log import log
from monasca_api.api import notifications_api_v2
from monasca_api.common.repositories import exceptions
from monasca_api.v2.common.exceptions import HTTPUnprocessableEntityError
from monasca_api.v2.common.schemas import (
notifications_request_body_schema as schemas_notifications)
from monasca_api.v2.common.schemas import exceptions as schemas_exceptions
@ -221,6 +222,14 @@ class Notifications(notifications_api_v2.NotificationsV2API):
validation.validate_sort_by(sort_by, allowed_sort_by)
offset = helpers.get_query_param(req, 'offset')
if offset is not None and not isinstance(offset, int):
try:
offset = int(offset)
except Exception:
raise HTTPUnprocessableEntityError('Unprocessable Entity',
'Offset value {} must be an integer'
.format(offset))
result = self._list_notifications(req.project_id, req.uri, sort_by,
offset, req.limit)
res.body = helpers.dumpit_utf8(result)

View File

@ -494,15 +494,16 @@ class TestNotificationMethods(base.BaseMonascaTest):
resp, response_body = self.monasca_client.\
list_notification_methods(query_parms)
self.assertEqual(200, resp.status)
self.assertEqual(4, len(elements))
self.assertEqual(first_element, elements[0])
self.assertEqual(4, len(response_body['elements']))
self.assertEqual(first_element, response_body['elements'][0])
timeout = time.time() + 60 * 1 # 1 minute timeout
for limit in xrange(1, 5):
next_element = elements[limit - 1]
offset = limit
while True:
if time.time() < timeout:
query_parms = '?offset=' + str(next_element['id']) + \
query_parms = '?offset=' + str(offset) + \
'&limit=' + str(limit)
resp, response_body = self.monasca_client.\
list_notification_methods(query_parms)
@ -511,6 +512,7 @@ class TestNotificationMethods(base.BaseMonascaTest):
if len(new_elements) > limit - 1:
self.assertEqual(limit, len(new_elements))
next_element = new_elements[limit - 1]
offset += 1
elif 0 < len(new_elements) <= limit - 1:
self.assertEqual(last_element, new_elements[0])
break