squirrels 0.4.0__py3-none-any.whl → 0.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of squirrels might be problematic. Click here for more details.

Files changed (125) hide show
  1. dateutils/__init__.py +6 -0
  2. dateutils/_enums.py +25 -0
  3. squirrels/dateutils.py → dateutils/_implementation.py +58 -111
  4. dateutils/types.py +6 -0
  5. squirrels/__init__.py +13 -11
  6. squirrels/_api_routes/__init__.py +5 -0
  7. squirrels/_api_routes/auth.py +271 -0
  8. squirrels/_api_routes/base.py +165 -0
  9. squirrels/_api_routes/dashboards.py +150 -0
  10. squirrels/_api_routes/data_management.py +145 -0
  11. squirrels/_api_routes/datasets.py +257 -0
  12. squirrels/_api_routes/oauth2.py +298 -0
  13. squirrels/_api_routes/project.py +252 -0
  14. squirrels/_api_server.py +256 -450
  15. squirrels/_arguments/__init__.py +0 -0
  16. squirrels/_arguments/init_time_args.py +108 -0
  17. squirrels/_arguments/run_time_args.py +147 -0
  18. squirrels/_auth.py +960 -0
  19. squirrels/_command_line.py +126 -45
  20. squirrels/_compile_prompts.py +147 -0
  21. squirrels/_connection_set.py +48 -26
  22. squirrels/_constants.py +68 -38
  23. squirrels/_dashboards.py +160 -0
  24. squirrels/_data_sources.py +570 -0
  25. squirrels/_dataset_types.py +84 -0
  26. squirrels/_exceptions.py +29 -0
  27. squirrels/_initializer.py +177 -80
  28. squirrels/_logging.py +115 -0
  29. squirrels/_manifest.py +208 -79
  30. squirrels/_model_builder.py +69 -0
  31. squirrels/_model_configs.py +74 -0
  32. squirrels/_model_queries.py +52 -0
  33. squirrels/_models.py +926 -367
  34. squirrels/_package_data/base_project/.env +42 -0
  35. squirrels/_package_data/base_project/.env.example +42 -0
  36. squirrels/_package_data/base_project/assets/expenses.db +0 -0
  37. squirrels/_package_data/base_project/connections.yml +16 -0
  38. squirrels/_package_data/base_project/dashboards/dashboard_example.py +34 -0
  39. squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
  40. squirrels/{package_data → _package_data}/base_project/docker/.dockerignore +5 -2
  41. squirrels/{package_data → _package_data}/base_project/docker/Dockerfile +3 -3
  42. squirrels/{package_data → _package_data}/base_project/docker/compose.yml +1 -1
  43. squirrels/_package_data/base_project/duckdb_init.sql +10 -0
  44. squirrels/{package_data/base_project/.gitignore → _package_data/base_project/gitignore} +3 -2
  45. squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
  46. squirrels/_package_data/base_project/models/builds/build_example.py +26 -0
  47. squirrels/_package_data/base_project/models/builds/build_example.sql +16 -0
  48. squirrels/_package_data/base_project/models/builds/build_example.yml +57 -0
  49. squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +12 -0
  50. squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +26 -0
  51. squirrels/_package_data/base_project/models/federates/federate_example.py +37 -0
  52. squirrels/_package_data/base_project/models/federates/federate_example.sql +19 -0
  53. squirrels/_package_data/base_project/models/federates/federate_example.yml +65 -0
  54. squirrels/_package_data/base_project/models/sources.yml +38 -0
  55. squirrels/{package_data → _package_data}/base_project/parameters.yml +56 -40
  56. squirrels/_package_data/base_project/pyconfigs/connections.py +14 -0
  57. squirrels/{package_data → _package_data}/base_project/pyconfigs/context.py +21 -40
  58. squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
  59. squirrels/_package_data/base_project/pyconfigs/user.py +44 -0
  60. squirrels/_package_data/base_project/seeds/seed_categories.yml +15 -0
  61. squirrels/_package_data/base_project/seeds/seed_subcategories.csv +15 -0
  62. squirrels/_package_data/base_project/seeds/seed_subcategories.yml +21 -0
  63. squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
  64. squirrels/_package_data/templates/dataset_results.html +112 -0
  65. squirrels/_package_data/templates/oauth_login.html +271 -0
  66. squirrels/_package_data/templates/squirrels_studio.html +20 -0
  67. squirrels/_package_loader.py +8 -4
  68. squirrels/_parameter_configs.py +104 -103
  69. squirrels/_parameter_options.py +348 -0
  70. squirrels/_parameter_sets.py +57 -47
  71. squirrels/_parameters.py +1664 -0
  72. squirrels/_project.py +721 -0
  73. squirrels/_py_module.py +7 -5
  74. squirrels/_schemas/__init__.py +0 -0
  75. squirrels/_schemas/auth_models.py +167 -0
  76. squirrels/_schemas/query_param_models.py +75 -0
  77. squirrels/{_api_response_models.py → _schemas/response_models.py} +126 -47
  78. squirrels/_seeds.py +35 -16
  79. squirrels/_sources.py +110 -0
  80. squirrels/_utils.py +248 -73
  81. squirrels/_version.py +1 -1
  82. squirrels/arguments.py +7 -0
  83. squirrels/auth.py +4 -0
  84. squirrels/connections.py +3 -0
  85. squirrels/dashboards.py +2 -81
  86. squirrels/data_sources.py +14 -631
  87. squirrels/parameter_options.py +13 -348
  88. squirrels/parameters.py +14 -1266
  89. squirrels/types.py +16 -0
  90. squirrels-0.5.0.dist-info/METADATA +113 -0
  91. squirrels-0.5.0.dist-info/RECORD +97 -0
  92. {squirrels-0.4.0.dist-info → squirrels-0.5.0.dist-info}/WHEEL +1 -1
  93. squirrels-0.5.0.dist-info/entry_points.txt +3 -0
  94. {squirrels-0.4.0.dist-info → squirrels-0.5.0.dist-info/licenses}/LICENSE +1 -1
  95. squirrels/_authenticator.py +0 -85
  96. squirrels/_dashboards_io.py +0 -61
  97. squirrels/_environcfg.py +0 -84
  98. squirrels/arguments/init_time_args.py +0 -40
  99. squirrels/arguments/run_time_args.py +0 -208
  100. squirrels/package_data/assets/favicon.ico +0 -0
  101. squirrels/package_data/assets/index.css +0 -1
  102. squirrels/package_data/assets/index.js +0 -58
  103. squirrels/package_data/base_project/assets/expenses.db +0 -0
  104. squirrels/package_data/base_project/connections.yml +0 -7
  105. squirrels/package_data/base_project/dashboards/dashboard_example.py +0 -32
  106. squirrels/package_data/base_project/dashboards.yml +0 -10
  107. squirrels/package_data/base_project/env.yml +0 -29
  108. squirrels/package_data/base_project/models/dbviews/dbview_example.py +0 -47
  109. squirrels/package_data/base_project/models/dbviews/dbview_example.sql +0 -22
  110. squirrels/package_data/base_project/models/federates/federate_example.py +0 -21
  111. squirrels/package_data/base_project/models/federates/federate_example.sql +0 -3
  112. squirrels/package_data/base_project/pyconfigs/auth.py +0 -45
  113. squirrels/package_data/base_project/pyconfigs/connections.py +0 -19
  114. squirrels/package_data/base_project/pyconfigs/parameters.py +0 -95
  115. squirrels/package_data/base_project/seeds/seed_subcategories.csv +0 -15
  116. squirrels/package_data/base_project/squirrels.yml.j2 +0 -94
  117. squirrels/package_data/templates/index.html +0 -18
  118. squirrels/project.py +0 -378
  119. squirrels/user_base.py +0 -55
  120. squirrels-0.4.0.dist-info/METADATA +0 -117
  121. squirrels-0.4.0.dist-info/RECORD +0 -60
  122. squirrels-0.4.0.dist-info/entry_points.txt +0 -4
  123. /squirrels/{package_data → _package_data}/base_project/assets/weather.db +0 -0
  124. /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.csv +0 -0
  125. /squirrels/{package_data → _package_data}/base_project/tmp/.gitignore +0 -0
@@ -4,36 +4,48 @@ parameters:
4
4
  arguments: ## arguments to specify depend on values for 'type' and 'factory'
5
5
  name: group_by
6
6
  label: Group By
7
- description: Dimension to aggregate by ## optional, default is empty string
7
+ description: Dimension(s) to aggregate by ## optional, default is empty string
8
+ user_attribute: access_level ## optional, default is null
8
9
  all_options:
9
- - id: g0
10
+ - id: trans
10
11
  label: Transaction
11
- columns: ["masked_id", "date", "description"] ## custom field
12
- aliases: ["id", "date", "description"] ## custom field
13
- is_default: false ## optional, default, exists for SingleSelect or MultiSelect options only
14
- user_groups: [] ## optional, default, exists for all parameter options
15
- parent_option_ids: [] ## optional, default, exists for all parameter options
16
- - id: g1
17
- label: Date
12
+ columns: ["id", "date", "category", "subcategory", "description"] ## custom field
13
+ aliases: ["_id", "date", "category", "subcategory", "description"] ## custom field (any alias starting with "_" will not be selected - see context.py for implementation)
14
+ is_default: false ## optional, shown is default - exists for SingleSelect or MultiSelect options only
15
+ user_groups: ["admin"] ## optional, default is empty list
16
+ parent_option_ids: [] ## optional, shown is default - exists for all parameter options
17
+ - id: day
18
+ label: Day
18
19
  columns: [date]
19
- - id: g2
20
+ aliases: [day]
21
+ user_groups: ["admin", "member"]
22
+ - id: month
23
+ label: Month
24
+ columns: [month]
25
+ user_groups: ["admin", "member", "guest"]
26
+ - id: cat
20
27
  label: Category
21
28
  columns: [category]
22
- - id: g3
29
+ user_groups: ["admin", "member", "guest"]
30
+ - id: subcat
23
31
  label: Subcategory
24
32
  columns: [category, subcategory]
25
- user_attribute: null ## optional, default, exists for all parameter types
26
- parent_name: null ## optional, default, exists for all parameter types
33
+ user_groups: ["admin", "member", "guest"]
34
+ parent_name: null ## optional, shown is default - exists for all parameter types
27
35
 
28
- - type: TextParameter
36
+ - type: NumberParameter
29
37
  factory: CreateWithOptions
30
38
  arguments:
31
- name: description_filter
32
- label: Description Contains
33
- description: Substring of description to filter transactions by
39
+ name: limit
40
+ label: Max Number of Rows
41
+ description: Maximum number of rows to return
34
42
  parent_name: group_by
35
43
  all_options:
36
- - parent_option_ids: g0
44
+ - min_value: 0
45
+ max_value: 1000
46
+ increment: 10
47
+ default_value: 1000
48
+ parent_option_ids: trans
37
49
 
38
50
  - type: DateParameter
39
51
  factory: CreateFromSource
@@ -42,7 +54,7 @@ parameters:
42
54
  label: Start Date
43
55
  description: Start date to filter transactions by
44
56
  data_source:
45
- table_or_query: SELECT min(date) AS min_date, max(date) AS max_date FROM transactions
57
+ table_or_query: SELECT min(date) AS min_date, max(date) AS max_date FROM expenses
46
58
  default_date_col: min_date
47
59
  min_date_col: min_date
48
60
  max_date_col: max_date
@@ -54,7 +66,9 @@ parameters:
54
66
  label: End Date
55
67
  description: End date to filter transactions by
56
68
  all_options:
57
- - default_date: 2023-12-31
69
+ - default_date: 2024-12-31
70
+ min_date: 2024-01-01
71
+ max_date: 2024-12-31
58
72
 
59
73
  - type: DateRangeParameter
60
74
  factory: CreateWithOptions
@@ -63,8 +77,10 @@ parameters:
63
77
  label: Date Range
64
78
  description: Date range to filter transactions by
65
79
  all_options:
66
- - default_start_date: 2023-01-01
67
- default_end_date: 2023-12-31
80
+ - default_start_date: 2024-01-01
81
+ default_end_date: 2024-12-31
82
+ min_date: 2024-01-01
83
+ max_date: 2024-12-31
68
84
 
69
85
  - type: MultiSelectParameter
70
86
  factory: CreateFromSource
@@ -76,14 +92,14 @@ parameters:
76
92
  table_or_query: seed_categories
77
93
  id_col: category_id
78
94
  options_col: category
79
- from_seeds: true ## optional, default is false, exists for data_source of any parameters
80
- order_by_col: null ## optional, default, exists for data_source of SingleSelect and MultiSelect
81
- is_default_col: null ## optional, default, exists for data_source of SingleSelect and MultiSelect
82
- custom_cols: {} ## optional, default, exists for data_source of SingleSelect and MultiSelect
83
- include_all: true ## optional, default, exists for data_source of MultiSelect only
84
- order_matters: false ## optional, default, exists for data_source of MultiSelect only
85
- user_group_col: null ## optional, default, exists for data_source of any parameters
86
- connection_name: default ## optional, default, exists for data_source of any parameters
95
+ source: seeds ## optional, default is "connection" - must be one of "connection", "seeds", or "vdl" - exists for data_source of any parameters
96
+ order_by_col: null ## optional, shown is default - exists for data_source of SingleSelect and MultiSelect
97
+ is_default_col: null ## optional, shown is default - exists for data_source of SingleSelect and MultiSelect
98
+ custom_cols: {} ## optional, shown is default - exists for data_source of SingleSelect and MultiSelect
99
+ include_all: true ## optional, shown is default - exists for data_source of MultiSelect only
100
+ order_matters: false ## optional, shown is default - exists for data_source of MultiSelect only
101
+ user_group_col: null ## optional, shown is default - exists for data_source of any parameters
102
+ connection_name: default ## optional, shown is default - exists for data_source of any parameters
87
103
 
88
104
  - type: MultiSelectParameter
89
105
  factory: CreateFromSource
@@ -96,8 +112,8 @@ parameters:
96
112
  table_or_query: seed_subcategories
97
113
  id_col: subcategory_id
98
114
  options_col: subcategory
99
- from_seeds: true
100
- parent_id_col: category_id ## optional, default is null, exists for all parameter types
115
+ source: seeds
116
+ parent_id_col: category_id ## optional, default is null - exists for all parameter types
101
117
 
102
118
  - type: NumberParameter
103
119
  factory: CreateWithOptions
@@ -107,9 +123,9 @@ parameters:
107
123
  description: Number to filter on transactions with an amount greater than this value
108
124
  all_options:
109
125
  - min_value: 0
110
- max_value: 500
111
- increment: 10 ## optional, default is 1, exists for Number and NumberRange options
112
- default_value: null ## optional, default, exists for Number options only
126
+ max_value: 300
127
+ increment: 10 ## optional, default is 1 - exists for Number and NumberRange options
128
+ default_value: null ## optional, shown is default - exists for Number options only
113
129
 
114
130
  - type: NumberParameter
115
131
  factory: CreateFromSource
@@ -118,12 +134,12 @@ parameters:
118
134
  label: Amounts Less Than
119
135
  description: Number to filter on transactions with an amount less than this value
120
136
  data_source:
121
- table_or_query: "SELECT 0 as min_value, max(-amount) as max_value, 10 as increment FROM transactions WHERE category <> 'Income'"
137
+ table_or_query: "SELECT 0 as min_value, 300 as max_value, 10 as increment"
122
138
  min_value_col: min_value
123
139
  max_value_col: max_value
124
140
  increment_col: increment ## optional, default is null
125
141
  default_value_col: max_value ## optional, default is null
126
- id_col: null ## optional, default, required for SingleSelect and MultiSelect, optional for all others
142
+ id_col: null ## optional, shown is default - required for SingleSelect and MultiSelect, optional for others
127
143
 
128
144
  - type: NumberRangeParameter
129
145
  factory: CreateWithOptions
@@ -133,8 +149,8 @@ parameters:
133
149
  description: Number range to filter on transactions with an amount within this range
134
150
  all_options:
135
151
  - min_value: 0
136
- max_value: 500
137
- default_lower_value: 10 ## optional, default is null (or min_value), exists for NumRange options only
138
- default_upper_value: 400 ## optional, default is null (or max_value), exists for NumRange options only
152
+ max_value: 300
153
+ default_lower_value: 0 ## optional, default is null (or min_value) - exists for NumberRange options only
154
+ default_upper_value: 300 ## optional, default is null (or max_value) - exists for NumberRange options only
139
155
 
140
156
 
@@ -0,0 +1,14 @@
1
+ from typing import Any
2
+ from squirrels import arguments as args, connections as cn
3
+
4
+
5
+ def main(connections: dict[str, cn.ConnectionProperties | Any], sqrl: args.ConnectionsArgs) -> None:
6
+ """
7
+ Define sqlalchemy engines by adding them to the "connections" dictionary
8
+ """
9
+ ## SQLAlchemy URL for a connection engine
10
+ conn_str: str = sqrl.env_vars["SQLITE_URI"].format(project_path=sqrl.project_path)
11
+
12
+ ## Assigning names to connection engines
13
+ connections["default"] = cn.ConnectionProperties(label="SQLite Expenses Database", type=cn.ConnectionTypeEnum.SQLALCHEMY, uri=conn_str)
14
+
@@ -1,14 +1,14 @@
1
1
  from typing import Any
2
- from squirrels import ContextArgs, parameters as p
2
+ from squirrels import arguments as args, parameters as p
3
3
 
4
4
 
5
- def main(ctx: dict[str, Any], sqrl: ContextArgs) -> None:
5
+ def main(ctx: dict[str, Any], sqrl: args.ContextArgs) -> None:
6
6
  """
7
7
  Define context variables AFTER parameter selections are made by adding entries to the dictionary "ctx".
8
8
  These context variables can then be used in the models.
9
9
 
10
10
  Note that the code here is used by all datasets, regardless of the parameters they use. You can use
11
- sqrl.prms and/or sqrl.traits to determine the conditions to execute certain blocks of code.
11
+ sqrl.param_exists to determine the conditions to execute certain blocks of code.
12
12
  """
13
13
  if sqrl.param_exists("group_by"):
14
14
  group_by_param = sqrl.prms["group_by"]
@@ -16,84 +16,65 @@ def main(ctx: dict[str, Any], sqrl: ContextArgs) -> None:
16
16
 
17
17
  columns = group_by_param.get_selected("columns")
18
18
  aliases = group_by_param.get_selected("aliases", default_field="columns")
19
- assert isinstance(columns, list) and isinstance(aliases, list)
19
+ assert isinstance(columns, list) and isinstance(aliases, list) and len(columns) == len(aliases)
20
20
 
21
- ctx["select_dim_cols"] = ", ".join(x+" as "+y for x, y in zip(columns, aliases))
22
- ctx["group_by_cols"] = ", ".join(columns)
23
- ctx["order_by_cols"] = ", ".join((x+" DESC") for x in aliases)
24
- ctx["order_by_cols_list"] = aliases
25
-
26
- if sqrl.param_exists("description_filter"):
27
- descript_param = sqrl.prms["description_filter"]
28
- assert isinstance(descript_param, p.TextParameter)
29
-
30
- desc_pattern = descript_param.get_entered_text().apply_percent_wrap()
31
-
32
- sqrl.set_placeholder("desc_pattern", desc_pattern)
21
+ column_to_alias_mapping = {x: y for x, y in zip(columns, aliases) if not y.startswith("_")}
33
22
 
23
+ ctx["group_by_cols"] = columns
24
+ ctx["select_dim_cols"] = list(x+" as "+y for x, y in column_to_alias_mapping.items())
25
+ ctx["order_by_cols"] = list(column_to_alias_mapping.values())
26
+ ctx["order_by_cols_desc"] = list(x+" DESC" for x in ctx["order_by_cols"])
27
+ ctx["column_to_alias_mapping"] = column_to_alias_mapping
28
+
34
29
  if sqrl.param_exists("start_date"):
35
30
  start_date_param = sqrl.prms["start_date"]
36
31
  assert isinstance(start_date_param, p.DateParameter)
37
32
 
38
- start_date = start_date_param.get_selected_date()
39
-
40
- sqrl.set_placeholder("start_date", start_date)
33
+ ctx["start_date"] = start_date_param.get_selected_date()
41
34
 
42
35
  if sqrl.param_exists("end_date"):
43
36
  end_date_param = sqrl.prms["end_date"]
44
37
  assert isinstance(end_date_param, p.DateParameter)
45
38
 
46
- end_date = end_date_param.get_selected_date()
47
-
48
- sqrl.set_placeholder("end_date", end_date)
39
+ ctx["end_date"] = end_date_param.get_selected_date()
49
40
 
50
41
  if sqrl.param_exists("date_range"):
51
42
  date_range_param = sqrl.prms["date_range"]
52
43
  assert isinstance(date_range_param, p.DateRangeParameter)
53
44
 
54
- start_date = date_range_param.get_selected_start_date()
55
- end_date = date_range_param.get_selected_end_date()
56
-
57
- sqrl.set_placeholder("start_date", start_date)
58
- sqrl.set_placeholder("end_date", end_date)
45
+ ctx["start_date_from_range"] = date_range_param.get_selected_start_date()
46
+ ctx["end_date_from_range"] = date_range_param.get_selected_end_date()
59
47
 
60
48
  if sqrl.param_exists("category"):
61
49
  category_param = sqrl.prms["category"]
62
50
  assert isinstance(category_param, p.MultiSelectParameter)
63
51
 
64
52
  ctx["has_categories"] = category_param.has_non_empty_selection()
65
- ctx["categories"] = category_param.get_selected_labels_quoted_joined()
53
+ ctx["categories"] = category_param.get_selected_ids_as_list()
66
54
 
67
55
  if sqrl.param_exists("subcategory"):
68
56
  subcategory_param = sqrl.prms["subcategory"]
69
57
  assert isinstance(subcategory_param, p.MultiSelectParameter)
70
58
 
71
59
  ctx["has_subcategories"] = subcategory_param.has_non_empty_selection()
72
- ctx["subcategories"] = subcategory_param.get_selected_labels_quoted_joined()
60
+ ctx["subcategories"] = subcategory_param.get_selected_ids_as_list()
73
61
 
74
62
  if sqrl.param_exists("min_filter"):
75
63
  min_amount_filter = sqrl.prms["min_filter"]
76
64
  assert isinstance(min_amount_filter, p.NumberParameter)
77
65
 
78
- min_amount = min_amount_filter.get_selected_value()
79
-
80
- sqrl.set_placeholder("min_amount", min_amount)
66
+ ctx["min_amount"] = min_amount_filter.get_selected_value()
81
67
 
82
68
  if sqrl.param_exists("max_filter"):
83
69
  max_amount_filter = sqrl.prms["max_filter"]
84
70
  assert isinstance(max_amount_filter, p.NumberParameter)
85
71
 
86
- max_amount = max_amount_filter.get_selected_value()
87
-
88
- sqrl.set_placeholder("max_amount", max_amount)
72
+ ctx["max_amount"] = max_amount_filter.get_selected_value()
89
73
 
90
74
  if sqrl.param_exists("between_filter"):
91
75
  between_filter = sqrl.prms["between_filter"]
92
76
  assert isinstance(between_filter, p.NumberRangeParameter)
93
77
 
94
- min_amount = between_filter.get_selected_lower_value()
95
- max_amount = between_filter.get_selected_upper_value()
96
-
97
- sqrl.set_placeholder("min_amount", min_amount)
98
- sqrl.set_placeholder("max_amount", max_amount)
78
+ ctx["min_amount_from_range"] = between_filter.get_selected_lower_value()
79
+ ctx["max_amount_from_range"] = between_filter.get_selected_upper_value()
99
80
 
@@ -0,0 +1,141 @@
1
+ from squirrels import parameters as p, parameter_options as po, data_sources as ds
2
+
3
+
4
+ ## Example of creating SingleSelectParameter and specifying each option by code
5
+ @p.SingleSelectParameter.create_with_options(
6
+ name="group_by", label="Group By",
7
+ description="Dimension(s) to aggregate by",
8
+ user_attribute="access_level"
9
+ )
10
+ def group_by_options():
11
+ return [
12
+ po.SelectParameterOption(
13
+ id="trans", label="Transaction",
14
+ columns=["id","date","category","subcategory","description"],
15
+ aliases=["_id","date","category","subcategory","description"], # in context.py, any alias starting with "_" will not be selected
16
+ user_groups=["admin"]
17
+ ),
18
+ po.SelectParameterOption(
19
+ id="day", label="Day",
20
+ columns=["date"],
21
+ aliases=["day"],
22
+ user_groups=["admin","member"]
23
+ ),
24
+ po.SelectParameterOption(
25
+ id="month", label="Month",
26
+ columns=["month"],
27
+ user_groups=["admin","member","guest"]
28
+ ),
29
+ po.SelectParameterOption(
30
+ id="cat", label="Category",
31
+ columns=["category"],
32
+ user_groups=["admin","member","guest"]
33
+ ),
34
+ po.SelectParameterOption(
35
+ id="subcat", label="Subcategory",
36
+ columns=["category","subcategory"],
37
+ user_groups=["admin","member","guest"]
38
+ ),
39
+ ]
40
+
41
+
42
+ ## Example of creating DateParameter
43
+ @p.DateParameter.create_from_source(
44
+ name="start_date", label="Start Date",
45
+ description="Start date to filter transactions by"
46
+ )
47
+ def start_date_source():
48
+ return ds.DateDataSource(
49
+ table_or_query="SELECT min(date) AS min_date, max(date) AS max_date FROM expenses",
50
+ default_date_col="min_date",
51
+ min_date_col="min_date", max_date_col="max_date",
52
+ )
53
+
54
+
55
+ ## Example of creating DateParameter from list of DateParameterOption's
56
+ @p.DateParameter.create_with_options(
57
+ name="end_date", label="End Date",
58
+ description="End date to filter transactions by"
59
+ )
60
+ def end_date_options():
61
+ return [
62
+ po.DateParameterOption(
63
+ default_date="2024-12-31", min_date="2024-01-01", max_date="2024-12-31"
64
+ )
65
+ ]
66
+
67
+
68
+ ## Example of creating DateRangeParameter
69
+ @p.DateRangeParameter.create_simple(
70
+ name="date_range", label="Date Range",
71
+ default_start_date="2024-01-01", default_end_date="2024-12-31",
72
+ min_date="2024-01-01", max_date="2024-12-31",
73
+ description="Date range to filter transactions by"
74
+ )
75
+ def date_range_options():
76
+ pass
77
+
78
+
79
+ ## Example of creating MultiSelectParameter from lookup query/table
80
+ @p.MultiSelectParameter.create_from_source(
81
+ name="category", label="Category Filter",
82
+ description="The expense categories to filter transactions by"
83
+ )
84
+ def category_source():
85
+ return ds.SelectDataSource(
86
+ table_or_query="seed_categories",
87
+ id_col="category_id",
88
+ options_col="category",
89
+ source=ds.SourceEnum.SEEDS
90
+ )
91
+
92
+
93
+ ## Example of creating MultiSelectParameter with parent from lookup query/table
94
+ @p.MultiSelectParameter.create_from_source(
95
+ name="subcategory", label="Subcategory Filter",
96
+ description="The expense subcategories to filter transactions by (available options are based on selected value(s) of 'Category Filter')",
97
+ parent_name="category"
98
+ )
99
+ def subcategory_source():
100
+ return ds.SelectDataSource(
101
+ table_or_query="seed_subcategories",
102
+ id_col="subcategory_id",
103
+ options_col="subcategory",
104
+ source=ds.SourceEnum.SEEDS,
105
+ parent_id_col="category_id"
106
+ )
107
+
108
+
109
+ ## Example of creating NumberParameter
110
+ @p.NumberParameter.create_simple(
111
+ name="min_filter", label="Amounts Greater Than",
112
+ min_value=0, max_value=300, increment=10,
113
+ description="Number to filter on transactions with an amount greater than this value"
114
+ )
115
+ def min_filter_options():
116
+ pass
117
+
118
+
119
+ ## Example of creating NumberParameter from lookup query/table
120
+ @p.NumberParameter.create_from_source(
121
+ name="max_filter", label="Amounts Less Than",
122
+ description="Number to filter on transactions with an amount less than this value"
123
+ )
124
+ def max_filter_source():
125
+ return ds.NumberDataSource(
126
+ table_or_query="SELECT 0 as min_value, 300 as max_value, 10 as increment",
127
+ min_value_col="min_value", max_value_col="max_value",
128
+ increment_col="increment",
129
+ default_value_col="max_value"
130
+ )
131
+
132
+
133
+ ## Example of creating NumberRangeParameter
134
+ @p.NumberRangeParameter.create_simple(
135
+ name="between_filter", label="Amounts Between",
136
+ min_value=0, max_value=300,
137
+ default_lower_value=0, default_upper_value=300,
138
+ description="Number range to filter on transactions with an amount within this range"
139
+ )
140
+ def between_filter_options():
141
+ pass
@@ -0,0 +1,44 @@
1
+ from typing import Literal
2
+ from squirrels import auth, arguments as args
3
+
4
+
5
+ class CustomUserFields(auth.CustomUserFields):
6
+ """
7
+ Extend the CustomUserFields class to add custom user attributes.
8
+ - Only the following types are supported: [str, int, float, bool, typing.Literal]
9
+ - Add "| None" after the type to make it nullable.
10
+ - Always set a default value for the field (use None if default is null).
11
+
12
+ Example:
13
+ organization: str | None = None
14
+ """
15
+ role: Literal["manager", "employee"] = "employee"
16
+
17
+
18
+ # @auth.provider(name="google", label="Google", icon="https://www.google.com/favicon.ico")
19
+ def google_auth_provider(sqrl: args.AuthProviderArgs) -> auth.ProviderConfigs:
20
+ """
21
+ Provider configs for authenticating a user using Google credentials.
22
+
23
+ See the following page for setting up the CLIENT_ID and CLIENT_SECRET for Google specifically:
24
+ https://support.google.com/googleapi/answer/6158849?hl=en
25
+ """
26
+ def get_sqrl_user(claims: dict) -> auth.RegisteredUser:
27
+ custom_fields = CustomUserFields(role="employee")
28
+ return auth.RegisteredUser(
29
+ username=claims["email"],
30
+ access_level="member",
31
+ custom_fields=custom_fields
32
+ )
33
+
34
+ # TODO: Add GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET to the .env file
35
+ # Then, uncomment the @auth.provider decorator above and set the client_id and client_secret below
36
+ provider_configs = auth.ProviderConfigs(
37
+ client_id="", # sqrl.env_vars["GOOGLE_CLIENT_ID"],
38
+ client_secret="", # sqrl.env_vars["GOOGLE_CLIENT_SECRET"],
39
+ server_url="https://accounts.google.com",
40
+ client_kwargs={"scope": "openid email profile"},
41
+ get_user=get_sqrl_user
42
+ )
43
+
44
+ return provider_configs
@@ -0,0 +1,15 @@
1
+ description: |
2
+ Lookup table for the category IDs and names of transactions.
3
+
4
+ cast_column_types: true # optional, default is false - setting SQRL_SEEDS__INFER_SCHEMA is ignored for this seed if this is set to true
5
+
6
+ columns:
7
+ - name: category_id
8
+ type: string
9
+ description: The category ID
10
+ category: dimension
11
+
12
+ - name: category
13
+ type: string
14
+ description: The human-readable category name
15
+ category: dimension
@@ -0,0 +1,15 @@
1
+ "subcategory_id","subcategory","category_id"
2
+ "0","Dining Out","0"
3
+ "1","Groceries","0"
4
+ "2","Utilities","1"
5
+ "3","Electronics","2"
6
+ "4","Ride Sharing","3"
7
+ "5","Mobile","1"
8
+ "6","Home Decor","2"
9
+ "7","Internet","1"
10
+ "8","Theater","4"
11
+ "9","Movies","4"
12
+ "10","Sports","2"
13
+ "11","Public Transit","3"
14
+ "12","Clothing","2"
15
+ "13","Concerts","4"
@@ -0,0 +1,21 @@
1
+ description: |
2
+ Lookup table for the subcategory IDs and names of transactions.
3
+
4
+ cast_column_types: true # optional, default is false - setting SQRL_SEEDS__INFER_SCHEMA is ignored for this seed if this is set to true
5
+
6
+ columns:
7
+ - name: subcategory_id
8
+ type: string
9
+ description: The subcategory ID
10
+ category: dimension
11
+
12
+ - name: subcategory
13
+ type: string
14
+ description: The human-readable subcategory name
15
+ category: dimension
16
+
17
+ - name: category_id
18
+ type: string
19
+ description: The category ID that the subcategory belongs to
20
+ category: dimension
21
+
@@ -0,0 +1,61 @@
1
+ project_variables:
2
+ name: sample_expenses
3
+ label: "Sample Expenses"
4
+ description: This is a sample squirrels project for analyzing expense transactions
5
+ major_version: 1
6
+
7
+
8
+ packages: []
9
+
10
+ ## Example for packages section:
11
+ # packages:
12
+ # - git: https://.../myrepo.git
13
+ # revision: v0.1.0
14
+ # directory: custom_name ## optional
15
+
16
+
17
+ {{ connections -}}
18
+
19
+
20
+ {{ parameters -}}
21
+
22
+
23
+ datasets:
24
+ - name: dbview_dataset_example ## model name uses same name unless "model" field is specified
25
+ label: Example Dataset from DBView Model
26
+ description: Aggregated expense transactions by month using dbview_example model
27
+ model: dbview_example
28
+ scope: private ## optional - one of 'public' (default), 'protected', or 'private'
29
+ parameters: ## optional - if not specified, then all parameters are used
30
+ - start_date
31
+ - end_date
32
+ - min_filter
33
+ - max_filter
34
+
35
+ - name: federate_dataset_example
36
+ label: Example Dataset from Federate Model
37
+ description: Aggregated expense transactions by custom dimension using federate_example model
38
+ model: federate_example
39
+ scope: public ## using an auth.py file is suggested for protected or private datasets
40
+ parameters:
41
+ - group_by
42
+ - date_range
43
+ - category
44
+ - subcategory
45
+ - between_filter
46
+
47
+
48
+ selection_test_sets:
49
+ - name: set_start_date
50
+ parameters: ## optional section - if not provided, then default value is used for all parameters
51
+ start_date: 2024-07-01 ## this parameter is only used by model "dbview_example"
52
+
53
+ - name: set_date_range
54
+ parameters:
55
+ date_range: [2024-02-01,2024-11-30] ## this parameter is only used by model "federate_example"
56
+
57
+ - name: use_admin_privileged_group_by
58
+ user:
59
+ access_level: admin
60
+ parameters:
61
+ group_by: trans