docs: def query(self,
                zipcode=None,
                prefix=None,
                pattern=None,
                city=None,
                state=None,
                lat=None,
                lng=None,
                radius=None,
  
                population_lower=None,
                population_upper=None,
                population_density_lower=None,
                population_density_upper=None,
  
                land_area_in_sqmi_lower=None,
                land_area_in_sqmi_upper=None,
                water_area_in_sqmi_lower=None,
                water_area_in_sqmi_upper=None,
  
                housing_units_lower=None,
                housing_units_upper=None,
                occupied_housing_units_lower=None,
                occupied_housing_units_upper=None,
  
                median_home_value_lower=None,
                median_home_value_upper=None,
                median_household_income_lower=None,
                median_household_income_upper=None,
  
                zipcode_type=ZipcodeType.Standard,
                sort_by=SimpleZipcode.zipcode.name,
                ascending=True,
                returns=DEFAULT_LIMIT):
          """
          Query zipcode the simple way.
  
          :param zipcode: int or str, find the exactly matched zipcode. Will be
              automatically zero padding to 5 digits
          :param prefix: str, zipcode prefix.
          :param pattern: str, zipcode wildcard.
          :param city: str, city name.
          :param state: str, state name, two letter abbr or state full name.
          :param lat: latitude.
          :param lng: longitude.
          :param radius: number, only returns zipcodes within a specific circle.
          :param population_lower:
          :param population_upper:
          :param population_density_lower:
          :param population_density_upper:
          :param land_area_in_sqmi_lower:
          :param land_area_in_sqmi_upper:
          :param water_area_in_sqmi_lower:
          :param water_area_in_sqmi_upper:
          :param housing_units_lower:
          :param housing_units_upper:
          :param occupied_housing_units_lower:
          :param occupied_housing_units_upper:
          :param median_home_value_lower:
          :param median_home_value_upper:
          :param median_household_income_lower:
          :param median_household_income_upper:
          :param zipcode_type: str or :class`~uszipcode.model.ZipcodeType` attribute.
              if None, allows to return any type of zipcode.
              if specified, only return specified zipcode type.
          :param sort_by: str or :class:`~uszipcode.model.Zipcode` attribute,
              specified which field is used for sorting.
          :param ascending: bool, True means ascending, False means descending.
          :param returns: int or None, limit the number of result to returns.
  
          :return: list of :class:`~uszipcode.model.SimpleZipcode` or
              :class:`~uszipcode.model.Zipcode`.
          """
          filters = list()
  
          # by coordinates
          _n_radius_param_not_null = sum([
              isinstance(lat, (integer_types, float)),
              isinstance(lng, (integer_types, float)),
              isinstance(radius, (integer_types, float)),
          ])
          if _n_radius_param_not_null == 3:
              flag_radius_query = True
              if radius <= 0:  # pragma: no cover
                  raise ValueError("`radius` parameters can't less than 0!")
              elif radius <= 50:  # pragma: no cover
                  radius_coef = 1.05
              elif radius <= 100:  # pragma: no cover
                  radius_coef = 1.10
              elif radius <= 250:  # pragma: no cover
                  radius_coef = 1.25
              elif radius <= 500:  # pragma: no cover
                  radius_coef = 1.5
              else:  # pragma: no cover
                  radius_coef = 2.0
  
              if radius >= 250:  # pragma: no cover
                  msg = ("\nwarning! search within radius >= 250 miles "
                         "may greatly slow down the query!")
                  sys.stdout.write(msg)
  
              # define lat lng boundary
              dist_btwn_lat_deg = 69.172
              dist_btwn_lon_deg = math.cos(lat) * 69.172
              lat_degr_rad = abs(radius * radius_coef / dist_btwn_lat_deg)
              lon_degr_rad = abs(radius * radius_coef / dist_btwn_lon_deg)
  
              lat_lower = lat - lat_degr_rad
              lat_upper = lat + lat_degr_rad
              lng_lower = lng - lon_degr_rad
              lng_upper = lng + lon_degr_rad
  
              filters.append(self.zip_klass.lat >= lat_lower)
              filters.append(self.zip_klass.lat <= lat_upper)
              filters.append(self.zip_klass.lng >= lng_lower)
              filters.append(self.zip_klass.lng <= lng_upper)
          elif _n_radius_param_not_null == 0:
              flag_radius_query = False
          else:
              msg = "You can either specify all of `lat`, `lng`, `radius` or none of them"
              raise ValueError(msg)
  
          # by city or state
          if (state is not None) and (city is not None):
              try:
                  state = self.find_state(state, best_match=True)[0]
                  city = self.find_city(city, state, best_match=True)[0]
                  filters.append(self.zip_klass.state == state)
                  filters.append(self.zip_klass.major_city == city)
              except ValueError:  # pragma: no cover
                  return []
          elif (state is not None):
              try:
                  state = self.find_state(state, best_match=True)[0]
                  filters.append(self.zip_klass.state == state)
              except ValueError:  # pragma: no cover
                  return []
          elif (city is not None):
              try:
                  city = self.find_city(city, None, best_match=True)[0]
                  filters.append(self.zip_klass.major_city == city)
              except ValueError:  # pragma: no cover
                  return []
          else:
              pass
  
          # by common filter
          if sum([zipcode is None, prefix is None, pattern is None]) <= 1:
              msg = "You can only specify one of the `zipcode`, `prefix` and `pattern`!"
              raise ValueError(msg)
  
          if zipcode_type is not None:
              filters.append(self.zip_klass.zipcode_type == zipcode_type)
  
          if zipcode is not None:
              filters.append(self.zip_klass.zipcode == str(zipcode))
          if prefix is not None:
              filters.append(self.zip_klass.zipcode.startswith(str(prefix)))
          if pattern is not None:
              filters.append(self.zip_klass.zipcode.like(
                  "%%%s%%" % str(pattern)))
  
          if population_lower is not None:
              filters.append(self.zip_klass.population >= population_lower)
          if population_upper is not None:
              filters.append(self.zip_klass.population <= population_upper)
  
          if population_density_lower is not None:
              filters.append(self.zip_klass.population_density >=
                             population_density_lower)
          if population_density_upper is not None:
              filters.append(self.zip_klass.population_density <=
                             population_density_upper)
  
          if land_area_in_sqmi_lower is not None:
              filters.append(self.zip_klass.land_area_in_sqmi >=
                             land_area_in_sqmi_lower)
          if land_area_in_sqmi_upper is not None:
              filters.append(self.zip_klass.land_area_in_sqmi <=
                             land_area_in_sqmi_upper)
  
          if water_area_in_sqmi_lower is not None:
              filters.append(self.zip_klass.water_area_in_sqmi >=
                             water_area_in_sqmi_lower)
          if water_area_in_sqmi_upper is not None:
              filters.append(self.zip_klass.water_area_in_sqmi <=
                             water_area_in_sqmi_upper)
  
          if housing_units_lower is not None:
              filters.append(self.zip_klass.housing_units >= housing_units_lower)
          if housing_units_upper is not None:
              filters.append(self.zip_klass.housing_units <= housing_units_upper)
  
          if occupied_housing_units_lower is not None:
              filters.append(self.zip_klass.occupied_housing_units >=
                             occupied_housing_units_lower)
          if occupied_housing_units_upper is not None:
              filters.append(self.zip_klass.occupied_housing_units <=
                             occupied_housing_units_upper)
  
          if median_home_value_lower is not None:
              filters.append(self.zip_klass.median_home_value >=
                             median_home_value_lower)
          if median_home_value_upper is not None:
              filters.append(self.zip_klass.median_home_value <=
                             median_home_value_upper)
  
          if median_household_income_lower is not None:
              filters.append(self.zip_klass.median_household_income >=
                             median_household_income_lower)
          if median_household_income_upper is not None:
              filters.append(self.zip_klass.median_household_income <=
                             median_household_income_upper)
  
          # --- solve coordinates and other search sort_by conflict ---
          sort_by = self._resolve_sort_by(sort_by, flag_radius_query)
  
          q = self.ses.query(self.zip_klass).filter(*filters)
  
          if sort_by is None:
              pass
          elif sort_by == SORT_BY_DIST:
              pass
          else:
              field = getattr(self.zip_klass, sort_by)
              if ascending:
                  by = field.asc()
              else:
                  by = field.desc()
              q = q.order_by(by)
  
          if flag_radius_query:
              # if we query by radius, then ignore returns limit before the
              # distance calculation, and then manually limit the returns
              pairs = list()
              for z in q:
                  dist = z.dist_from(lat, lng)
                  if dist <= radius:
                      pairs.append((dist, z))
  
              if sort_by == SORT_BY_DIST:
                  if ascending:
                      if returns:
                          pairs_new = heapq.nsmallest(
                              returns, pairs, key=lambda x: x[0])
                      else:
                          pairs_new = list(sorted(pairs, key=lambda x: x[0]))
                  else:
                      if returns:
                          pairs_new = heapq.nlargest(
                              returns, pairs, key=lambda x: x[0])
                      else:
                          pairs_new = list(
                              sorted(pairs, key=lambda x: x[0], reverse=True))
                  return [z for _, z in pairs_new]
              else:
                  return [z for _, z in pairs[:returns]]
          else:
              if returns:
                  return q.limit(returns).all()
              else:
                  return q.all()