propel_api 0.3.2 โ 0.3.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +66 -0
- data/FILTERING_DOCUMENTATION.md +470 -0
- data/README.md +46 -1
- data/lib/generators/propel_api/core/named_base.rb +47 -76
- data/lib/generators/propel_api/install/install_generator.rb +43 -2
- data/lib/generators/propel_api/templates/concerns/propel_controller_filters_concern.rb +141 -0
- data/lib/generators/propel_api/templates/concerns/propel_model_filters_concern.rb +128 -0
- data/lib/generators/propel_api/templates/controllers/api_controller_propel_facets.rb +1 -0
- data/lib/generators/propel_api/templates/lib/XX_dynamic_scope_generator.rb +360 -0
- data/lib/generators/propel_api/templates/lib/propel_dynamic_scope_generator.rb +473 -0
- data/lib/generators/propel_api/templates/lib/propel_filter_operators.rb +16 -0
- data/lib/generators/propel_api/templates/scaffold/facet_model_template.rb.tt +14 -0
- data/lib/generators/propel_api/templates/seeds/seeds_template.rb.tt +100 -6
- data/lib/generators/propel_api/templates/tests/controller_test_template.rb.tt +9 -0
- data/lib/generators/propel_api/templates/tests/integration_test_template.rb.tt +660 -10
- data/lib/generators/propel_api/templates/tests/model_test_template.rb.tt +7 -0
- data/lib/propel_api.rb +1 -1
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04fb55f19379b238226c473c68009234156cc6f788d54eb29a89155db938556e
|
4
|
+
data.tar.gz: 6bb69d00b06c6497d0a6fbbec4d4bafc026cd2b1484eaef48e9b31e9bd20564d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49af6bb0bbfcad1d62fdf4aada990189a1c1e850df87f1cee4b284ece041bf7c3c777907deff2d2df332b7b44a4563dba6b6f4de29c75c3e4c2e97609345b8d5
|
7
|
+
data.tar.gz: 87d70201da1cd3e2630cc1135997dfdb8bcf7c17900a341e4f9337d9accdc446d64dea4a06aeafcf1a7ae6e621daa2366ab5ea7c35e5434f594bd5e2fbb9869a
|
data/CHANGELOG.md
CHANGED
@@ -7,9 +7,75 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [0.3.4] - 2025-09-29
|
11
|
+
|
12
|
+
### Fixed
|
13
|
+
- **Custom `has_scope` definitions**: The dynamic scope generator no longer overrides custom `has_scope` definitions, allowing developers to implement their own filtering logic without interference.
|
14
|
+
- **`has_scope` parameter filtering**: All declared `has_scope` parameters (both dynamic and custom) are now automatically permitted, fixing an issue where they were being filtered out as unsafe.
|
15
|
+
|
10
16
|
### Planned Features
|
11
17
|
- GraphQL adapter support
|
12
18
|
|
19
|
+
## [0.3.3] - 2025-01-XX
|
20
|
+
|
21
|
+
### ๐ Major Features Added
|
22
|
+
- **Comprehensive Dynamic Filtering System**: Complete implementation of automatic URL query string filtering and scoping using the `has_scope` gem
|
23
|
+
- **Multi-Type Filtering Support**: Full filtering support across all data types (string, numeric, boolean, datetime, date, time)
|
24
|
+
- **Database-Agnostic Implementation**: Works seamlessly across SQLite, PostgreSQL, and MySQL without database-specific code
|
25
|
+
- **Automatic Scope Generation**: Dynamic scope generation based on model column types and filter operators
|
26
|
+
- **Intelligent Facet Integration**: Automatic inclusion of filterable fields in JSON facets for API responses
|
27
|
+
|
28
|
+
### ๐ Advanced Filtering Capabilities
|
29
|
+
- **String Filtering**: Exact match (`_eq`), contains (`_contains`), starts with (`_starts_with`), ends with (`_ends_with`), in list (`_in`)
|
30
|
+
- **Numeric Filtering**: Comparison operators (`_gt`, `_lt`, `_gte`, `_lte`), range filtering (`_range`), in list (`_in`)
|
31
|
+
- **Boolean Filtering**: Multiple value format support (`true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off`)
|
32
|
+
- **DateTime Filtering**: Temporal comparisons (`_before`, `_after`), date extraction (`_year`, `_month`, `_day`), date matching (`_date`)
|
33
|
+
- **Range Filtering**: Support for both array and string formats (e.g., `"150,350"` or `[150, 350]`)
|
34
|
+
|
35
|
+
### ๐ ๏ธ Technical Implementation
|
36
|
+
- **PropelDynamicScopeGenerator**: New generator class for automatic scope creation based on model columns
|
37
|
+
- **PropelModelFiltersConcern**: Model concern for dynamic scope generation and filter parameter validation
|
38
|
+
- **PropelControllerFiltersConcern**: Controller concern for has_scope integration and security validation
|
39
|
+
- **PropelFilterOperators**: Configuration class defining available operators for each data type
|
40
|
+
- **Database-Agnostic Datetime Parsing**: Ruby-based datetime parsing instead of SQL extraction functions
|
41
|
+
|
42
|
+
### ๐ Security & Performance
|
43
|
+
- **Input Validation**: Comprehensive validation of filter parameters against allowed field names and operators
|
44
|
+
- **SQL Injection Protection**: All parameters properly escaped and parameterized
|
45
|
+
- **Multi-Tenancy Integration**: Automatic organization scoping for all filtered queries
|
46
|
+
- **Sensitive Field Filtering**: Automatic exclusion of sensitive fields (passwords, tokens, etc.) from filtering
|
47
|
+
- **Performance Optimization**: Efficient range queries and indexed field prioritization
|
48
|
+
|
49
|
+
### ๐ Enhanced JSON Facet System
|
50
|
+
- **Smart Field Inclusion**: Automatic inclusion of boolean and datetime fields in `:short` facets
|
51
|
+
- **Exclusion Lists**: Configurable exclusion of specific fields (e.g., `created_at`, `updated_at`, `internal_flag`)
|
52
|
+
- **Consistent Serialization**: Ensures filterable fields are available in API responses for client-side filtering
|
53
|
+
|
54
|
+
### ๐งช Comprehensive Testing
|
55
|
+
- **Test-Driven Development**: Complete test suite with 992 tests covering all filtering scenarios
|
56
|
+
- **Fixture-Aware Testing**: Unique test data values to avoid conflicts with fixture data
|
57
|
+
- **Multi-Tenancy Testing**: Proper testing of organization-scoped filtering
|
58
|
+
- **Edge Case Coverage**: Testing of invalid inputs, empty values, and error conditions
|
59
|
+
- **Database Compatibility**: Tests pass across SQLite, PostgreSQL, and MySQL
|
60
|
+
|
61
|
+
### ๐ Documentation & Examples
|
62
|
+
- **Comprehensive API Documentation**: Complete filtering documentation with examples for all operators
|
63
|
+
- **Postman Collection Ready**: Detailed query parameter examples for testing
|
64
|
+
- **Error Handling Guide**: Common error scenarios and troubleshooting tips
|
65
|
+
- **Performance Guidelines**: Optimization recommendations for large datasets
|
66
|
+
|
67
|
+
### ๐ง Configuration & Customization
|
68
|
+
- **Flexible Operator Configuration**: Easy addition of new filter operators via `PropelFilterOperators`
|
69
|
+
- **Customizable Field Exclusions**: Configurable lists for fields to exclude from facets
|
70
|
+
- **Template-Based Generation**: All filtering code generated via ERB templates for easy customization
|
71
|
+
- **Backward Compatibility**: Existing applications continue to work without changes
|
72
|
+
|
73
|
+
### ๐ Bug Fixes
|
74
|
+
- **Template Syntax Errors**: Fixed ERB template syntax issues with `next` vs `return` in select blocks
|
75
|
+
- **Scope Generation Caching**: Resolved issues with cached scopes not updating after template changes
|
76
|
+
- **Datetime Parsing Errors**: Fixed datetime scope generation to handle multiple input formats
|
77
|
+
- **SQL Compatibility**: Resolved SQLite `EXTRACT` function compatibility issues
|
78
|
+
|
13
79
|
## [0.3.2] - 2025-09-15
|
14
80
|
|
15
81
|
### ๐ Critical Bug Fixes
|
@@ -0,0 +1,470 @@
|
|
1
|
+
# Propel Rails Filtering System Documentation
|
2
|
+
|
3
|
+
## Overview
|
4
|
+
|
5
|
+
The Propel Rails filtering system provides automatic URL query string filtering and scoping using the `has_scope` gem. It supports filtering across multiple data types with various operators, making it easy to build powerful search and filter interfaces.
|
6
|
+
|
7
|
+
## Base URL Structure
|
8
|
+
|
9
|
+
```
|
10
|
+
GET {{base_url}}/api/v1/{resource}
|
11
|
+
```
|
12
|
+
|
13
|
+
## Authentication
|
14
|
+
|
15
|
+
All API requests require authentication via JWT token in the Authorization header:
|
16
|
+
|
17
|
+
```
|
18
|
+
Authorization: Bearer <your_jwt_token>
|
19
|
+
```
|
20
|
+
|
21
|
+
## Data Types and Supported Operators
|
22
|
+
|
23
|
+
### 1. String Fields
|
24
|
+
|
25
|
+
String fields support text-based filtering with multiple operators.
|
26
|
+
|
27
|
+
#### Supported Operators
|
28
|
+
|
29
|
+
| Operator | Description | Example |
|
30
|
+
|----------|-------------|---------|
|
31
|
+
| `_eq` | Exact match | `name_eq=Acme Corporation` |
|
32
|
+
| `_contains` | Contains substring | `title_contains=Project` |
|
33
|
+
| `_starts_with` | Starts with substring | `name_starts_with=Acme` |
|
34
|
+
| `_ends_with` | Ends with substring | `email_ends_with=@company.com` |
|
35
|
+
| `_in` | In list of values | `status_in=active,pending` |
|
36
|
+
|
37
|
+
#### Examples
|
38
|
+
|
39
|
+
```bash
|
40
|
+
# Exact match
|
41
|
+
GET /api/v1/meetings?title_eq=Important Meeting
|
42
|
+
|
43
|
+
# Contains search
|
44
|
+
GET /api/v1/meetings?title_contains=Project
|
45
|
+
|
46
|
+
# Starts with
|
47
|
+
GET /api/v1/organizations?name_starts_with=Acme
|
48
|
+
|
49
|
+
# Ends with
|
50
|
+
GET /api/v1/users?email_ends_with=@company.com
|
51
|
+
|
52
|
+
# Multiple values
|
53
|
+
GET /api/v1/meetings?status_in=active,pending,cancelled
|
54
|
+
```
|
55
|
+
|
56
|
+
### 2. Numeric Fields (Integer, Decimal, Float)
|
57
|
+
|
58
|
+
Numeric fields support mathematical comparisons and range operations.
|
59
|
+
|
60
|
+
#### Supported Operators
|
61
|
+
|
62
|
+
| Operator | Description | Example |
|
63
|
+
|----------|-------------|---------|
|
64
|
+
| `_eq` | Equal to | `max_participants_eq=50` |
|
65
|
+
| `_gt` | Greater than | `max_participants_gt=100` |
|
66
|
+
| `_lt` | Less than | `max_participants_lt=500` |
|
67
|
+
| `_gte` | Greater than or equal | `max_participants_gte=200` |
|
68
|
+
| `_lte` | Less than or equal | `max_participants_lte=400` |
|
69
|
+
| `_min` | Alias for `_gte` | `max_participants_min=100` |
|
70
|
+
| `_max` | Alias for `_lte` | `max_participants_max=500` |
|
71
|
+
| `_range` | Between two values | `max_participants_range=150,350` |
|
72
|
+
| `_in` | In list of values | `room_id_in=1,2,3,4` |
|
73
|
+
|
74
|
+
#### Examples
|
75
|
+
|
76
|
+
```bash
|
77
|
+
# Exact match
|
78
|
+
GET /api/v1/meetings?max_participants_eq=50
|
79
|
+
|
80
|
+
# Greater than
|
81
|
+
GET /api/v1/meetings?max_participants_gt=100
|
82
|
+
|
83
|
+
# Less than
|
84
|
+
GET /api/v1/meetings?max_participants_lt=500
|
85
|
+
|
86
|
+
# Range filtering
|
87
|
+
GET /api/v1/meetings?max_participants_range=150,350
|
88
|
+
|
89
|
+
# Multiple values
|
90
|
+
GET /api/v1/meetings?room_id_in=1,2,3
|
91
|
+
|
92
|
+
# Combined numeric filters
|
93
|
+
GET /api/v1/meetings?max_participants_gte=20&max_participants_lte=100
|
94
|
+
```
|
95
|
+
|
96
|
+
### 3. Boolean Fields
|
97
|
+
|
98
|
+
Boolean fields support true/false filtering with multiple value formats.
|
99
|
+
|
100
|
+
#### Supported Operators
|
101
|
+
|
102
|
+
| Operator | Description | Example |
|
103
|
+
|----------|-------------|---------|
|
104
|
+
| `_eq` | Equal to boolean value | `recording_enabled_eq=true` |
|
105
|
+
|
106
|
+
#### Supported Boolean Values
|
107
|
+
|
108
|
+
| Value | Description |
|
109
|
+
|-------|-------------|
|
110
|
+
| `true`, `false` | Standard boolean |
|
111
|
+
| `1`, `0` | Numeric boolean |
|
112
|
+
| `yes`, `no` | Text boolean |
|
113
|
+
| `on`, `off` | Toggle boolean |
|
114
|
+
|
115
|
+
#### Examples
|
116
|
+
|
117
|
+
```bash
|
118
|
+
# Standard boolean
|
119
|
+
GET /api/v1/meetings?recording_enabled_eq=true
|
120
|
+
GET /api/v1/meetings?ai_research_enabled_eq=false
|
121
|
+
|
122
|
+
# Numeric boolean
|
123
|
+
GET /api/v1/meetings?auto_agenda_eq=1
|
124
|
+
GET /api/v1/meetings?follow_up_enabled_eq=0
|
125
|
+
|
126
|
+
# Text boolean
|
127
|
+
GET /api/v1/meetings?transcription_enabled_eq=yes
|
128
|
+
GET /api/v1/meetings?auto_presentation_eq=no
|
129
|
+
```
|
130
|
+
|
131
|
+
### 4. DateTime Fields
|
132
|
+
|
133
|
+
DateTime fields support temporal filtering with various operators.
|
134
|
+
|
135
|
+
#### Supported Operators
|
136
|
+
|
137
|
+
| Operator | Description | Example |
|
138
|
+
|----------|-------------|---------|
|
139
|
+
| `_before` | Before datetime | `start_time_before=2024-12-31T23:59:59Z` |
|
140
|
+
| `_after` | After datetime | `start_time_after=2024-01-01T00:00:00Z` |
|
141
|
+
| `_year` | Specific year | `start_time_year=2024` |
|
142
|
+
| `_month` | Specific month | `start_time_month=6` |
|
143
|
+
| `_day` | Specific day | `start_time_day=15` |
|
144
|
+
| `_date` | Specific date | `start_time_date=2024-06-15` |
|
145
|
+
|
146
|
+
#### Supported DateTime Formats
|
147
|
+
|
148
|
+
| Format | Example | Description |
|
149
|
+
|--------|---------|-------------|
|
150
|
+
| ISO 8601 | `2024-06-15T14:30:00Z` | Full datetime with timezone |
|
151
|
+
| Date only | `2024-06-15` | Date without time |
|
152
|
+
| Local format | `2024-06-15 14:30:00` | Local datetime format |
|
153
|
+
| Array format | `[2024, 6, 15]` | Year, month, day array |
|
154
|
+
|
155
|
+
#### Examples
|
156
|
+
|
157
|
+
```bash
|
158
|
+
# Before specific datetime
|
159
|
+
GET /api/v1/meetings?start_time_before=2024-12-31T23:59:59Z
|
160
|
+
|
161
|
+
# After specific datetime
|
162
|
+
GET /api/v1/meetings?start_time_after=2024-01-01T00:00:00Z
|
163
|
+
|
164
|
+
# Specific year
|
165
|
+
GET /api/v1/meetings?start_time_year=2024
|
166
|
+
|
167
|
+
# Specific month
|
168
|
+
GET /api/v1/meetings?start_time_month=6
|
169
|
+
|
170
|
+
# Specific day
|
171
|
+
GET /api/v1/meetings?start_time_day=15
|
172
|
+
|
173
|
+
# Specific date
|
174
|
+
GET /api/v1/meetings?start_time_date=2024-06-15
|
175
|
+
|
176
|
+
# Expiration filtering
|
177
|
+
GET /api/v1/rooms?expiration_date_after=2024-12-31T23:59:59Z
|
178
|
+
```
|
179
|
+
|
180
|
+
### 5. Date Fields
|
181
|
+
|
182
|
+
Date fields support date-specific filtering (without time components).
|
183
|
+
|
184
|
+
#### Supported Operators
|
185
|
+
|
186
|
+
Same as DateTime fields, but optimized for date-only operations.
|
187
|
+
|
188
|
+
#### Examples
|
189
|
+
|
190
|
+
```bash
|
191
|
+
# Date range
|
192
|
+
GET /api/v1/events?event_date_after=2024-01-01&event_date_before=2024-12-31
|
193
|
+
|
194
|
+
# Specific year
|
195
|
+
GET /api/v1/events?event_date_year=2024
|
196
|
+
|
197
|
+
# Specific month
|
198
|
+
GET /api/v1/events?event_date_month=6
|
199
|
+
```
|
200
|
+
|
201
|
+
### 6. Time Fields
|
202
|
+
|
203
|
+
Time fields support time-of-day filtering.
|
204
|
+
|
205
|
+
#### Supported Operators
|
206
|
+
|
207
|
+
Same as DateTime fields, but focused on time components.
|
208
|
+
|
209
|
+
#### Examples
|
210
|
+
|
211
|
+
```bash
|
212
|
+
# Time range
|
213
|
+
GET /api/v1/schedules?start_time_after=09:00:00&end_time_before=17:00:00
|
214
|
+
|
215
|
+
# Specific hour
|
216
|
+
GET /api/v1/schedules?start_time_hour=14
|
217
|
+
```
|
218
|
+
|
219
|
+
## Sorting
|
220
|
+
|
221
|
+
All resources support sorting by any filterable field.
|
222
|
+
|
223
|
+
### Sorting Syntax
|
224
|
+
|
225
|
+
| Format | Description | Example |
|
226
|
+
|--------|-------------|---------|
|
227
|
+
| `order_by=field` | Ascending order | `order_by=title` |
|
228
|
+
| `order_by=-field` | Descending order | `order_by=-created_at` |
|
229
|
+
|
230
|
+
### Examples
|
231
|
+
|
232
|
+
```bash
|
233
|
+
# Sort by title ascending
|
234
|
+
GET /api/v1/meetings?order_by=title
|
235
|
+
|
236
|
+
# Sort by start time descending
|
237
|
+
GET /api/v1/meetings?order_by=-start_time
|
238
|
+
|
239
|
+
# Sort by multiple fields (if supported)
|
240
|
+
GET /api/v1/meetings?order_by=status,start_time
|
241
|
+
```
|
242
|
+
|
243
|
+
## Pagination
|
244
|
+
|
245
|
+
All list endpoints support pagination parameters.
|
246
|
+
|
247
|
+
### Pagination Parameters
|
248
|
+
|
249
|
+
| Parameter | Description | Example |
|
250
|
+
|-----------|-------------|---------|
|
251
|
+
| `page` | Page number (1-based) | `page=2` |
|
252
|
+
| `limit` | Records per page | `limit=10` |
|
253
|
+
| `per_page` | Alias for limit | `per_page=25` |
|
254
|
+
|
255
|
+
### Examples
|
256
|
+
|
257
|
+
```bash
|
258
|
+
# First page with 10 records
|
259
|
+
GET /api/v1/meetings?page=1&limit=10
|
260
|
+
|
261
|
+
# Second page with 25 records
|
262
|
+
GET /api/v1/meetings?page=2&per_page=25
|
263
|
+
|
264
|
+
# Large page size
|
265
|
+
GET /api/v1/meetings?limit=100
|
266
|
+
```
|
267
|
+
|
268
|
+
## Complex Query Examples
|
269
|
+
|
270
|
+
### Multi-Parameter Filtering
|
271
|
+
|
272
|
+
```bash
|
273
|
+
# Find large meetings with recording enabled, starting after June 1st
|
274
|
+
GET /api/v1/meetings?max_participants_gte=50&recording_enabled_eq=true&start_time_after=2024-06-01T00:00:00Z
|
275
|
+
|
276
|
+
# Find project meetings in 2024, sorted by start time
|
277
|
+
GET /api/v1/meetings?title_contains=Project&start_time_year=2024&order_by=start_time
|
278
|
+
|
279
|
+
# Find meetings in specific room range with pagination
|
280
|
+
GET /api/v1/meetings?room_id_range=1,5&page=1&limit=20
|
281
|
+
```
|
282
|
+
|
283
|
+
### Organization Filtering
|
284
|
+
|
285
|
+
```bash
|
286
|
+
# Find organizations with names starting with "Acme"
|
287
|
+
GET /api/v1/organizations?name_starts_with=Acme
|
288
|
+
|
289
|
+
# Find organizations with specific names
|
290
|
+
GET /api/v1/organizations?name_in=Acme Corporation,Tech Corp
|
291
|
+
```
|
292
|
+
|
293
|
+
### Action Item Report Filtering
|
294
|
+
|
295
|
+
```bash
|
296
|
+
# Find reports due before end of year with specific status
|
297
|
+
GET /api/v1/action_item_reports?follow_up_date_before=2024-12-31T23:59:59Z&status_in=active,pending
|
298
|
+
|
299
|
+
# Find reports from specific year and month
|
300
|
+
GET /api/v1/action_item_reports?follow_up_date_year=2024&follow_up_date_month=6
|
301
|
+
```
|
302
|
+
|
303
|
+
### Room Availability
|
304
|
+
|
305
|
+
```bash
|
306
|
+
# Find available rooms with sufficient capacity
|
307
|
+
GET /api/v1/rooms?expiration_date_after=2024-12-31T23:59:59Z&max_capacity_gte=50&order_by=max_capacity
|
308
|
+
```
|
309
|
+
|
310
|
+
## Response Format
|
311
|
+
|
312
|
+
All filtered responses follow this structure:
|
313
|
+
|
314
|
+
```json
|
315
|
+
{
|
316
|
+
"data": [
|
317
|
+
{
|
318
|
+
"id": 1,
|
319
|
+
"title": "Meeting Title",
|
320
|
+
"start_time": "2024-06-15T14:30:00Z",
|
321
|
+
"max_participants": 50,
|
322
|
+
"recording_enabled": true,
|
323
|
+
// ... other fields based on facet configuration
|
324
|
+
}
|
325
|
+
],
|
326
|
+
"pagination": {
|
327
|
+
"current_page": 1,
|
328
|
+
"per_page": 10,
|
329
|
+
"total_pages": 5,
|
330
|
+
"total_count": 50,
|
331
|
+
"next_page": 2,
|
332
|
+
"prev_page": null
|
333
|
+
}
|
334
|
+
}
|
335
|
+
```
|
336
|
+
|
337
|
+
## Error Handling
|
338
|
+
|
339
|
+
### Common Error Responses
|
340
|
+
|
341
|
+
#### 400 Bad Request
|
342
|
+
```json
|
343
|
+
{
|
344
|
+
"error": "Invalid filter parameter",
|
345
|
+
"message": "Invalid datetime format for start_time_before",
|
346
|
+
"code": "INVALID_FILTER"
|
347
|
+
}
|
348
|
+
```
|
349
|
+
|
350
|
+
#### 401 Unauthorized
|
351
|
+
```json
|
352
|
+
{
|
353
|
+
"error": "Authentication required",
|
354
|
+
"message": "Valid JWT token must be provided",
|
355
|
+
"code": "MISSING_AUTH_TOKEN"
|
356
|
+
}
|
357
|
+
```
|
358
|
+
|
359
|
+
#### 403 Forbidden
|
360
|
+
```json
|
361
|
+
{
|
362
|
+
"error": "Organization context required",
|
363
|
+
"message": "Valid organization_id must be provided in JWT token",
|
364
|
+
"code": "MISSING_ORGANIZATION_CONTEXT"
|
365
|
+
}
|
366
|
+
```
|
367
|
+
|
368
|
+
## Testing Tips
|
369
|
+
|
370
|
+
### 1. Start Simple
|
371
|
+
Begin with single parameter tests to verify basic functionality.
|
372
|
+
|
373
|
+
### 2. Combine Gradually
|
374
|
+
Add multiple parameters to test complex filtering scenarios.
|
375
|
+
|
376
|
+
### 3. Test Edge Cases
|
377
|
+
- Invalid dates: `start_time_before=invalid-date`
|
378
|
+
- Empty strings: `title_eq=`
|
379
|
+
- Special characters: `title_contains=Project%20Meeting`
|
380
|
+
- Large numbers: `max_participants_gt=999999`
|
381
|
+
|
382
|
+
### 4. Verify Sorting
|
383
|
+
Test both ascending and descending order for each sortable field.
|
384
|
+
|
385
|
+
### 5. Check Pagination
|
386
|
+
Test different page sizes and verify pagination metadata.
|
387
|
+
|
388
|
+
### 6. Test Boolean Variations
|
389
|
+
Try different boolean value formats: `true`, `1`, `yes`, `on`
|
390
|
+
|
391
|
+
## Performance Considerations
|
392
|
+
|
393
|
+
### 1. Use Indexed Fields
|
394
|
+
Filtering on indexed fields (like `id`, `organization_id`) is faster than unindexed fields.
|
395
|
+
|
396
|
+
### 2. Limit Result Sets
|
397
|
+
Use pagination to limit large result sets and improve response times.
|
398
|
+
|
399
|
+
### 3. Combine Filters Efficiently
|
400
|
+
Multiple filters are combined with AND logic, so more specific filters reduce the result set faster.
|
401
|
+
|
402
|
+
### 4. Avoid Wildcard Searches
|
403
|
+
`_contains` operations are slower than exact matches (`_eq`) or prefix matches (`_starts_with`).
|
404
|
+
|
405
|
+
## Security Notes
|
406
|
+
|
407
|
+
### 1. Input Validation
|
408
|
+
All filter parameters are validated against allowed field names and operators.
|
409
|
+
|
410
|
+
### 2. SQL Injection Protection
|
411
|
+
All parameters are properly escaped and parameterized to prevent SQL injection.
|
412
|
+
|
413
|
+
### 3. Multi-tenancy
|
414
|
+
All queries are automatically scoped to the user's organization context.
|
415
|
+
|
416
|
+
### 4. Sensitive Field Filtering
|
417
|
+
Sensitive fields (passwords, tokens, etc.) are automatically excluded from filtering.
|
418
|
+
|
419
|
+
## Troubleshooting
|
420
|
+
|
421
|
+
### Common Issues
|
422
|
+
|
423
|
+
#### No Results Returned
|
424
|
+
- Check if the field name is correct
|
425
|
+
- Verify the operator is supported for that field type
|
426
|
+
- Ensure the value format matches the expected type
|
427
|
+
|
428
|
+
#### Invalid Filter Error
|
429
|
+
- Verify the field name exists on the model
|
430
|
+
- Check that the operator is supported for the field type
|
431
|
+
- Ensure the value can be parsed correctly
|
432
|
+
|
433
|
+
#### Authentication Errors
|
434
|
+
- Verify the JWT token is valid and not expired
|
435
|
+
- Check that the organization context is properly set
|
436
|
+
- Ensure the user has access to the requested resource
|
437
|
+
|
438
|
+
#### Performance Issues
|
439
|
+
- Use more specific filters to reduce result sets
|
440
|
+
- Add database indexes for frequently filtered fields
|
441
|
+
- Consider using pagination for large datasets
|
442
|
+
|
443
|
+
## API Endpoints
|
444
|
+
|
445
|
+
### Available Resources
|
446
|
+
|
447
|
+
| Resource | Endpoint | Description |
|
448
|
+
|----------|----------|-------------|
|
449
|
+
| Meetings | `/api/v1/meetings` | Meeting management |
|
450
|
+
| Organizations | `/api/v1/organizations` | Organization data |
|
451
|
+
| Users | `/api/v1/users` | User management |
|
452
|
+
| Rooms | `/api/v1/rooms` | Room management |
|
453
|
+
| Action Item Reports | `/api/v1/action_item_reports` | Action item tracking |
|
454
|
+
| Meeting Links | `/api/v1/meeting_links` | Meeting link management |
|
455
|
+
| Dossiers | `/api/v1/dossiers` | Document management |
|
456
|
+
|
457
|
+
### Field Reference
|
458
|
+
|
459
|
+
Each resource has different available fields for filtering. Check the individual resource documentation for the complete list of filterable fields.
|
460
|
+
|
461
|
+
## Changelog
|
462
|
+
|
463
|
+
### Version 0.3.2
|
464
|
+
- Added comprehensive datetime filtering support
|
465
|
+
- Implemented database-agnostic datetime parsing
|
466
|
+
- Added boolean field filtering with multiple value formats
|
467
|
+
- Enhanced string filtering with pattern matching
|
468
|
+
- Added range filtering for numeric fields
|
469
|
+
- Implemented multi-tenancy filtering
|
470
|
+
- Added comprehensive error handling and validation
|
data/README.md
CHANGED
@@ -1,6 +1,51 @@
|
|
1
1
|
# PropelApi
|
2
2
|
|
3
|
-
A comprehensive Rails generator that creates complete API resources with models, controllers, tests, and realistic seed data. Supports both PropelFacets (JSON Facet) and Graphiti serialization engines with **fixed route insertion
|
3
|
+
A comprehensive Rails generator that creates complete API resources with models, controllers, tests, and realistic seed data. Supports both PropelFacets (JSON Facet) and Graphiti serialization engines with **fixed route insertion**, proper indentation, and **comprehensive dynamic filtering system**.
|
4
|
+
|
5
|
+
## ๐ NEW in v0.3.3: Dynamic Filtering System
|
6
|
+
|
7
|
+
PropelApi now includes a complete automatic URL query string filtering and scoping system using the `has_scope` gem. This provides powerful, database-agnostic filtering across all data types with zero configuration required.
|
8
|
+
|
9
|
+
### Quick Filtering Examples
|
10
|
+
|
11
|
+
```bash
|
12
|
+
# String filtering
|
13
|
+
GET /api/v1/meetings?title_contains=Project&status_in=active,pending
|
14
|
+
|
15
|
+
# Numeric filtering
|
16
|
+
GET /api/v1/meetings?max_participants_gte=50&max_participants_lte=200
|
17
|
+
|
18
|
+
# Boolean filtering
|
19
|
+
GET /api/v1/meetings?recording_enabled_eq=true&ai_research_enabled_eq=false
|
20
|
+
|
21
|
+
# DateTime filtering
|
22
|
+
GET /api/v1/meetings?start_time_after=2024-01-01T00:00:00Z&start_time_before=2024-12-31T23:59:59Z
|
23
|
+
|
24
|
+
# Range filtering
|
25
|
+
GET /api/v1/meetings?max_participants_range=150,350
|
26
|
+
|
27
|
+
# Combined filtering with sorting and pagination
|
28
|
+
GET /api/v1/meetings?title_contains=Project&max_participants_gte=50&order_by=start_time&page=1&limit=20
|
29
|
+
```
|
30
|
+
|
31
|
+
### Supported Filter Operators
|
32
|
+
|
33
|
+
| Data Type | Operators | Examples |
|
34
|
+
|-----------|-----------|----------|
|
35
|
+
| **String** | `_eq`, `_contains`, `_starts_with`, `_ends_with`, `_in` | `name_eq=Acme`, `title_contains=Project` |
|
36
|
+
| **Numeric** | `_eq`, `_gt`, `_lt`, `_gte`, `_lte`, `_range`, `_in` | `max_participants_gte=50`, `price_range=100,500` |
|
37
|
+
| **Boolean** | `_eq` (supports `true`/`false`, `1`/`0`, `yes`/`no`, `on`/`off`) | `recording_enabled_eq=true` |
|
38
|
+
| **DateTime** | `_before`, `_after`, `_year`, `_month`, `_day`, `_date` | `start_time_after=2024-01-01`, `created_at_year=2024` |
|
39
|
+
| **Date** | Same as DateTime | `event_date_after=2024-01-01` |
|
40
|
+
| **Time** | Same as DateTime | `start_time_hour=14` |
|
41
|
+
|
42
|
+
### Automatic Features
|
43
|
+
|
44
|
+
- **Zero Configuration**: Filtering works automatically for all generated resources
|
45
|
+
- **Database Agnostic**: Works with SQLite, PostgreSQL, and MySQL
|
46
|
+
- **Security Built-in**: SQL injection protection and input validation
|
47
|
+
- **Multi-tenancy Ready**: Automatic organization scoping
|
48
|
+
- **Performance Optimized**: Efficient queries with proper indexing support
|
4
49
|
|
5
50
|
## Installation
|
6
51
|
|