@Override
	public List<City> load(int first, int pageSize, String sortField,
			SortOrder order, Map<String, String> filters) {
		// cache parameters

		this.first = first;
		this.sortField = sortField;
		this.sortOrder = (order == SortOrder.ASCENDING) ? "ascending" :
			"descending";
		this.filters = filters;

		// builder for SELECT query
		StringBuilder selectQuery = new StringBuilder();
		selectQuery.append("SELECT * FROM cities ");

		// builder for COUNT(*) query
		StringBuilder countQuery = new StringBuilder();
		countQuery.append("SELECT COUNT(*) FROM cities ");

		// WHERE clause
		List<Object> args = new ArrayList<Object>();
		Set<Entry<String, String>> entries = filters.entrySet();
		List<String> whereQueries = new ArrayList<String>();
		for (Entry<String, String> entry : entries) {
			String field = getDbFieldName(entry.getKey());
			String operator = "LIKE";
			String rawValue = entry.getValue();
			Object value = rawValue + "%";

			whereQueries.add("LOWER(" + field + ") " + operator + " LOWER(?) ");
			args.add(value);
		}
		if (whereQueries.size() > 0) {
			String where = StringUtils.join(whereQueries, " AND ");
			selectQuery.append("WHERE " + where);
			countQuery.append("WHERE " + where);
		}

		// ORDER BY clause
		if (sortField != null) {
			String field = getDbFieldName(sortField);
			selectQuery.append("ORDER BY " + field + " ");
			if (order == SortOrder.DESCENDING) {
				selectQuery.append("DESC ");
			}
		}

		// LIMIT clause
		selectQuery.append("LIMIT " + first + ", " + pageSize);

		// query for data
		String sql = selectQuery.toString();
		List<Map<String, Object>> rows = getRows(sql, args);
		cities = new ArrayList<City>(pageSize);
		for (Map<String, Object> row : rows) {
			City city = new City();
			city.setId((Integer)row.get("id"));
			city.setName((String)row.get("name"));
			city.setAsciiName((String)row.get("ascii_name"));
			city.setLatitude((Integer)row.get("latitude"));
			city.setLongitude((Integer)row.get("longitude"));
			city.setTimeZone((String)row.get("time_zone"));
			city.setPopulation((Integer)row.get("population"));
			city.setProvince((String)row.get("province"));
			cities.add(city);
		}

		// query for data set size
		sql = countQuery.toString();
		setRowCount(getIntResult(sql, args));
		return cities;
	}