Repository: dbt-labs/dbt-core

Issue:
[CT-2697] Can't use integers in measure `expr` 
### Is this a new bug in dbt-core?

- [X] I believe this is a new bug in dbt-core
- [X] I have searched the existing issues, and I could not find an existing issue for this bug

### Current Behavior

Can’t use 1 in expr. A measure like below will yield the following error: `1 is not valid under any of the given schemas`

```
- name: orders
        expr: 1
        agg: sum
```

### Expected Behavior

I should be able to use integers in expr key. 

### Steps To Reproduce

Create a measure like below and run `dbt run`

```
- name: orders
        expr: 1
        agg: sum
```

### Relevant log output

_No response_

### Environment

```markdown
- OS:
- Python:
- dbt:
```


### Which database adapter are you using with dbt?

_No response_

### Additional Context

_No response_


Discussion:
cc @QMalcolm 

Resolving patch:
diff --git a/core/dbt/contracts/graph/unparsed.py b/core/dbt/contracts/graph/unparsed.py
--- a/core/dbt/contracts/graph/unparsed.py
+++ b/core/dbt/contracts/graph/unparsed.py
@@ -618,7 +618,7 @@ class UnparsedMetricTypeParams(dbtClassMixin):
     measure: Optional[Union[UnparsedMetricInputMeasure, str]] = None
     numerator: Optional[Union[UnparsedMetricInput, str]] = None
     denominator: Optional[Union[UnparsedMetricInput, str]] = None
-    expr: Optional[str] = None
+    expr: Optional[Union[str, bool]] = None
     window: Optional[str] = None
     grain_to_date: Optional[str] = None  # str is really a TimeGranularity Enum
     metrics: Optional[List[Union[UnparsedMetricInput, str]]] = None
@@ -698,7 +698,7 @@ class UnparsedMeasure(dbtClassMixin):
     agg: str  # actually an enum
     description: Optional[str] = None
     create_metric: bool = False
-    expr: Optional[str] = None
+    expr: Optional[Union[str, bool, int]] = None
     agg_params: Optional[MeasureAggregationParameters] = None
     non_additive_dimension: Optional[UnparsedNonAdditiveDimension] = None
     agg_time_dimension: Optional[str] = None
diff --git a/core/dbt/parser/schema_yaml_readers.py b/core/dbt/parser/schema_yaml_readers.py
--- a/core/dbt/parser/schema_yaml_readers.py
+++ b/core/dbt/parser/schema_yaml_readers.py
@@ -293,7 +293,7 @@ def _get_metric_type_params(self, type_params: UnparsedMetricTypeParams) -> Metr
             measure=self._get_optional_input_measure(type_params.measure),
             numerator=self._get_optional_metric_input(type_params.numerator),
             denominator=self._get_optional_metric_input(type_params.denominator),
-            expr=type_params.expr,
+            expr=str(type_params.expr) if type_params.expr is not None else None,
             window=self._get_time_window(type_params.window),
             grain_to_date=grain_to_date,
             metrics=self._get_metric_inputs(type_params.metrics),
@@ -500,7 +500,7 @@ def _get_measures(self, unparsed_measures: List[UnparsedMeasure]) -> List[Measur
                     agg=AggregationType(unparsed.agg),
                     description=unparsed.description,
                     create_metric=unparsed.create_metric,
-                    expr=unparsed.expr,
+                    expr=str(unparsed.expr) if unparsed.expr is not None else None,
                     agg_params=unparsed.agg_params,
                     non_additive_dimension=self._get_non_additive_dimension(
                         unparsed.non_additive_dimension


Test patch:
diff --git a/tests/functional/semantic_models/test_semantic_model_parsing.py b/tests/functional/semantic_models/test_semantic_model_parsing.py
--- a/tests/functional/semantic_models/test_semantic_model_parsing.py
+++ b/tests/functional/semantic_models/test_semantic_model_parsing.py
@@ -23,6 +23,12 @@
       - name: txn_revenue
         expr: revenue
         agg: sum
+      - name: sum_of_things
+        expr: 2
+        agg: sum
+      - name: has_revenue
+        expr: true
+        agg: sum_boolean
 
     dimensions:
       - name: ds
@@ -65,6 +71,7 @@ def test_semantic_model_parsing(self, project):
             semantic_model.node_relation.relation_name
             == f'"dbt"."{project.test_schema}"."fct_revenue"'
         )
+        assert len(semantic_model.measures) == 3
 
     @pytest.mark.skip("Restore this test when partial parsing is implemented.")
     def test_semantic_model_partial_parsing(self, project):