Repository: ofek/pypinfo

Issue:
--where ignores project
These match because `--where 'file.project = "project"'` gets silently overridden:
```console
$ pypinfo --days 1095 --limit 36 --order download_month --where 'details.python = "1.17"' '' month
Served from cache: False
Data processed: 186.48 GiB
Data billed: 186.48 GiB
Estimated cost: $0.92

| download_month | download_count |
| -------------- | -------------- |
| 2018-03        |         18,667 |
| 2018-02        |         67,154 |
| 2018-01        |      1,898,377 |
| 2017-12        |         70,865 |
| 2017-11        |         64,577 |
| 2017-10        |         66,968 |
| 2017-09        |         63,809 |
| 2017-08        |         93,022 |
| 2017-07        |        628,639 |
| 2017-06        |        200,335 |
| 2017-05        |        148,618 |
| 2017-04        |         50,842 |
| 2017-03        |         53,755 |
| 2017-02        |         47,414 |
| 2017-01        |         50,651 |
| 2016-12        |         53,138 |
| 2016-11        |        129,537 |
| 2016-10        |        477,819 |
| 2016-09        |      1,013,797 |
| 2016-08        |        116,291 |
| 2016-07        |         81,521 |
| 2016-06        |         59,695 |
| 2016-05        |        151,872 |
| 2016-03        |          4,618 |
| 2016-02        |        226,267 |
| 2016-01        |        184,133 |
```
```console
$ pypinfo --days 1095 --limit 36 --order download_month --where 'details.python = "1.17"' certifi month
Served from cache: True
Data processed: 0.00 B
Data billed: 0.00 B
Estimated cost: $0.00

| download_month | download_count |
| -------------- | -------------- |
| 2018-03        |         18,667 |
| 2018-02        |         67,154 |
| 2018-01        |      1,898,377 |
| 2017-12        |         70,865 |
| 2017-11        |         64,577 |
| 2017-10        |         66,968 |
| 2017-09        |         63,809 |
| 2017-08        |         93,022 |
| 2017-07        |        628,639 |
| 2017-06        |        200,335 |
| 2017-05        |        148,618 |
| 2017-04        |         50,842 |
| 2017-03        |         53,755 |
| 2017-02        |         47,414 |
| 2017-01        |         50,651 |
| 2016-12        |         53,138 |
| 2016-11        |        129,537 |
| 2016-10        |        477,819 |
| 2016-09        |      1,013,797 |
| 2016-08        |        116,291 |
| 2016-07        |         81,521 |
| 2016-06        |         59,695 |
| 2016-05        |        151,872 |
| 2016-03        |          4,618 |
| 2016-02        |        226,267 |
| 2016-01        |        184,133 |
```
This isn't a huge deal other than there isn't really a reason to even accept `project` in these cases.

Maybe it'd be better to tell people to run `--where 'file.project = "project"'` themselves or to work in an `AND` on custom `--where`s:
```console
$ pypinfo --days 1095 --limit 36 --order download_month --where 'details.python = "1.17" AND file.project = "certifi"' '' month
Served from cache: False
Data processed: 331.50 GiB
Data billed: 331.50 GiB
Estimated cost: $1.62

| download_month | download_count |
| -------------- | -------------- |
| 2018-03        |             70 |
| 2018-02        |             68 |
| 2018-01        |            155 |
| 2017-12        |             93 |
| 2017-11        |            116 |
| 2017-10        |             90 |
| 2017-09        |             95 |
| 2017-08        |             86 |
| 2017-07        |            112 |
| 2017-06        |             83 |
| 2017-05        |             69 |
| 2017-04        |             29 |
| 2017-03        |             12 |
| 2017-02        |             10 |
| 2017-01        |             13 |
| 2016-12        |              8 |
| 2016-11        |              8 |
| 2016-10        |             15 |
| 2016-09        |             55 |
| 2016-08        |             19 |
| 2016-07        |              3 |
| 2016-06        |             14 |
| 2016-05        |              3 |
| 2016-03        |              4 |
| 2016-02        |             13 |
| 2016-01        |              7 |
```

`--order` is affected by the same issue.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev) Report
> Merging [#137](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev) (a30a824) into [master](https://codecov.io/gh/ofek/pypinfo/commit/51c05f209d76d7558b702403f8713cf738a0fe92?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev) (51c05f2) will **increase** coverage by `0.82%`.
> The diff coverage is `90.47%`.

```diff
@@            Coverage Diff             @@
##           master     #137      +/-   ##
==========================================
+ Coverage   96.92%   97.75%   +0.82%     
==========================================
  Files           6        6              
  Lines         390      400      +10     
  Branches       48       35      -13     
==========================================
+ Hits          378      391      +13     
+ Misses          4        3       -1     
+ Partials        8        6       -2     
```


| [Impacted Files](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev) | Coverage Δ | |
|---|---|---|
| [pypinfo/core.py](https://codecov.io/gh/ofek/pypinfo/pull/137/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev#diff-cHlwaW5mby9jb3JlLnB5) | `95.38% <71.42%> (+1.44%)` | :arrow_up: |
| [tests/test\_core.py](https://codecov.io/gh/ofek/pypinfo/pull/137/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev#diff-dGVzdHMvdGVzdF9jb3JlLnB5) | `100.00% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev). Last update [51c05f2...a30a824](https://codecov.io/gh/ofek/pypinfo/pull/137?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Ofek+Lev).


Patch:
diff --git a/pypinfo/core.py b/pypinfo/core.py
index fe4de37..39fb272 100644
--- a/pypinfo/core.py
+++ b/pypinfo/core.py
@@ -138,20 +138,16 @@ def build_query(
     for field in fields:
         query += f'  {field.data} as {field.name},\n'
 
-    query += FROM
-
-    query += f'\nWHERE timestamp BETWEEN {start_date} AND {end_date}\n'
+    query += f'{FROM}\n'
+
+    conditions = [f'WHERE timestamp BETWEEN {start_date} AND {end_date}\n']
+    if project:
+        conditions.append(f'file.project = "{project}"\n')
+    if pip:
+        conditions.append('details.installer.name = "pip"\n')
+    query += '  AND '.join(conditions)
     if where:
         query += f'  AND {where}\n'
-    else:
-        conditions = []
-        if project:
-            conditions.append(f'file.project = "{project}"\n')
-        if pip:
-            conditions.append('details.installer.name = "pip"\n')
-        if conditions:
-            query += '  AND '
-            query += '  AND '.join(conditions)
 
     if len(fields) > 1:
         gb = 'GROUP BY\n'


Test patch:
diff --git a/tests/test_core.py b/tests/test_core.py
index 3178977..1b031f4 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -3,7 +3,7 @@ import copy
 import pytest
 
 from pypinfo import core
-from pypinfo.fields import PythonVersion
+from pypinfo.fields import File, PythonVersion
 
 ROWS = [
     ['python_version', 'percent', 'download_count'],
@@ -196,6 +196,69 @@ LIMIT 100
     assert output == expected
 
 
+def test_build_query_where():
+    # Arrange
+    # pypinfo -sd -2 -ed -1 --test --where 'file.filename LIKE "%manylinux%"' numpy file
+    project = "numpy"
+    all_fields = [File]
+    start_date = "-2"
+    end_date = "-1"
+    days = None
+    limit = 10
+    where = 'file.filename LIKE "%manylinux%"'
+    order = None
+    pip = True
+    expected = r"""
+SELECT
+  file.filename as file,
+  COUNT(*) as download_count,
+FROM `bigquery-public-data.pypi.file_downloads`
+WHERE timestamp BETWEEN TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -2 DAY) AND TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -1 DAY)
+  AND file.project = "numpy"
+  AND details.installer.name = "pip"
+  AND file.filename LIKE "%manylinux%"
+GROUP BY
+  file
+ORDER BY
+  download_count DESC
+LIMIT 10
+    """.strip()  # noqa: E501
+
+    # Act
+    output = core.build_query(project, all_fields, start_date, end_date, days, limit, where, order, pip)
+
+    # Assert
+    assert output == expected
+
+
+def test_build_query_no_project():
+    # pypinfo -sd -2 -ed -1 -l 20 --all --test ''
+    project = ""
+    all_fields = []
+    start_date = "-2"
+    end_date = "-1"
+    days = None
+    limit = 20
+    where = None
+    order = None
+    pip = False
+    expected = r"""
+SELECT
+  COUNT(*) as download_count,
+FROM `bigquery-public-data.pypi.file_downloads`
+WHERE timestamp BETWEEN TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -2 DAY) AND TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -1 DAY)
+ORDER BY
+  download_count DESC
+LIMIT 20
+        """.strip()  # noqa: E501
+
+    # Act
+    output = core.build_query(project, all_fields, start_date, end_date, days, limit, where, order, pip)
+
+    # Assert
+    assert output == expected
+
+
 def test_build_query_bad_end_date():
     # Arrange
     project = "pycodestyle"