Skip to main content

reinhardt_views/viewsets/handler/
model_view_set_handler.rs

1//! `ModelViewSetHandler` — Django REST Framework-style CRUD handler.
2//!
3//! Provides the standard list/retrieve/create/update/destroy actions with
4//! permission checks, optional pagination, and serialization for `Model`
5//! types. The response rendering for each action lives next to the action
6//! itself in this module.
7
8use super::error::ViewError;
9use reinhardt_auth::{Permission, PermissionContext};
10use reinhardt_db::orm::model::filter_value_from_field_type;
11use reinhardt_db::orm::{
12	CustomManager, Filter, FilterCondition, FilterOperator, FilterValue, Model, QuerySet,
13	query_types::DbBackend,
14};
15use reinhardt_http::{AuthState, Request, Response};
16use reinhardt_rest::filters::FilterBackend;
17use reinhardt_rest::serializers::{ModelSerializer, Serializer};
18use serde::Serialize;
19use serde::de::DeserializeOwned;
20use std::marker::PhantomData;
21use std::sync::Arc;
22
23type QuerysetFn =
24	dyn Fn(&Request) -> std::result::Result<FilterCondition, ViewError> + Send + Sync + 'static;
25
26fn map_scope_field<T: Model>(field_name: &mut String) {
27	if let Some((prefix, name)) = field_name.rsplit_once('.') {
28		let mut mapped_name = name.to_owned();
29		map_scope_field::<T>(&mut mapped_name);
30		*field_name = format!("{prefix}.{mapped_name}");
31		return;
32	}
33
34	if let Some(field) = T::field_metadata()
35		.into_iter()
36		.find(|field| field.name == *field_name)
37	{
38		*field_name = field.db_column_name().to_owned();
39	}
40}
41
42fn map_scope_subquery_field<T: Model>(field_name: &mut String) {
43	map_scope_field::<T>(field_name);
44}
45
46fn map_scope_expression_sql<T: Model>(sql: &str) -> String {
47	let fields = T::field_metadata();
48	let bytes = sql.as_bytes();
49	let mut mapped = String::with_capacity(sql.len());
50	let mut index = 0;
51	while index < bytes.len() {
52		let quote = bytes[index] as char;
53		if matches!(quote, '"' | '`') {
54			let identifier_start = index + 1;
55			let mut cursor = identifier_start;
56			while cursor < bytes.len() {
57				if bytes[cursor] as char == quote {
58					if bytes.get(cursor + 1).map(|byte| *byte as char) == Some(quote) {
59						cursor += 2;
60						continue;
61					}
62					break;
63				}
64				cursor += 1;
65			}
66			if cursor < bytes.len() {
67				let identifier = &sql[identifier_start..cursor];
68				let replacement = fields
69					.iter()
70					.find(|field| field.name == identifier)
71					.map(|field| field.db_column_name())
72					.unwrap_or(identifier);
73				mapped.push(quote);
74				mapped.push_str(replacement);
75				mapped.push(quote);
76				index = cursor + 1;
77				continue;
78			}
79		}
80
81		let character = sql[index..]
82			.chars()
83			.next()
84			.expect("index is within the expression");
85		mapped.push(character);
86		index += character.len_utf8();
87	}
88	mapped
89}
90
91fn map_scope_query_condition<T: Model>(condition: &mut reinhardt_db::orm::expressions::Q) {
92	use reinhardt_db::orm::expressions::Q;
93
94	match condition {
95		Q::Condition { field, .. } => map_scope_field::<T>(field),
96		Q::Combined { conditions, .. } => {
97			for condition in conditions {
98				map_scope_query_condition::<T>(condition);
99			}
100		}
101	}
102}
103
104fn map_scope_annotation_value<T: Model>(
105	value: &mut reinhardt_db::orm::annotation::AnnotationValue,
106) {
107	use reinhardt_db::orm::annotation::AnnotationValue;
108
109	match value {
110		AnnotationValue::Field(field) => map_scope_field::<T>(&mut field.field),
111		AnnotationValue::Aggregate(aggregate) => {
112			if let Some(field) = &mut aggregate.field {
113				map_scope_field::<T>(field);
114			}
115		}
116		AnnotationValue::Expression(expression) => map_scope_annotation_expression::<T>(expression),
117		AnnotationValue::ArrayAgg(value) => value.map_fields(map_scope_order_by_field::<T>),
118		AnnotationValue::StringAgg(value) => value.map_fields(map_scope_order_by_field::<T>),
119		AnnotationValue::JsonbAgg(value) => value.map_fields(map_scope_order_by_field::<T>),
120		AnnotationValue::JsonbBuildObject(value) => {
121			value.map_fields(map_scope_field::<T>);
122		}
123		AnnotationValue::TsRank(value) => value.map_fields(map_scope_field::<T>),
124		AnnotationValue::Value(_) | AnnotationValue::Subquery(_) => {}
125	}
126}
127
128fn map_scope_annotation_expression<T: Model>(
129	expression: &mut reinhardt_db::orm::annotation::Expression,
130) {
131	use reinhardt_db::orm::annotation::Expression;
132
133	match expression {
134		Expression::Add(left, right)
135		| Expression::Subtract(left, right)
136		| Expression::Multiply(left, right)
137		| Expression::Divide(left, right) => {
138			map_scope_annotation_value::<T>(left);
139			map_scope_annotation_value::<T>(right);
140		}
141		Expression::Case { whens, default } => {
142			for when in whens {
143				map_scope_query_condition::<T>(&mut when.condition);
144				map_scope_annotation_value::<T>(&mut when.then);
145			}
146			if let Some(default) = default {
147				map_scope_annotation_value::<T>(default);
148			}
149		}
150		Expression::Coalesce(values) => {
151			for value in values {
152				map_scope_annotation_value::<T>(value);
153			}
154		}
155	}
156}
157
158fn map_scope_filter_value<T: Model>(value: &mut FilterValue) {
159	match value {
160		FilterValue::FieldRef(field) => map_scope_field::<T>(&mut field.field),
161		FilterValue::OuterRef(field) => map_scope_field::<T>(&mut field.field),
162		FilterValue::Expression(expression) => map_scope_annotation_expression::<T>(expression),
163		FilterValue::List(values) => {
164			for value in values {
165				map_scope_filter_value::<T>(value);
166			}
167		}
168		FilterValue::Range(start, end) => {
169			map_scope_filter_value::<T>(start);
170			map_scope_filter_value::<T>(end);
171		}
172		FilterValue::String(_)
173		| FilterValue::Timestamp(_)
174		| FilterValue::Date(_)
175		| FilterValue::Time(_)
176		| FilterValue::NaiveDateTime(_)
177		| FilterValue::Decimal(_)
178		| FilterValue::Uuid(_)
179		| FilterValue::Integer(_)
180		| FilterValue::Int(_)
181		| FilterValue::Float(_)
182		| FilterValue::Boolean(_)
183		| FilterValue::Bool(_)
184		| FilterValue::Null
185		| FilterValue::Array(_) => {}
186	}
187}
188
189fn map_scope_filter_column<T: Model>(filter: &mut Filter) {
190	filter.map_expression_source(map_scope_expression_sql::<T>);
191	map_scope_field::<T>(&mut filter.field);
192	map_scope_filter_value::<T>(&mut filter.value);
193}
194
195fn map_scope_filter_columns<T: Model>(condition: &mut FilterCondition) {
196	match condition {
197		FilterCondition::Single(filter) => map_scope_filter_column::<T>(filter),
198		FilterCondition::And(conditions) | FilterCondition::Or(conditions) => {
199			for condition in conditions {
200				map_scope_filter_columns::<T>(condition);
201			}
202		}
203		FilterCondition::Not(condition) => map_scope_filter_columns::<T>(condition),
204	}
205}
206
207fn scope_annotation_value_contains_opaque_subquery(
208	value: &reinhardt_db::orm::annotation::AnnotationValue,
209) -> bool {
210	use reinhardt_db::orm::annotation::AnnotationValue;
211
212	match value {
213		AnnotationValue::Subquery(_) => true,
214		AnnotationValue::Expression(expression) => {
215			scope_annotation_expression_contains_opaque_subquery(expression)
216		}
217		AnnotationValue::Value(_)
218		| AnnotationValue::Field(_)
219		| AnnotationValue::Aggregate(_)
220		| AnnotationValue::ArrayAgg(_)
221		| AnnotationValue::StringAgg(_)
222		| AnnotationValue::JsonbAgg(_)
223		| AnnotationValue::JsonbBuildObject(_)
224		| AnnotationValue::TsRank(_) => false,
225	}
226}
227
228fn scope_annotation_expression_contains_opaque_subquery(
229	expression: &reinhardt_db::orm::annotation::Expression,
230) -> bool {
231	use reinhardt_db::orm::annotation::Expression;
232
233	match expression {
234		Expression::Add(left, right)
235		| Expression::Subtract(left, right)
236		| Expression::Multiply(left, right)
237		| Expression::Divide(left, right) => {
238			scope_annotation_value_contains_opaque_subquery(left)
239				|| scope_annotation_value_contains_opaque_subquery(right)
240		}
241		Expression::Case { whens, default } => {
242			whens
243				.iter()
244				.any(|when| scope_annotation_value_contains_opaque_subquery(&when.then))
245				|| default
246					.as_deref()
247					.is_some_and(scope_annotation_value_contains_opaque_subquery)
248		}
249		Expression::Coalesce(values) => values
250			.iter()
251			.any(scope_annotation_value_contains_opaque_subquery),
252	}
253}
254
255fn scope_filter_value_contains_opaque_subquery(value: &FilterValue) -> bool {
256	match value {
257		FilterValue::Expression(expression) => {
258			scope_annotation_expression_contains_opaque_subquery(expression)
259		}
260		FilterValue::List(values) => values
261			.iter()
262			.any(scope_filter_value_contains_opaque_subquery),
263		FilterValue::Range(start, end) => {
264			scope_filter_value_contains_opaque_subquery(start)
265				|| scope_filter_value_contains_opaque_subquery(end)
266		}
267		_ => false,
268	}
269}
270
271fn scope_filter_condition_contains_opaque_subquery(condition: &FilterCondition) -> bool {
272	match condition {
273		FilterCondition::Single(filter) => {
274			scope_filter_value_contains_opaque_subquery(&filter.value)
275		}
276		FilterCondition::And(conditions) | FilterCondition::Or(conditions) => conditions
277			.iter()
278			.any(scope_filter_condition_contains_opaque_subquery),
279		FilterCondition::Not(condition) => {
280			scope_filter_condition_contains_opaque_subquery(condition)
281		}
282	}
283}
284
285fn collect_scope_annotation_value(
286	value: &reinhardt_db::orm::annotation::AnnotationValue,
287	fields: &mut Vec<String>,
288) {
289	use reinhardt_db::orm::annotation::{AnnotationValue, Expression};
290
291	match value {
292		AnnotationValue::Field(field) => fields.push(field.field.clone()),
293		AnnotationValue::Aggregate(aggregate) => {
294			if let Some(field) = &aggregate.field {
295				fields.push(field.clone());
296			}
297		}
298		AnnotationValue::Expression(expression) => match expression {
299			Expression::Add(left, right)
300			| Expression::Subtract(left, right)
301			| Expression::Multiply(left, right)
302			| Expression::Divide(left, right) => {
303				collect_scope_annotation_value(left, fields);
304				collect_scope_annotation_value(right, fields);
305			}
306			Expression::Case { whens, default } => {
307				for when in whens {
308					collect_scope_query_condition(&when.condition, fields);
309					collect_scope_annotation_value(&when.then, fields);
310				}
311				if let Some(default) = default {
312					collect_scope_annotation_value(default, fields);
313				}
314			}
315			Expression::Coalesce(values) => {
316				for value in values {
317					collect_scope_annotation_value(value, fields);
318				}
319			}
320		},
321		AnnotationValue::ArrayAgg(value) => {
322			let mut value = value.clone();
323			value.map_fields(|field| collect_scope_order_by_field(field, fields));
324		}
325		AnnotationValue::StringAgg(value) => {
326			let mut value = value.clone();
327			value.map_fields(|field| collect_scope_order_by_field(field, fields));
328		}
329		AnnotationValue::JsonbAgg(value) => {
330			let mut value = value.clone();
331			value.map_fields(|field| collect_scope_order_by_field(field, fields));
332		}
333		AnnotationValue::JsonbBuildObject(value) => {
334			let mut value = value.clone();
335			value.map_fields(|field| fields.push(field.clone()));
336		}
337		AnnotationValue::TsRank(value) => {
338			let mut value = value.clone();
339			value.map_fields(|field| fields.push(field.clone()));
340		}
341		AnnotationValue::Value(_) | AnnotationValue::Subquery(_) => {}
342	}
343}
344
345fn collect_scope_query_condition(
346	condition: &reinhardt_db::orm::expressions::Q,
347	fields: &mut Vec<String>,
348) {
349	use reinhardt_db::orm::expressions::Q;
350
351	match condition {
352		Q::Condition { field, .. } => fields.push(field.clone()),
353		Q::Combined { conditions, .. } => {
354			for condition in conditions {
355				collect_scope_query_condition(condition, fields);
356			}
357		}
358	}
359}
360
361fn collect_scope_filter_value(value: &FilterValue, fields: &mut Vec<String>) {
362	match value {
363		FilterValue::FieldRef(field) => fields.push(field.field.clone()),
364		FilterValue::OuterRef(field) => fields.push(field.field.clone()),
365		FilterValue::Expression(expression) => {
366			collect_scope_annotation_expression(expression, fields);
367		}
368		FilterValue::List(values) => {
369			for value in values {
370				collect_scope_filter_value(value, fields);
371			}
372		}
373		FilterValue::Range(start, end) => {
374			collect_scope_filter_value(start, fields);
375			collect_scope_filter_value(end, fields);
376		}
377		FilterValue::String(_)
378		| FilterValue::Timestamp(_)
379		| FilterValue::Date(_)
380		| FilterValue::Time(_)
381		| FilterValue::NaiveDateTime(_)
382		| FilterValue::Decimal(_)
383		| FilterValue::Uuid(_)
384		| FilterValue::Integer(_)
385		| FilterValue::Int(_)
386		| FilterValue::Float(_)
387		| FilterValue::Boolean(_)
388		| FilterValue::Bool(_)
389		| FilterValue::Null
390		| FilterValue::Array(_) => {}
391	}
392}
393
394fn collect_scope_annotation_expression(
395	expression: &reinhardt_db::orm::annotation::Expression,
396	fields: &mut Vec<String>,
397) {
398	use reinhardt_db::orm::annotation::Expression;
399
400	match expression {
401		Expression::Add(left, right)
402		| Expression::Subtract(left, right)
403		| Expression::Multiply(left, right)
404		| Expression::Divide(left, right) => {
405			collect_scope_annotation_value(left, fields);
406			collect_scope_annotation_value(right, fields);
407		}
408		Expression::Case { whens, default } => {
409			for when in whens {
410				collect_scope_query_condition(&when.condition, fields);
411				collect_scope_annotation_value(&when.then, fields);
412			}
413			if let Some(default) = default {
414				collect_scope_annotation_value(default, fields);
415			}
416		}
417		Expression::Coalesce(values) => {
418			for value in values {
419				collect_scope_annotation_value(value, fields);
420			}
421		}
422	}
423}
424
425fn collect_scope_filter_condition(condition: &FilterCondition, fields: &mut Vec<String>) {
426	match condition {
427		FilterCondition::Single(filter) => {
428			fields.push(
429				filter
430					.source_field_name()
431					.unwrap_or(&filter.field)
432					.to_owned(),
433			);
434			collect_scope_filter_value(&filter.value, fields);
435		}
436		FilterCondition::And(conditions) | FilterCondition::Or(conditions) => {
437			for condition in conditions {
438				collect_scope_filter_condition(condition, fields);
439			}
440		}
441		FilterCondition::Not(condition) => collect_scope_filter_condition(condition, fields),
442	}
443}
444
445fn serialized_scope_field<'a>(
446	value: &'a serde_json::Value,
447	field: &reinhardt_db::orm::inspection::FieldInfo,
448) -> Option<&'a serde_json::Value> {
449	value
450		.get(&field.name)
451		.or_else(|| value.get(field.db_column_name()))
452}
453
454fn map_scope_order_by_field<T: Model>(field_name: &mut String) {
455	let descending = field_name.starts_with('-');
456	let order_field = field_name
457		.strip_prefix('-')
458		.unwrap_or(field_name)
459		.to_owned();
460	let Some(separator) = order_field.find(|character: char| character.is_whitespace()) else {
461		map_scope_order_by_name::<T>(
462			field_name,
463			if descending { "-" } else { "" },
464			&order_field,
465			"",
466		);
467		return;
468	};
469	let (logical_name, suffix) = order_field.split_at(separator);
470	map_scope_order_by_name::<T>(
471		field_name,
472		if descending { "-" } else { "" },
473		logical_name,
474		suffix,
475	);
476}
477
478fn map_scope_order_by_name<T: Model>(
479	field_name: &mut String,
480	prefix: &str,
481	qualified_name: &str,
482	suffix: &str,
483) {
484	let (qualifier, logical_name) = qualified_name
485		.rsplit_once('.')
486		.map_or(("", qualified_name), |(qualifier, name)| (qualifier, name));
487	let Some(field) = T::field_metadata()
488		.into_iter()
489		.find(|field| field.name == logical_name)
490	else {
491		return;
492	};
493	let physical_name = field.db_column_name();
494	let mapped_name = if qualifier.is_empty() {
495		physical_name.to_owned()
496	} else {
497		format!("{qualifier}.{physical_name}")
498	};
499	*field_name = format!("{prefix}{mapped_name}{suffix}");
500}
501
502fn collect_scope_order_by_field(field_name: &str, fields: &mut Vec<String>) {
503	let field_name = field_name.strip_prefix('-').unwrap_or(field_name);
504	let field_name = field_name
505		.split_once(|character: char| character.is_whitespace())
506		.map_or(field_name, |(field, _)| field);
507	fields.push(field_name.to_owned());
508}
509
510fn parse_length_prefixed_composite_parts<'a>(
511	inner: &'a str,
512	fields: &[String],
513) -> Option<Vec<&'a str>> {
514	if fields.is_empty() {
515		return None;
516	}
517
518	let mut cursor = inner;
519	let mut parts = Vec::with_capacity(fields.len());
520	for (index, field_name) in fields.iter().enumerate() {
521		let value_start = cursor.strip_prefix(&format!("{field_name}="))?;
522		let length_separator = value_start.find(':')?;
523		let length = value_start[..length_separator].parse::<usize>().ok()?;
524		let content_start = length_separator + 1;
525		let content_end = content_start.checked_add(length)?;
526		let value = value_start.get(content_start..content_end)?;
527		let remainder = value_start.get(content_end..)?;
528
529		if index + 1 == fields.len() {
530			if !remainder.is_empty() {
531				return None;
532			}
533		} else {
534			cursor = remainder.strip_prefix(", ")?;
535		}
536		parts.push(value);
537	}
538
539	Some(parts)
540}
541
542fn parse_legacy_composite_parts<'a, F>(
543	cursor: &'a str,
544	fields: &[String],
545	index: usize,
546	is_valid_part: &F,
547) -> Option<Vec<&'a str>>
548where
549	F: Fn(usize, &str) -> bool,
550{
551	let field_name = fields.get(index)?;
552	let value_start = cursor.strip_prefix(&format!("{field_name}="))?;
553	if index + 1 == fields.len() {
554		return is_valid_part(index, value_start).then(|| vec![value_start]);
555	}
556
557	let delimiter = format!(", {}=", fields[index + 1]);
558	for (position, _) in value_start.match_indices(&delimiter) {
559		let part = &value_start[..position];
560		if !is_valid_part(index, part) {
561			continue;
562		}
563		let next_cursor = &value_start[position + 2..];
564		if let Some(mut tail) =
565			parse_legacy_composite_parts(next_cursor, fields, index + 1, is_valid_part)
566		{
567			tail.insert(0, part);
568			return Some(tail);
569		}
570	}
571
572	None
573}
574
575fn primary_key_filter_for_model<T: Model>(
576	pk: &serde_json::Value,
577) -> std::result::Result<FilterCondition, ViewError> {
578	let pk_string = pk
579		.as_str()
580		.map(str::to_owned)
581		.unwrap_or_else(|| pk.to_string());
582	let pk_string = urlencoding::decode(&pk_string)
583		.map_err(|_| ViewError::NotFound(format!("Object with pk={} not found", pk_string)))?
584		.into_owned();
585	let Some(composite) = T::composite_primary_key() else {
586		let value = T::primary_key_filter_value_from_str(&pk_string)
587			.map_err(|_| ViewError::NotFound(format!("Object with pk={} not found", pk_string)))?;
588		let column = T::field_metadata()
589			.into_iter()
590			.find(|field| field.name == T::primary_key_field())
591			.map(|field| field.db_column_name().to_owned())
592			.unwrap_or_else(|| T::primary_key_field().to_owned());
593		return Ok(Filter::new(column, FilterOperator::Eq, value).into());
594	};
595
596	let inner = pk_string
597		.strip_prefix('(')
598		.and_then(|value| value.strip_suffix(')'))
599		.ok_or_else(|| ViewError::NotFound(format!("Object with pk={} not found", pk_string)))?;
600	let fields = composite.fields();
601	let metadata = T::field_metadata();
602	let is_valid_part = |index: usize, part: &str| {
603		let field_name = &fields[index];
604		match metadata.iter().find(|field| field.name == *field_name) {
605			Some(field) => filter_value_from_field_type(&field.field_type, part).is_ok(),
606			None => true,
607		}
608	};
609	let parts = parse_length_prefixed_composite_parts(inner, fields)
610		.or_else(|| parse_legacy_composite_parts(inner, fields, 0, &is_valid_part));
611	let parts = parts
612		.ok_or_else(|| ViewError::NotFound(format!("Object with pk={} not found", pk_string)))?;
613	let filters = fields
614		.iter()
615		.zip(parts)
616		.map(|(field_name, part)| {
617			let field = metadata.iter().find(|field| field.name == *field_name);
618			let filter_value = field
619				.map(|field| filter_value_from_field_type(&field.field_type, part))
620				.transpose()
621				.map_err(|_| {
622					ViewError::NotFound(format!("Object with pk={} not found", pk_string))
623				})?
624				.unwrap_or_else(|| FilterValue::String(part.to_owned()));
625			let column = field
626				.map(|field| field.db_column_name().to_owned())
627				.unwrap_or_else(|| field_name.clone());
628			Ok(Filter::new(column, FilterOperator::Eq, filter_value))
629		})
630		.collect::<std::result::Result<Vec<_>, _>>()?;
631
632	Ok(FilterCondition::and(
633		filters.into_iter().map(FilterCondition::from).collect(),
634	))
635}
636
637fn lookup_value(value: &serde_json::Value) -> std::result::Result<String, ViewError> {
638	let value = value
639		.as_str()
640		.map(str::to_owned)
641		.unwrap_or_else(|| value.to_string());
642	urlencoding::decode(&value)
643		.map(|value| value.into_owned())
644		.map_err(|_| ViewError::NotFound(format!("Object with lookup={value} not found")))
645}
646
647fn lookup_filter_for_model<T: Model>(
648	lookup_field: Option<&str>,
649	value: &serde_json::Value,
650) -> std::result::Result<FilterCondition, ViewError> {
651	let Some(lookup_field) = lookup_field else {
652		return primary_key_filter_for_model::<T>(value);
653	};
654	if lookup_field == T::primary_key_field() {
655		return primary_key_filter_for_model::<T>(value);
656	}
657
658	let value = lookup_value(value)?;
659	let field = T::field_metadata()
660		.into_iter()
661		.find(|field| field.name == lookup_field);
662	let filter_value = field
663		.as_ref()
664		.map(|field| filter_value_from_field_type(&field.field_type, &value))
665		.transpose()
666		.map_err(|_| ViewError::NotFound(format!("Object with lookup={value} not found")))?
667		.unwrap_or(FilterValue::String(value));
668	let column = field
669		.as_ref()
670		.map(|field| field.db_column_name())
671		.unwrap_or(lookup_field);
672	Ok(Filter::new(column, FilterOperator::Eq, filter_value).into())
673}
674
675fn assigned_primary_key_filter<T: Model>(item: &T) -> Option<FilterCondition> {
676	let metadata = T::field_metadata();
677	if let Some(composite) = T::composite_primary_key() {
678		let values = item.get_composite_pk_values();
679		let filters = composite
680			.fields()
681			.iter()
682			.map(|field_name| {
683				let value = match values.get(field_name)? {
684					reinhardt_db::orm::composite_pk::PkValue::String(value) => {
685						FilterValue::String(value.clone())
686					}
687					reinhardt_db::orm::composite_pk::PkValue::Int(value) => {
688						FilterValue::Integer(*value)
689					}
690					reinhardt_db::orm::composite_pk::PkValue::Uint(value) => {
691						FilterValue::Integer(i64::try_from(*value).ok()?)
692					}
693					reinhardt_db::orm::composite_pk::PkValue::Bool(value) => {
694						FilterValue::Boolean(*value)
695					}
696				};
697				let column = metadata
698					.iter()
699					.find(|field| field.name == *field_name)
700					.map(|field| field.db_column_name().to_owned())
701					.unwrap_or_else(|| field_name.clone());
702				Some(Filter::new(column, FilterOperator::Eq, value).into())
703			})
704			.collect::<Option<Vec<FilterCondition>>>()?;
705		return Some(FilterCondition::and(filters));
706	}
707
708	let column = metadata
709		.iter()
710		.find(|field| field.name == T::primary_key_field())
711		.map(|field| field.db_column_name().to_owned())
712		.unwrap_or_else(|| T::primary_key_field().to_owned());
713	let serialized = serde_json::to_value(item).ok()?;
714	let primary_key_value = serialized
715		.get(T::primary_key_field())
716		.or_else(|| serialized.get(&column))?;
717	let filter = primary_key_filter_for_model::<T>(primary_key_value).ok()?;
718	let FilterCondition::Single(mut filter) = filter else {
719		return None;
720	};
721	filter.field = column;
722	Some(filter.into())
723}
724
725/// Django REST Framework-style ViewSet handler for models.
726///
727/// Provides automatic CRUD operations with permission checks, filtering,
728/// pagination, and serialization for Model types.
729///
730/// # Examples
731///
732/// ```no_run
733/// # use reinhardt_views::viewsets::ModelViewSetHandler;
734/// # use reinhardt_db::orm::Model;
735/// # use serde::{Serialize, Deserialize};
736/// #
737/// # #[derive(Serialize, Deserialize, Clone, Debug)]
738/// # struct User {
739/// #     id: Option<i64>,
740/// #     username: String,
741/// # }
742/// #
743/// # #[derive(Clone)]
744/// # struct UserFields;
745/// #
746/// # impl reinhardt_db::orm::FieldSelector for UserFields {
747/// #     fn with_alias(self, _alias: &str) -> Self { self }
748/// # }
749/// #
750/// # impl Model for User {
751/// #     type PrimaryKey = i64;
752/// #     type Fields = UserFields;
753/// #     type Objects = reinhardt_db::orm::Manager<Self>;
754/// #     fn table_name() -> &'static str { "users" }
755/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
756/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
757/// #     fn new_fields() -> Self::Fields { UserFields }
758/// # }
759/// #
760/// # async fn example() {
761/// let handler = ModelViewSetHandler::<User>::new();
762/// # }
763/// ```
764pub struct ModelViewSetHandler<T>
765where
766	T: Model + Serialize + DeserializeOwned + Clone + Send + Sync + 'static,
767{
768	queryset: Option<Vec<T>>,
769	queryset_fn: Option<Arc<QuerysetFn>>,
770	serializer_class: Option<Arc<dyn Serializer<Input = T, Output = String> + Send + Sync>>,
771	permission_classes: Vec<Arc<dyn Permission>>,
772	filter_backends: Vec<Arc<dyn FilterBackend>>,
773	pagination_class: Option<reinhardt_core::pagination::PaginatorImpl>,
774	pool: Option<Arc<sqlx::AnyPool>>,
775	lookup_field: Option<String>,
776	/// Database backend type (default: PostgreSQL)
777	db_backend: DbBackend,
778	_phantom: PhantomData<T>,
779}
780
781impl<T> ModelViewSetHandler<T>
782where
783	T: Model + Serialize + DeserializeOwned + Clone + Send + Sync + 'static,
784{
785	/// Create a new ModelViewSetHandler
786	///
787	/// # Examples
788	///
789	/// ```
790	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
791	/// # use reinhardt_db::orm::Model;
792	/// # use serde::{Serialize, Deserialize};
793	/// #
794	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
795	/// # struct User {
796	/// #     id: Option<i64>,
797	/// #     username: String,
798	/// # }
799	/// #
800	/// # #[derive(Clone)]
801	/// # struct UserFields;
802	/// #
803	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
804	/// #     fn with_alias(self, _alias: &str) -> Self { self }
805	/// # }
806	/// #
807	/// # impl Model for User {
808	/// #     type PrimaryKey = i64;
809	/// #     type Fields = UserFields;
810	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
811	/// #     fn table_name() -> &'static str { "users" }
812	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
813	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
814	/// #     fn new_fields() -> Self::Fields { UserFields }
815	/// # }
816	/// let handler = ModelViewSetHandler::<User>::new();
817	/// ```
818	pub fn new() -> Self {
819		Self {
820			queryset: None,
821			queryset_fn: None,
822			serializer_class: None,
823			permission_classes: Vec::new(),
824			filter_backends: Vec::new(),
825			pagination_class: None,
826			pool: None,
827			lookup_field: None,
828			db_backend: DbBackend::Postgres, // Default to PostgreSQL
829			_phantom: PhantomData,
830		}
831	}
832
833	/// Set the queryset (in-memory data) for this handler
834	///
835	/// # Examples
836	///
837	/// ```
838	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
839	/// # use reinhardt_db::orm::Model;
840	/// # use serde::{Serialize, Deserialize};
841	/// #
842	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
843	/// # struct User {
844	/// #     id: Option<i64>,
845	/// #     username: String,
846	/// # }
847	/// #
848	/// # #[derive(Clone)]
849	/// # struct UserFields;
850	/// #
851	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
852	/// #     fn with_alias(self, _alias: &str) -> Self { self }
853	/// # }
854	/// #
855	/// # impl Model for User {
856	/// #     type PrimaryKey = i64;
857	/// #     type Fields = UserFields;
858	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
859	/// #     fn table_name() -> &'static str { "users" }
860	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
861	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
862	/// #     fn new_fields() -> Self::Fields { UserFields }
863	/// # }
864	/// let users = vec![
865	///     User { id: Some(1), username: "alice".to_string() },
866	///     User { id: Some(2), username: "bob".to_string() },
867	/// ];
868	/// let handler = ModelViewSetHandler::<User>::new()
869	///     .with_queryset(users);
870	/// ```
871	pub fn with_queryset(mut self, queryset: Vec<T>) -> Self {
872		self.queryset = Some(queryset);
873		self
874	}
875
876	pub(crate) fn with_lookup_field(mut self, lookup_field: String) -> Self {
877		self.lookup_field = Some(lookup_field);
878		self
879	}
880
881	/// Scope database queries using the current request.
882	///
883	/// The synchronous, fallible hook returns one [`FilterCondition`] and requires
884	/// a database pool. It applies to list, retrieve, update, and destroy; create
885	/// deliberately does not call it, so create ownership belongs in the
886	/// serializer, permission layer, or database. Resolve asynchronous scope data
887	/// in middleware before dispatch and read its application-defined identity
888	/// from request extensions in this hook. Static `Vec` data supplied through
889	/// [`Self::with_queryset`] is separate and is never filtered by this hook.
890	/// A scoped-out object or malformed detail lookup value is reported as 404.
891	pub fn with_queryset_fn<F>(mut self, queryset_fn: F) -> Self
892	where
893		F: Fn(&Request) -> std::result::Result<FilterCondition, ViewError> + Send + Sync + 'static,
894	{
895		self.queryset_fn = Some(Arc::new(queryset_fn));
896		self
897	}
898
899	/// Set the serializer class for this handler
900	///
901	/// # Examples
902	///
903	/// ```
904	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
905	/// # use reinhardt_rest::serializers::ModelSerializer;
906	/// # use reinhardt_db::orm::Model;
907	/// # use serde::{Serialize, Deserialize};
908	/// # use std::sync::Arc;
909	/// #
910	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
911	/// # struct User {
912	/// #     id: Option<i64>,
913	/// #     username: String,
914	/// # }
915	/// #
916	/// # #[derive(Clone)]
917	/// # struct UserFields;
918	/// #
919	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
920	/// #     fn with_alias(self, _alias: &str) -> Self { self }
921	/// # }
922	/// #
923	/// # impl Model for User {
924	/// #     type PrimaryKey = i64;
925	/// #     type Fields = UserFields;
926	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
927	/// #     fn table_name() -> &'static str { "users" }
928	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
929	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
930	/// #     fn new_fields() -> Self::Fields { UserFields }
931	/// # }
932	/// let serializer = Arc::new(ModelSerializer::<User>::new());
933	/// let handler = ModelViewSetHandler::<User>::new()
934	///     .with_serializer(serializer);
935	/// ```
936	pub fn with_serializer(
937		mut self,
938		serializer: Arc<dyn Serializer<Input = T, Output = String> + Send + Sync>,
939	) -> Self {
940		self.serializer_class = Some(serializer);
941		self
942	}
943
944	/// Set the database connection pool for this handler
945	///
946	/// # Examples
947	///
948	/// ```no_run
949	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
950	/// # use reinhardt_db::orm::Model;
951	/// # use serde::{Serialize, Deserialize};
952	/// # use sqlx::AnyPool;
953	/// # use std::sync::Arc;
954	/// #
955	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
956	/// # struct User {
957	/// #     id: Option<i64>,
958	/// #     username: String,
959	/// # }
960	/// #
961	/// # #[derive(Clone)]
962	/// # struct UserFields;
963	/// #
964	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
965	/// #     fn with_alias(self, _alias: &str) -> Self { self }
966	/// # }
967	/// #
968	/// # impl Model for User {
969	/// #     type PrimaryKey = i64;
970	/// #     type Fields = UserFields;
971	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
972	/// #     fn table_name() -> &'static str { "users" }
973	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
974	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
975	/// #     fn new_fields() -> Self::Fields { UserFields }
976	/// # }
977	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
978	/// let pool = Arc::new(AnyPool::connect("postgres://localhost/mydb").await?);
979	/// let handler = ModelViewSetHandler::<User>::new()
980	///     .with_pool(pool);
981	/// # Ok(())
982	/// # }
983	/// ```
984	pub fn with_pool(mut self, pool: Arc<sqlx::AnyPool>) -> Self {
985		self.pool = Some(pool);
986		self
987	}
988
989	/// Set the database backend type for this handler
990	///
991	/// # Examples
992	///
993	/// ```
994	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
995	/// # use reinhardt_db::orm::{Model, query_types::DbBackend};
996	/// # use serde::{Serialize, Deserialize};
997	/// #
998	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
999	/// # struct User {
1000	/// #     id: Option<i64>,
1001	/// #     username: String,
1002	/// # }
1003	/// #
1004	/// # #[derive(Clone)]
1005	/// # struct UserFields;
1006	/// #
1007	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1008	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1009	/// # }
1010	/// #
1011	/// # impl Model for User {
1012	/// #     type PrimaryKey = i64;
1013	/// #     type Fields = UserFields;
1014	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1015	/// #     fn table_name() -> &'static str { "users" }
1016	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1017	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1018	/// #     fn new_fields() -> Self::Fields { UserFields }
1019	/// # }
1020	/// let handler = ModelViewSetHandler::<User>::new()
1021	///     .with_db_backend(DbBackend::Sqlite);
1022	/// ```
1023	pub fn with_db_backend(mut self, db_backend: DbBackend) -> Self {
1024		self.db_backend = db_backend;
1025		self
1026	}
1027
1028	/// Add a permission class to this handler
1029	///
1030	/// # Examples
1031	///
1032	/// ```
1033	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1034	/// # use reinhardt_auth::IsAuthenticated;
1035	/// # use reinhardt_db::orm::Model;
1036	/// # use serde::{Serialize, Deserialize};
1037	/// # use std::sync::Arc;
1038	/// #
1039	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1040	/// # struct User {
1041	/// #     id: Option<i64>,
1042	/// #     username: String,
1043	/// # }
1044	/// #
1045	/// # #[derive(Clone)]
1046	/// # struct UserFields;
1047	/// #
1048	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1049	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1050	/// # }
1051	/// #
1052	/// # impl Model for User {
1053	/// #     type PrimaryKey = i64;
1054	/// #     type Fields = UserFields;
1055	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1056	/// #     fn table_name() -> &'static str { "users" }
1057	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1058	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1059	/// #     fn new_fields() -> Self::Fields { UserFields }
1060	/// # }
1061	/// let handler = ModelViewSetHandler::<User>::new()
1062	///     .add_permission(Arc::new(IsAuthenticated));
1063	/// ```
1064	pub fn add_permission(mut self, permission: Arc<dyn Permission>) -> Self {
1065		self.permission_classes.push(permission);
1066		self
1067	}
1068
1069	/// Add a filter backend to this handler
1070	pub fn add_filter_backend(mut self, backend: Arc<dyn FilterBackend>) -> Self {
1071		self.filter_backends.push(backend);
1072		self
1073	}
1074
1075	/// Set the pagination class for this handler
1076	pub fn with_pagination(
1077		mut self,
1078		pagination: reinhardt_core::pagination::PaginatorImpl,
1079	) -> Self {
1080		self.pagination_class = Some(pagination);
1081		self
1082	}
1083
1084	/// Get the queryset for this handler
1085	fn get_queryset(&self) -> &[T] {
1086		self.queryset.as_deref().unwrap_or(&[])
1087	}
1088
1089	fn scoped_queryset(&self, request: &Request) -> std::result::Result<QuerySet<T>, ViewError> {
1090		let mut queryset = T::objects().all().for_model_session();
1091		queryset.map_filter_columns(map_scope_filter_column::<T>);
1092		queryset.map_order_by_fields(map_scope_order_by_field::<T>);
1093		queryset.map_subquery_fields(map_scope_subquery_field::<T>);
1094		match &self.queryset_fn {
1095			Some(queryset_fn) => {
1096				let mut condition = queryset_fn(request)?;
1097				map_scope_filter_columns::<T>(&mut condition);
1098				Ok(queryset.filter(condition))
1099			}
1100			None => Ok(queryset),
1101		}
1102	}
1103
1104	fn ensure_scope_values_unchanged(
1105		&self,
1106		request: &Request,
1107		before: &serde_json::Value,
1108		after: &serde_json::Value,
1109	) -> std::result::Result<(), ViewError> {
1110		let mut field_names = Vec::new();
1111		self.ensure_mutation_scope_supported()?;
1112		let manager_queryset = T::objects().all();
1113		let mut has_opaque_subquery = manager_queryset
1114			.filters()
1115			.iter()
1116			.any(|filter| scope_filter_value_contains_opaque_subquery(&filter.value));
1117		has_opaque_subquery |= manager_queryset
1118			.filter_conditions()
1119			.iter()
1120			.any(scope_filter_condition_contains_opaque_subquery);
1121		for filter in manager_queryset.filters() {
1122			field_names.push(
1123				filter
1124					.source_field_name()
1125					.unwrap_or(&filter.field)
1126					.to_owned(),
1127			);
1128			collect_scope_filter_value(&filter.value, &mut field_names);
1129		}
1130		for condition in manager_queryset.filter_conditions() {
1131			collect_scope_filter_condition(condition, &mut field_names);
1132		}
1133		field_names.extend(manager_queryset.subquery_fields().map(|field| {
1134			field
1135				.rsplit_once('.')
1136				.map_or_else(|| field.to_owned(), |(_, name)| name.to_owned())
1137		}));
1138		if let Some(queryset_fn) = &self.queryset_fn {
1139			let condition = queryset_fn(request)?;
1140			has_opaque_subquery |= scope_filter_condition_contains_opaque_subquery(&condition);
1141			collect_scope_filter_condition(&condition, &mut field_names);
1142		}
1143		if has_opaque_subquery {
1144			return Err(ViewError::Permission(
1145				"opaque scalar subquery scopes cannot be mutated".to_owned(),
1146			));
1147		}
1148		if field_names.is_empty() {
1149			return Ok(());
1150		}
1151		field_names.sort_unstable();
1152		field_names.dedup();
1153
1154		for field_name in field_names {
1155			let field_name = field_name
1156				.rsplit_once('.')
1157				.map_or(field_name.as_str(), |(_, name)| name);
1158			let Some(field) = T::field_metadata()
1159				.into_iter()
1160				.find(|field| field.name == field_name || field.db_column_name() == field_name)
1161			else {
1162				return Err(ViewError::Permission(format!(
1163					"request scope field `{field_name}` is not a model field"
1164				)));
1165			};
1166			if serialized_scope_field(before, &field) != serialized_scope_field(after, &field) {
1167				return Err(ViewError::Permission(format!(
1168					"scope field `{}` cannot be changed",
1169					field.name
1170				)));
1171			}
1172		}
1173
1174		Ok(())
1175	}
1176
1177	fn ensure_mutation_scope_supported(&self) -> std::result::Result<(), ViewError> {
1178		if T::objects().all().has_joins() {
1179			return Err(ViewError::Permission(
1180				"join-backed scopes cannot be mutated".to_owned(),
1181			));
1182		}
1183		Ok(())
1184	}
1185
1186	fn ensure_scope_fields_unchanged(
1187		&self,
1188		request: &Request,
1189		before: &T,
1190		after: &T,
1191	) -> std::result::Result<(), ViewError> {
1192		let before = serde_json::to_value(before).map_err(|error| {
1193			ViewError::Serialization(format!("failed to serialize original scope state: {error}"))
1194		})?;
1195		let after = serde_json::to_value(after).map_err(|error| {
1196			ViewError::Serialization(format!("failed to serialize updated scope state: {error}"))
1197		})?;
1198		self.ensure_scope_values_unchanged(request, &before, &after)
1199	}
1200
1201	fn primary_key_filter(
1202		pk: &serde_json::Value,
1203	) -> std::result::Result<FilterCondition, ViewError> {
1204		primary_key_filter_for_model::<T>(pk)
1205	}
1206
1207	fn lookup_filter(
1208		&self,
1209		value: &serde_json::Value,
1210	) -> std::result::Result<FilterCondition, ViewError> {
1211		lookup_filter_for_model::<T>(self.lookup_field.as_deref(), value)
1212	}
1213
1214	fn matches_lookup(&self, item: &T, value: &serde_json::Value) -> bool {
1215		let Some(lookup_field) = self.lookup_field.as_deref() else {
1216			let value = value.to_string();
1217			return item
1218				.primary_key()
1219				.is_some_and(|primary_key| primary_key.to_string() == value.trim_matches('"'));
1220		};
1221		let Ok(value) = lookup_value(value) else {
1222			return false;
1223		};
1224		serde_json::to_value(item)
1225			.ok()
1226			.and_then(|item| item.get(lookup_field).cloned())
1227			.is_some_and(|field_value| match field_value {
1228				serde_json::Value::String(field_value) => field_value == value,
1229				serde_json::Value::Number(field_value) => field_value.to_string() == value,
1230				serde_json::Value::Bool(field_value) => field_value.to_string() == value,
1231				_ => false,
1232			})
1233	}
1234
1235	async fn get_object(
1236		&self,
1237		request: &Request,
1238		pk: &serde_json::Value,
1239	) -> std::result::Result<T, ViewError> {
1240		let pool = self.pool.as_ref().ok_or_else(|| {
1241			ViewError::Internal("with_queryset_fn requires a database pool".to_owned())
1242		})?;
1243		let session = reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1244			.await
1245			.map_err(|error| {
1246				ViewError::DatabaseError(format!("Failed to create session: {error}"))
1247			})?;
1248		let queryset = self
1249			.scoped_queryset(request)?
1250			.filter(self.lookup_filter(pk)?)
1251			.without_slicing();
1252		session
1253			.list(&queryset)
1254			.await
1255			.map_err(|error| ViewError::DatabaseError(format!("Failed to query objects: {error}")))?
1256			.into_iter()
1257			.next()
1258			.ok_or_else(|| ViewError::NotFound(format!("Object with pk={pk} not found")))
1259	}
1260
1261	/// Get the serializer for this handler
1262	fn get_serializer(&self) -> Arc<dyn Serializer<Input = T, Output = String> + Send + Sync> {
1263		self.serializer_class
1264			.clone()
1265			.unwrap_or_else(|| Arc::new(ModelSerializer::<T>::new()))
1266	}
1267
1268	/// Check permissions for the request
1269	async fn check_permissions(&self, request: &Request) -> std::result::Result<(), ViewError> {
1270		// Extract authentication information from request extensions
1271		// The session middleware stores authenticated user_id in extensions
1272		//
1273		// Expected usage:
1274		// 1. Session middleware extracts session from cookie/token
1275		// 2. Middleware validates session and extracts user_id
1276		// 3. Middleware stores user_id in request.extensions using a dedicated type
1277		//
1278		// Example middleware implementation:
1279		//   if let Some(user_id) = session.get::<i64>("user_id").ok().flatten() {
1280		//       request.extensions.insert(AuthenticatedUserId(user_id));
1281		//   }
1282
1283		let auth_state = AuthState::from_extensions(&request.extensions);
1284		let is_authenticated = auth_state
1285			.as_ref()
1286			.map(|state| state.is_authenticated())
1287			.unwrap_or(false);
1288		let is_admin = auth_state
1289			.as_ref()
1290			.map(|state| state.is_admin())
1291			.unwrap_or(false);
1292		let is_active = auth_state
1293			.as_ref()
1294			.map(|state| state.is_active())
1295			.unwrap_or(false);
1296		let user_obj = None;
1297
1298		let context = PermissionContext {
1299			request,
1300			is_authenticated,
1301			is_admin,
1302			is_active,
1303			user: user_obj,
1304		};
1305
1306		// Check all registered permission classes
1307		for permission in &self.permission_classes {
1308			if !permission.has_permission(&context).await {
1309				// Permission denied - return specific error
1310				return Err(ViewError::Permission(format!(
1311					"Permission denied by {}",
1312					std::any::type_name_of_val(&**permission)
1313				)));
1314			}
1315		}
1316
1317		Ok(())
1318	}
1319
1320	/// List all objects with optional filtering and pagination
1321	///
1322	/// # Examples
1323	///
1324	/// ```no_run
1325	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1326	/// # use reinhardt_http::Request;
1327	/// # use reinhardt_db::orm::Model;
1328	/// # use serde::{Serialize, Deserialize};
1329	/// # use bytes::Bytes;
1330	/// # use hyper::{Method, Version, HeaderMap};
1331	/// #
1332	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1333	/// # struct User {
1334	/// #     id: Option<i64>,
1335	/// #     username: String,
1336	/// # }
1337	/// #
1338	/// # #[derive(Clone)]
1339	/// # struct UserFields;
1340	/// #
1341	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1342	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1343	/// # }
1344	/// #
1345	/// # impl Model for User {
1346	/// #     type PrimaryKey = i64;
1347	/// #     type Fields = UserFields;
1348	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1349	/// #     fn table_name() -> &'static str { "users" }
1350	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1351	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1352	/// #     fn new_fields() -> Self::Fields { UserFields }
1353	/// # }
1354	/// #
1355	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1356	/// let handler = ModelViewSetHandler::<User>::new();
1357	/// let request = Request::builder()
1358	///     .method(Method::GET)
1359	///     .uri("/users/")
1360	///     .version(Version::HTTP_11)
1361	///     .headers(HeaderMap::new())
1362	///     .body(Bytes::new())
1363	///     .build()?;
1364	/// let response = handler.list(&request).await?;
1365	/// # Ok(())
1366	/// # }
1367	/// ```
1368	pub async fn list(&self, request: &Request) -> std::result::Result<Response, ViewError> {
1369		self.check_permissions(request).await?;
1370
1371		let serializer = self.get_serializer();
1372
1373		let items = if let Some(pool) = &self.pool {
1374			let session = reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1375				.await
1376				.map_err(|error| {
1377					ViewError::DatabaseError(format!("Failed to create session: {error}"))
1378				})?;
1379			let queryset = self.scoped_queryset(request)?;
1380			session.list(&queryset).await.map_err(|error| {
1381				ViewError::DatabaseError(format!("Failed to list objects: {error}"))
1382			})?
1383		} else if self.queryset_fn.is_some() {
1384			return Err(ViewError::Internal(
1385				"with_queryset_fn requires a database pool".to_owned(),
1386			));
1387		} else {
1388			self.get_queryset().to_vec()
1389		};
1390
1391		// Serialize all objects
1392		let mut serialized_items = Vec::new();
1393		for item in &items {
1394			let json = serializer
1395				.serialize(item)
1396				.map_err(|e| ViewError::Serialization(e.to_string()))?;
1397			serialized_items.push(json);
1398		}
1399
1400		// Create response body
1401		let response_body = format!("[{}]", serialized_items.join(","));
1402
1403		Ok(Response::ok().with_body(response_body))
1404	}
1405
1406	/// Retrieve a single object by primary key
1407	///
1408	/// # Examples
1409	///
1410	/// ```no_run
1411	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1412	/// # use reinhardt_http::Request;
1413	/// # use reinhardt_db::orm::Model;
1414	/// # use serde::{Serialize, Deserialize};
1415	/// # use serde_json::Value;
1416	/// # use bytes::Bytes;
1417	/// # use hyper::{Method, Version, HeaderMap};
1418	/// #
1419	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1420	/// # struct User {
1421	/// #     id: Option<i64>,
1422	/// #     username: String,
1423	/// # }
1424	/// #
1425	/// # #[derive(Clone)]
1426	/// # struct UserFields;
1427	/// #
1428	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1429	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1430	/// # }
1431	/// #
1432	/// # impl Model for User {
1433	/// #     type PrimaryKey = i64;
1434	/// #     type Fields = UserFields;
1435	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1436	/// #     fn table_name() -> &'static str { "users" }
1437	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1438	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1439	/// #     fn new_fields() -> Self::Fields { UserFields }
1440	/// # }
1441	/// #
1442	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1443	/// let handler = ModelViewSetHandler::<User>::new();
1444	/// let request = Request::builder()
1445	///     .method(Method::GET)
1446	///     .uri("/users/1/")
1447	///     .version(Version::HTTP_11)
1448	///     .headers(HeaderMap::new())
1449	///     .body(Bytes::new())
1450	///     .build()?;
1451	/// let pk = serde_json::json!(1);
1452	/// let response = handler.retrieve(&request, pk).await?;
1453	/// # Ok(())
1454	/// # }
1455	/// ```
1456	pub async fn retrieve(
1457		&self,
1458		request: &Request,
1459		pk: serde_json::Value,
1460	) -> std::result::Result<Response, ViewError> {
1461		self.check_permissions(request).await?;
1462
1463		let serializer = self.get_serializer();
1464
1465		let item = if self.pool.is_some() {
1466			self.get_object(request, &pk).await?
1467		} else if self.queryset_fn.is_some() {
1468			return Err(ViewError::Internal(
1469				"with_queryset_fn requires a database pool".to_owned(),
1470			));
1471		} else {
1472			let queryset = self.get_queryset();
1473			queryset
1474				.iter()
1475				.find(|item| self.matches_lookup(item, &pk))
1476				.cloned()
1477				.ok_or_else(|| ViewError::NotFound(format!("Object with pk={} not found", pk)))?
1478		};
1479
1480		let json = serializer
1481			.serialize(&item)
1482			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1483
1484		Ok(Response::ok().with_body(json))
1485	}
1486
1487	/// Create a new object
1488	///
1489	/// # Examples
1490	///
1491	/// ```no_run
1492	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1493	/// # use reinhardt_http::Request;
1494	/// # use reinhardt_db::orm::Model;
1495	/// # use serde::{Serialize, Deserialize};
1496	/// # use bytes::Bytes;
1497	/// # use hyper::{Method, Version, HeaderMap};
1498	/// #
1499	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1500	/// # struct User {
1501	/// #     id: Option<i64>,
1502	/// #     username: String,
1503	/// # }
1504	/// #
1505	/// # #[derive(Clone)]
1506	/// # struct UserFields;
1507	/// #
1508	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1509	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1510	/// # }
1511	/// #
1512	/// # impl Model for User {
1513	/// #     type PrimaryKey = i64;
1514	/// #     type Fields = UserFields;
1515	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1516	/// #     fn table_name() -> &'static str { "users" }
1517	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1518	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1519	/// #     fn new_fields() -> Self::Fields { UserFields }
1520	/// # }
1521	/// #
1522	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1523	/// let handler = ModelViewSetHandler::<User>::new();
1524	/// let request = Request::builder()
1525	///     .method(Method::POST)
1526	///     .uri("/users/")
1527	///     .version(Version::HTTP_11)
1528	///     .headers(HeaderMap::new())
1529	///     .body(Bytes::from(r#"{"username":"alice"}"#))
1530	///     .build()?;
1531	/// let response = handler.create(&request).await?;
1532	/// # Ok(())
1533	/// # }
1534	/// ```
1535	pub async fn create(&self, request: &Request) -> std::result::Result<Response, ViewError> {
1536		self.check_permissions(request).await?;
1537
1538		let serializer = self.get_serializer();
1539
1540		// Parse request body
1541		let body_str = String::from_utf8(request.body().to_vec())
1542			.map_err(|e| ViewError::BadRequest(format!("Invalid UTF-8: {}", e)))?;
1543
1544		// Deserialize into model
1545		let item = serializer
1546			.deserialize(&body_str)
1547			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1548
1549		// Save to database if pool is available
1550		if let Some(pool) = &self.pool {
1551			// Create a new session for this request
1552			let mut session = reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1553				.await
1554				.map_err(|e| {
1555					ViewError::DatabaseError(format!("Failed to create session: {}", e))
1556				})?;
1557
1558			// Begin transaction
1559			session.begin().await.map_err(|e| {
1560				ViewError::DatabaseError(format!("Failed to begin transaction: {}", e))
1561			})?;
1562
1563			// Add object to session
1564			session
1565				.add_new(item.clone())
1566				.await
1567				.map_err(|e| ViewError::DatabaseError(format!("Failed to add object: {}", e)))?;
1568
1569			// Flush changes to database (generates and executes INSERT)
1570			session
1571				.flush()
1572				.await
1573				.map_err(|e| ViewError::DatabaseError(format!("Failed to flush: {}", e)))?;
1574
1575			// Get the generated ID from the session
1576			let generated_id = session.get_generated_ids().first().map(|(_, id)| *id);
1577
1578			// Commit transaction
1579			session
1580				.commit()
1581				.await
1582				.map_err(|e| ViewError::DatabaseError(format!("Failed to commit: {}", e)))?;
1583
1584			// Re-fetch the created object from the database to get all auto-populated fields
1585			// (e.g., created_at which is set by database DEFAULT), including when the
1586			// primary key was supplied by the caller.
1587			let refresh_filter = if let Some(id) = generated_id {
1588				Some(Self::primary_key_filter(&serde_json::json!(id))?)
1589			} else {
1590				assigned_primary_key_filter(&item)
1591			};
1592			if let Some(refresh_filter) = refresh_filter {
1593				let fetch_session =
1594					reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1595						.await
1596						.map_err(|e| {
1597							ViewError::DatabaseError(format!("Failed to create session: {}", e))
1598						})?;
1599
1600				let queryset = QuerySet::<T>::new().filter(refresh_filter).limit(1);
1601				let created_item = fetch_session
1602					.list(&queryset)
1603					.await
1604					.map_err(|error| {
1605						ViewError::DatabaseError(format!(
1606							"Failed to refresh created object: {error}"
1607						))
1608					})?
1609					.into_iter()
1610					.next()
1611					.ok_or_else(|| {
1612						ViewError::DatabaseError("Failed to find created object".to_owned())
1613					})?;
1614
1615				// Serialize the complete object (including auto-populated fields)
1616				let response_body = serializer
1617					.serialize(&created_item)
1618					.map_err(|e| ViewError::Serialization(e.to_string()))?;
1619
1620				return Ok(Response::created().with_body(response_body));
1621			}
1622		}
1623
1624		// Fallback: return the original item if no database pool
1625		let response_body = serializer
1626			.serialize(&item)
1627			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1628
1629		Ok(Response::created().with_body(response_body))
1630	}
1631
1632	/// Update an existing object
1633	///
1634	/// # Examples
1635	///
1636	/// ```no_run
1637	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1638	/// # use reinhardt_http::Request;
1639	/// # use reinhardt_db::orm::Model;
1640	/// # use serde::{Serialize, Deserialize};
1641	/// # use serde_json::Value;
1642	/// # use bytes::Bytes;
1643	/// # use hyper::{Method, Version, HeaderMap};
1644	/// #
1645	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1646	/// # struct User {
1647	/// #     id: Option<i64>,
1648	/// #     username: String,
1649	/// # }
1650	/// #
1651	/// # #[derive(Clone)]
1652	/// # struct UserFields;
1653	/// #
1654	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1655	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1656	/// # }
1657	/// #
1658	/// # impl Model for User {
1659	/// #     type PrimaryKey = i64;
1660	/// #     type Fields = UserFields;
1661	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1662	/// #     fn table_name() -> &'static str { "users" }
1663	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1664	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1665	/// #     fn new_fields() -> Self::Fields { UserFields }
1666	/// # }
1667	/// #
1668	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1669	/// let handler = ModelViewSetHandler::<User>::new();
1670	/// let request = Request::builder()
1671	///     .method(Method::PUT)
1672	///     .uri("/users/1/")
1673	///     .version(Version::HTTP_11)
1674	///     .headers(HeaderMap::new())
1675	///     .body(Bytes::from(r#"{"username":"alice_updated"}"#))
1676	///     .build()?;
1677	/// let pk = serde_json::json!(1);
1678	/// let response = handler.update(&request, pk).await?;
1679	/// # Ok(())
1680	/// # }
1681	/// ```
1682	pub async fn update(
1683		&self,
1684		request: &Request,
1685		pk: serde_json::Value,
1686	) -> std::result::Result<Response, ViewError> {
1687		self.check_permissions(request).await?;
1688		self.ensure_mutation_scope_supported()?;
1689
1690		let serializer = self.get_serializer();
1691
1692		let existing_obj = if self.pool.is_some() {
1693			self.get_object(request, &pk).await?
1694		} else if self.queryset_fn.is_some() {
1695			return Err(ViewError::Internal(
1696				"with_queryset_fn requires a database pool".to_owned(),
1697			));
1698		} else {
1699			// Fall back to queryset for non-database mode
1700			self.get_queryset()
1701				.iter()
1702				.find(|item| self.matches_lookup(item, &pk))
1703				.cloned()
1704				.ok_or_else(|| ViewError::NotFound(format!("Object with lookup={pk} not found")))?
1705		};
1706
1707		// Parse request body as JSON for partial update (PATCH semantics)
1708		let body_str = String::from_utf8(request.body().to_vec())
1709			.map_err(|e| ViewError::BadRequest(format!("Invalid UTF-8: {}", e)))?;
1710
1711		// Parse patch data as JSON
1712		let patch_data: serde_json::Value = serde_json::from_str(&body_str)
1713			.map_err(|e| ViewError::Serialization(format!("Invalid JSON: {}", e)))?;
1714
1715		// Serialize existing object to JSON and merge with patch data
1716		let existing_json = serializer
1717			.serialize(&existing_obj)
1718			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1719		let mut existing_value: serde_json::Value = serde_json::from_str(&existing_json)
1720			.map_err(|e| ViewError::Serialization(format!("Failed to parse existing: {}", e)))?;
1721		// Validate and merge patch data into existing object (only overwrites provided fields)
1722		crate::generic::patch_utils::merge_patch_object_into(&mut existing_value, &patch_data)
1723			.map_err(ViewError::BadRequest)?;
1724
1725		// Deserialize merged object back to model type
1726		let merged_json = serde_json::to_string(&existing_value)
1727			.map_err(|e| ViewError::Serialization(format!("Failed to serialize merged: {}", e)))?;
1728		let mut updated_item: T = serializer
1729			.deserialize(&merged_json)
1730			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1731		self.ensure_scope_fields_unchanged(request, &existing_obj, &updated_item)?;
1732		let primary_key = existing_obj
1733			.primary_key()
1734			.ok_or_else(|| ViewError::Internal("Object has no primary key".to_owned()))?;
1735		updated_item.set_primary_key(primary_key);
1736		let response_json = serializer
1737			.serialize(&updated_item)
1738			.map_err(|e| ViewError::Serialization(e.to_string()))?;
1739
1740		// Update database if pool is available
1741		if let Some(pool) = &self.pool {
1742			// Create a new session for this request
1743			let mut session = reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1744				.await
1745				.map_err(|e| {
1746					ViewError::DatabaseError(format!("Failed to create session: {}", e))
1747				})?;
1748
1749			// Recheck and mutate through one dedicated transaction connection.
1750			let mut transaction = pool.begin().await.map_err(|e| {
1751				ViewError::DatabaseError(format!("Failed to begin transaction: {}", e))
1752			})?;
1753
1754			// Recheck the request-scoped predicate and lock the row before writing.
1755			let mutation_queryset = self
1756				.scoped_queryset(request)?
1757				.filter(self.lookup_filter(&pk)?)
1758				.without_slicing()
1759				.without_distinct();
1760			if session
1761				.list_with_connection_for_update(&mutation_queryset, &mut transaction)
1762				.await
1763				.map_err(|e| ViewError::DatabaseError(format!("Failed to recheck object: {}", e)))?
1764				.into_iter()
1765				.next()
1766				.is_none()
1767			{
1768				return Err(ViewError::NotFound(format!(
1769					"Object with pk={} not found",
1770					pk
1771				)));
1772			}
1773
1774			// Add updated object to session (marks as dirty for UPDATE)
1775			session
1776				.add(updated_item.clone())
1777				.await
1778				.map_err(|e| ViewError::DatabaseError(format!("Failed to add object: {}", e)))?;
1779
1780			// Flush changes to database (generates and executes UPDATE)
1781			session
1782				.flush_with_connection(&mut transaction)
1783				.await
1784				.map_err(|e| ViewError::DatabaseError(format!("Failed to flush: {}", e)))?;
1785
1786			// Commit transaction
1787			transaction
1788				.commit()
1789				.await
1790				.map_err(|e| ViewError::DatabaseError(format!("Failed to commit: {}", e)))?;
1791		}
1792
1793		// Return the complete merged/updated object
1794		Ok(Response::ok().with_body(response_json))
1795	}
1796
1797	/// Delete an object
1798	///
1799	/// # Examples
1800	///
1801	/// ```no_run
1802	/// # use reinhardt_views::viewsets::ModelViewSetHandler;
1803	/// # use reinhardt_http::Request;
1804	/// # use reinhardt_db::orm::Model;
1805	/// # use serde::{Serialize, Deserialize};
1806	/// # use serde_json::Value;
1807	/// # use bytes::Bytes;
1808	/// # use hyper::{Method, Version, HeaderMap};
1809	/// #
1810	/// # #[derive(Debug, Clone, Serialize, Deserialize)]
1811	/// # struct User {
1812	/// #     id: Option<i64>,
1813	/// #     username: String,
1814	/// # }
1815	/// #
1816	/// # #[derive(Clone)]
1817	/// # struct UserFields;
1818	/// #
1819	/// # impl reinhardt_db::orm::FieldSelector for UserFields {
1820	/// #     fn with_alias(self, _alias: &str) -> Self { self }
1821	/// # }
1822	/// #
1823	/// # impl Model for User {
1824	/// #     type PrimaryKey = i64;
1825	/// #     type Fields = UserFields;
1826	/// #     type Objects = reinhardt_db::orm::Manager<Self>;
1827	/// #     fn table_name() -> &'static str { "users" }
1828	/// #     fn primary_key(&self) -> Option<Self::PrimaryKey> { self.id }
1829	/// #     fn set_primary_key(&mut self, value: Self::PrimaryKey) { self.id = Some(value); }
1830	/// #     fn new_fields() -> Self::Fields { UserFields }
1831	/// # }
1832	/// #
1833	/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
1834	/// let handler = ModelViewSetHandler::<User>::new();
1835	/// let request = Request::builder()
1836	///     .method(Method::DELETE)
1837	///     .uri("/users/1/")
1838	///     .version(Version::HTTP_11)
1839	///     .headers(HeaderMap::new())
1840	///     .body(Bytes::new())
1841	///     .build()?;
1842	/// let pk = serde_json::json!(1);
1843	/// let response = handler.destroy(&request, pk).await?;
1844	/// # Ok(())
1845	/// # }
1846	/// ```
1847	pub async fn destroy(
1848		&self,
1849		request: &Request,
1850		pk: serde_json::Value,
1851	) -> std::result::Result<Response, ViewError> {
1852		self.check_permissions(request).await?;
1853		self.ensure_mutation_scope_supported()?;
1854
1855		if self.pool.is_none() {
1856			if self.queryset_fn.is_some() {
1857				return Err(ViewError::Internal(
1858					"with_queryset_fn requires a database pool".to_owned(),
1859				));
1860			}
1861			self.get_queryset()
1862				.iter()
1863				.find(|item| self.matches_lookup(item, &pk))
1864				.cloned()
1865				.ok_or_else(|| ViewError::NotFound(format!("Object with lookup={pk} not found")))?;
1866		}
1867
1868		// Delete from database if pool is available
1869		if let Some(pool) = &self.pool {
1870			// Create a new session for this request
1871			let mut session = reinhardt_db::prelude::Session::new(pool.clone(), self.db_backend)
1872				.await
1873				.map_err(|e| {
1874					ViewError::DatabaseError(format!("Failed to create session: {}", e))
1875				})?;
1876
1877			// Recheck and mutate through one dedicated transaction connection.
1878			let mut transaction = pool.begin().await.map_err(|e| {
1879				ViewError::DatabaseError(format!("Failed to begin transaction: {}", e))
1880			})?;
1881
1882			// Recheck the request-scoped predicate and lock the row before deleting.
1883			let mutation_queryset = self
1884				.scoped_queryset(request)?
1885				.filter(self.lookup_filter(&pk)?)
1886				.without_slicing()
1887				.without_distinct();
1888			let item = session
1889				.list_with_connection_for_update(&mutation_queryset, &mut transaction)
1890				.await
1891				.map_err(|e| ViewError::DatabaseError(format!("Failed to recheck object: {}", e)))?
1892				.into_iter()
1893				.next()
1894				.ok_or_else(|| ViewError::NotFound(format!("Object with pk={} not found", pk)))?;
1895
1896			// Mark object for deletion
1897			session.delete(item).await.map_err(|e| {
1898				ViewError::DatabaseError(format!("Failed to mark object for deletion: {}", e))
1899			})?;
1900
1901			// Flush changes to database (generates and executes DELETE)
1902			session
1903				.flush_with_connection(&mut transaction)
1904				.await
1905				.map_err(|e| ViewError::DatabaseError(format!("Failed to flush: {}", e)))?;
1906
1907			// Commit transaction
1908			transaction
1909				.commit()
1910				.await
1911				.map_err(|e| ViewError::DatabaseError(format!("Failed to commit: {}", e)))?;
1912		}
1913
1914		Ok(Response::no_content())
1915	}
1916}
1917
1918impl<T> Default for ModelViewSetHandler<T>
1919where
1920	T: Model + Serialize + DeserializeOwned + Clone + Send + Sync + 'static,
1921{
1922	fn default() -> Self {
1923		Self::new()
1924	}
1925}
1926
1927#[cfg(test)]
1928mod tests {
1929	use super::*;
1930	use bytes::Bytes;
1931	use hyper::{HeaderMap, Method, Version};
1932	use reinhardt_auth::{IsActiveUser, IsAuthenticated};
1933	use reinhardt_db::orm::fields::{CharField, Field};
1934	use reinhardt_db::orm::inspection::FieldInfo;
1935	use reinhardt_db::orm::{Filter, FilterOperator, FilterValue};
1936	use reinhardt_http::Request;
1937	use reinhardt_rest::serializers::SerializerError;
1938	use rstest::rstest;
1939	use std::sync::atomic::{AtomicUsize, Ordering};
1940
1941	fn build_request(uri: &str) -> Request {
1942		Request::builder()
1943			.method(Method::GET)
1944			.uri(uri)
1945			.version(Version::HTTP_11)
1946			.headers(HeaderMap::new())
1947			.body(Bytes::new())
1948			.build()
1949			.unwrap()
1950	}
1951
1952	#[rstest]
1953	fn composite_pk_parser_preserves_delimiters_in_length_prefixed_values() {
1954		let fields = vec!["namespace".to_owned(), "id".to_owned()];
1955		let parts =
1956			parse_length_prefixed_composite_parts("namespace=9:a, id=999, id=3:123", &fields)
1957				.expect("length-prefixed composite keys should parse");
1958
1959		assert_eq!(parts, vec!["a, id=999", "123"]);
1960	}
1961
1962	#[rstest]
1963	fn legacy_composite_pk_parser_uses_typed_boundaries() {
1964		let fields = vec!["namespace".to_owned(), "id".to_owned()];
1965		let is_valid = |index: usize, value: &str| index == 0 || value.parse::<i64>().is_ok();
1966		let parts =
1967			parse_legacy_composite_parts("namespace=a, id=999, id=1", &fields, 0, &is_valid)
1968				.expect("legacy composite keys should parse");
1969
1970		assert_eq!(parts, vec!["a, id=999", "1"]);
1971	}
1972
1973	// -----------------------------------------------------------------------
1974	// Test model for retrieve PK tests
1975	// -----------------------------------------------------------------------
1976
1977	#[derive(Debug, Clone, Serialize, serde::Deserialize, PartialEq)]
1978	struct TestItem {
1979		id: Option<i64>,
1980		name: String,
1981		organization: Option<String>,
1982	}
1983
1984	#[derive(Clone, Copy)]
1985	struct AliasTestItemSerializer;
1986
1987	impl Serializer for AliasTestItemSerializer {
1988		type Input = TestItem;
1989		type Output = String;
1990
1991		fn serialize(&self, input: &Self::Input) -> Result<Self::Output, SerializerError> {
1992			serde_json::to_string(&serde_json::json!({
1993				"id": input.id,
1994				"name": input.name,
1995				"tenant": input.organization,
1996			}))
1997			.map_err(|error| SerializerError::Serde {
1998				message: error.to_string(),
1999			})
2000		}
2001
2002		fn deserialize(&self, output: &Self::Output) -> Result<Self::Input, SerializerError> {
2003			#[derive(serde::Deserialize)]
2004			struct Payload {
2005				id: Option<i64>,
2006				name: String,
2007				tenant: Option<String>,
2008			}
2009
2010			let payload: Payload =
2011				serde_json::from_str(output).map_err(|error| SerializerError::Serde {
2012					message: error.to_string(),
2013				})?;
2014			Ok(TestItem {
2015				id: payload.id,
2016				name: payload.name,
2017				organization: payload.tenant,
2018			})
2019		}
2020	}
2021
2022	#[derive(Clone)]
2023	struct TestItemFields;
2024
2025	#[derive(Clone, Copy)]
2026	struct OrganizationId(i64);
2027
2028	#[derive(Default)]
2029	struct ScopedTestItemManager;
2030
2031	impl reinhardt_db::orm::CustomManager for ScopedTestItemManager {
2032		type Model = TestItem;
2033
2034		fn new() -> Self {
2035			Self
2036		}
2037
2038		fn all(&self) -> QuerySet<Self::Model> {
2039			QuerySet::new()
2040				.filter(Filter::new(
2041					"organization",
2042					FilterOperator::Eq,
2043					FilterValue::Integer(99),
2044				))
2045				.filter(Filter::new(
2046					"organization",
2047					FilterOperator::Eq,
2048					FilterValue::FieldRef(reinhardt_db::orm::expressions::F::new("organization")),
2049				))
2050				.filter(Filter::new(
2051					"organization",
2052					FilterOperator::Eq,
2053					FilterValue::Expression(reinhardt_db::orm::annotation::Expression::Add(
2054						Box::new(reinhardt_db::orm::annotation::AnnotationValue::Field(
2055							reinhardt_db::orm::expressions::F::new("organization"),
2056						)),
2057						Box::new(reinhardt_db::orm::annotation::AnnotationValue::Value(
2058							reinhardt_db::orm::annotation::Value::Int(1),
2059						)),
2060					)),
2061				))
2062				.filter(
2063					reinhardt_db::orm::expressions::FieldRef::<TestItem, String>::new(
2064						"organization",
2065					)
2066					.year()
2067					.eq(2026),
2068				)
2069				.order_by(&["-organization"])
2070		}
2071	}
2072
2073	impl reinhardt_db::orm::FieldSelector for TestItemFields {
2074		fn with_alias(self, _alias: &str) -> Self {
2075			self
2076		}
2077	}
2078
2079	impl reinhardt_db::orm::Model for TestItem {
2080		type PrimaryKey = i64;
2081		type Fields = TestItemFields;
2082		type Objects = ScopedTestItemManager;
2083
2084		fn table_name() -> &'static str {
2085			"test_items"
2086		}
2087
2088		fn primary_key(&self) -> Option<Self::PrimaryKey> {
2089			self.id
2090		}
2091
2092		fn set_primary_key(&mut self, value: Self::PrimaryKey) {
2093			self.id = Some(value);
2094		}
2095
2096		fn new_fields() -> Self::Fields {
2097			TestItemFields
2098		}
2099
2100		fn field_metadata() -> Vec<FieldInfo> {
2101			let mut organization = CharField::new(255);
2102			organization.set_attributes_from_name("organization");
2103			organization.base.db_column = Some("organization_id".to_owned());
2104			vec![FieldInfo::from_field(&organization)]
2105		}
2106	}
2107
2108	/// Helper to build a ModelViewSetHandler with in-memory queryset
2109	fn build_model_handler(items: Vec<TestItem>) -> ModelViewSetHandler<TestItem> {
2110		ModelViewSetHandler::<TestItem>::new().with_queryset(items)
2111	}
2112
2113	#[test]
2114	fn scoped_queryset_fn_reads_request_extensions() {
2115		let request = build_request("/items/");
2116		request.extensions.insert(OrganizationId(7));
2117		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(|request| {
2118			let organization = request
2119				.extensions
2120				.get::<OrganizationId>()
2121				.ok_or_else(|| ViewError::Permission("organization scope is missing".to_owned()))?;
2122			Ok(Filter::new(
2123				"organization_id",
2124				FilterOperator::Eq,
2125				FilterValue::Integer(organization.0),
2126			)
2127			.into())
2128		});
2129
2130		let queryset = handler.scoped_queryset(&request).unwrap();
2131
2132		assert_eq!(queryset.filters().len(), 5);
2133		assert!(
2134			queryset
2135				.filters()
2136				.iter()
2137				.take(3)
2138				.all(|filter| filter.field == "organization_id")
2139		);
2140		assert_eq!(
2141			queryset.filters()[3].field,
2142			"EXTRACT(YEAR FROM \"organization_id\")"
2143		);
2144		assert_eq!(
2145			queryset.filters()[3].source_field_name(),
2146			Some("organization")
2147		);
2148		let FilterValue::FieldRef(field) = &queryset.filters()[1].value else {
2149			panic!("custom-manager field reference should be preserved");
2150		};
2151		assert_eq!(field.field, "organization_id");
2152		let FilterValue::Expression(expression) = &queryset.filters()[2].value else {
2153			panic!("custom-manager expression should be preserved");
2154		};
2155		assert_eq!(expression.to_sql(), "(\"organization_id\" + 1)");
2156		assert_eq!(
2157			queryset.to_sql(),
2158			"SELECT * FROM \"test_items\" WHERE (\"organization_id\" = 99 AND \"organization_id\" = \"organization_id\" AND \"organization_id\" = (\"organization_id\" + 1) AND EXTRACT(YEAR FROM \"organization_id\") = 2026 AND \"organization_id\" = 7) ORDER BY \"organization_id\" DESC"
2159		);
2160	}
2161
2162	#[test]
2163	fn postgres_annotation_scope_fields_are_mapped_and_collected() {
2164		use reinhardt_db::orm::annotation::{AnnotationValue, Expression};
2165
2166		let mut value = AnnotationValue::Expression(Expression::Coalesce(vec![
2167			AnnotationValue::ArrayAgg(
2168				reinhardt_db::orm::ArrayAgg::new("organization".to_owned())
2169					.order_by(vec!["organization DESC".to_owned()]),
2170			),
2171			AnnotationValue::StringAgg(reinhardt_db::orm::StringAgg::new(
2172				"organization".to_owned(),
2173				", ".to_owned(),
2174			)),
2175			AnnotationValue::JsonbAgg(reinhardt_db::orm::JsonbAgg::new("organization".to_owned())),
2176			AnnotationValue::JsonbBuildObject(
2177				reinhardt_db::orm::JsonbBuildObject::new().add("tenant", "organization"),
2178			),
2179			AnnotationValue::TsRank(reinhardt_db::orm::TsRank::new(
2180				"organization".to_owned(),
2181				"tenant".to_owned(),
2182			)),
2183		]));
2184
2185		let mut fields = Vec::new();
2186		collect_scope_annotation_value(&value, &mut fields);
2187		assert_eq!(fields, vec!["organization"; 6]);
2188
2189		map_scope_annotation_value::<TestItem>(&mut value);
2190		assert_eq!(
2191			value.to_sql(),
2192			"COALESCE(ARRAY_AGG(organization_id ORDER BY organization_id DESC), STRING_AGG(organization_id, ', '), JSONB_AGG(organization_id), jsonb_build_object('tenant', organization_id), ts_rank(organization_id, to_tsquery('english', 'tenant')))"
2193		);
2194	}
2195
2196	#[rstest]
2197	fn qualified_scope_fields_map_the_final_component() {
2198		let mut field = "items.organization".to_owned();
2199
2200		map_scope_field::<TestItem>(&mut field);
2201
2202		assert_eq!(field, "items.organization_id");
2203	}
2204
2205	#[rstest]
2206	fn qualified_scope_ordering_maps_the_final_component() {
2207		let mut field = "items.organization DESC NULLS LAST".to_owned();
2208
2209		map_scope_order_by_field::<TestItem>(&mut field);
2210
2211		assert_eq!(field, "items.organization_id DESC NULLS LAST");
2212	}
2213
2214	#[rstest]
2215	fn opaque_scalar_subquery_scope_is_rejected_before_mutation() {
2216		use reinhardt_db::orm::annotation::{AnnotationValue, Expression};
2217
2218		let request = build_request("/items/");
2219		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(|_| {
2220			Ok(Filter::new(
2221				"organization",
2222				FilterOperator::Eq,
2223				FilterValue::Expression(Expression::Coalesce(vec![AnnotationValue::Subquery(
2224					"(SELECT organization_id FROM memberships WHERE memberships.item_id = items.id)"
2225						.to_owned(),
2226				)])),
2227			)
2228			.into())
2229		});
2230
2231		let error = handler
2232			.ensure_scope_values_unchanged(
2233				&request,
2234				&serde_json::json!({"organization": "tenant-a"}),
2235				&serde_json::json!({"organization": "tenant-a"}),
2236			)
2237			.unwrap_err();
2238
2239		assert!(matches!(
2240			error,
2241			ViewError::Permission(message)
2242				if message == "opaque scalar subquery scopes cannot be mutated"
2243		));
2244	}
2245
2246	#[rstest]
2247	fn scope_field_changes_are_rejected_before_update() {
2248		let request = build_request("/items/");
2249		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(|_| {
2250			Ok(Filter::new("organization", FilterOperator::Eq, FilterValue::Integer(7)).into())
2251		});
2252
2253		let error = handler
2254			.ensure_scope_values_unchanged(
2255				&request,
2256				&serde_json::json!({"organization": "tenant-a"}),
2257				&serde_json::json!({"organization": "tenant-b"}),
2258			)
2259			.unwrap_err();
2260
2261		assert!(matches!(
2262			error,
2263			ViewError::Permission(message) if message == "scope field `organization` cannot be changed"
2264		));
2265	}
2266
2267	#[test]
2268	fn scope_field_changes_are_rejected_after_custom_serializer_alias_round_trip() {
2269		let request = build_request("/items/");
2270		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(|_| {
2271			Ok(Filter::new(
2272				"organization",
2273				FilterOperator::Eq,
2274				FilterValue::String("tenant-a".to_owned()),
2275			)
2276			.into())
2277		});
2278		let serializer = AliasTestItemSerializer;
2279		let existing = TestItem {
2280			id: Some(1),
2281			name: "item".to_owned(),
2282			organization: Some("tenant-a".to_owned()),
2283		};
2284		let mut serialized: serde_json::Value =
2285			serde_json::from_str(&serializer.serialize(&existing).unwrap()).unwrap();
2286		serialized["tenant"] = serde_json::json!("tenant-b");
2287		let updated = serializer
2288			.deserialize(&serde_json::to_string(&serialized).unwrap())
2289			.unwrap();
2290
2291		let error = handler
2292			.ensure_scope_fields_unchanged(&request, &existing, &updated)
2293			.unwrap_err();
2294
2295		assert!(matches!(
2296			error,
2297			ViewError::Permission(message) if message == "scope field `organization` cannot be changed"
2298		));
2299	}
2300
2301	#[rstest]
2302	fn custom_manager_scope_fields_are_rejected_before_update() {
2303		let request = build_request("/items/");
2304		let handler = ModelViewSetHandler::<TestItem>::new();
2305
2306		let error = handler
2307			.ensure_scope_values_unchanged(
2308				&request,
2309				&serde_json::json!({"organization": "99"}),
2310				&serde_json::json!({"organization": "100"}),
2311			)
2312			.unwrap_err();
2313
2314		assert!(matches!(
2315			error,
2316			ViewError::Permission(message) if message == "scope field `organization` cannot be changed"
2317		));
2318	}
2319
2320	#[test]
2321	fn scoped_queryset_propagates_hook_errors() {
2322		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(|_| {
2323			Err(ViewError::Permission(
2324				"organization scope is missing".to_owned(),
2325			))
2326		});
2327
2328		let error = match handler.scoped_queryset(&build_request("/items/")) {
2329			Ok(_) => panic!("queryset hook error must propagate"),
2330			Err(error) => error,
2331		};
2332
2333		assert!(
2334			matches!(error, ViewError::Permission(message) if message == "organization scope is missing")
2335		);
2336	}
2337
2338	#[test]
2339	fn get_object_primary_key_filter_preserves_integer_type() {
2340		let filter =
2341			ModelViewSetHandler::<TestItem>::primary_key_filter(&serde_json::json!(42)).unwrap();
2342		let FilterCondition::Single(filter) = filter else {
2343			panic!("a scalar primary key should produce one filter");
2344		};
2345
2346		assert_eq!(filter.field, "id");
2347		assert!(matches!(filter.value, FilterValue::Integer(42)));
2348	}
2349
2350	#[test]
2351	fn custom_lookup_filter_maps_declared_database_column() {
2352		let handler =
2353			ModelViewSetHandler::<TestItem>::new().with_lookup_field("organization".to_owned());
2354
2355		let FilterCondition::Single(filter) = handler
2356			.lookup_filter(&serde_json::json!("tenant-a"))
2357			.unwrap()
2358		else {
2359			panic!("a custom lookup should produce one filter");
2360		};
2361
2362		assert_eq!(filter.field, "organization_id");
2363		assert!(matches!(
2364			filter.value,
2365			FilterValue::String(value) if value == "tenant-a"
2366		));
2367	}
2368
2369	#[test]
2370	fn assigned_primary_key_filter_preserves_declared_key_binding() {
2371		let item = TestItem {
2372			id: Some(42),
2373			name: "item".to_owned(),
2374			organization: Some("tenant-a".to_owned()),
2375		};
2376		let FilterCondition::Single(filter) = assigned_primary_key_filter(&item).unwrap() else {
2377			panic!("single primary key should produce one filter");
2378		};
2379
2380		assert_eq!(filter.field, "id");
2381		assert!(matches!(filter.value, FilterValue::Integer(42)));
2382	}
2383
2384	#[tokio::test]
2385	async fn queryset_fn_without_pool_fails_closed() {
2386		let request = build_request("/items/");
2387		let handler = ModelViewSetHandler::<TestItem>::new()
2388			.with_queryset(vec![TestItem {
2389				id: Some(1),
2390				name: "visible".to_owned(),
2391				organization: None,
2392			}])
2393			.with_queryset_fn(|_| {
2394				Ok(Filter::new("organization_id", FilterOperator::Eq, 1_i64.into()).into())
2395			});
2396
2397		let error = handler.list(&request).await.unwrap_err();
2398
2399		assert!(matches!(error, ViewError::Internal(_)));
2400	}
2401
2402	#[tokio::test]
2403	async fn permission_denial_does_not_call_queryset_fn() {
2404		let hook_calls = Arc::new(AtomicUsize::new(0));
2405		let hook_calls_for_queryset = Arc::clone(&hook_calls);
2406		let handler = ModelViewSetHandler::<TestItem>::new()
2407			.add_permission(Arc::new(IsAuthenticated))
2408			.with_queryset_fn(move |_| {
2409				hook_calls_for_queryset.fetch_add(1, Ordering::SeqCst);
2410				Ok(Filter::new("organization_id", FilterOperator::Eq, 1_i64.into()).into())
2411			});
2412
2413		let error = handler.list(&build_request("/items/")).await.unwrap_err();
2414
2415		assert!(matches!(error, ViewError::Permission(_)));
2416		assert_eq!(hook_calls.load(Ordering::SeqCst), 0);
2417	}
2418
2419	#[tokio::test]
2420	async fn create_does_not_call_queryset_fn() {
2421		let hook_calls = Arc::new(AtomicUsize::new(0));
2422		let hook_calls_for_queryset = Arc::clone(&hook_calls);
2423		let handler = ModelViewSetHandler::<TestItem>::new().with_queryset_fn(move |_| {
2424			hook_calls_for_queryset.fetch_add(1, Ordering::SeqCst);
2425			Ok(Filter::new("organization_id", FilterOperator::Eq, 1_i64.into()).into())
2426		});
2427		let request = Request::builder()
2428			.method(Method::POST)
2429			.uri("/items/")
2430			.body(Bytes::from_static(br#"{"id":null,"name":"created"}"#))
2431			.build()
2432			.unwrap();
2433
2434		let response = handler.create(&request).await.unwrap();
2435
2436		assert_eq!(response.status, hyper::StatusCode::CREATED);
2437		assert_eq!(hook_calls.load(Ordering::SeqCst), 0);
2438	}
2439
2440	#[rstest]
2441	#[tokio::test]
2442	async fn test_list_denies_bare_user_id_extensions_for_active_permissions() {
2443		// Arrange
2444		let handler = build_model_handler(vec![TestItem {
2445			id: Some(1),
2446			name: "first".to_string(),
2447			organization: None,
2448		}])
2449		.add_permission(Arc::new(IsAuthenticated))
2450		.add_permission(Arc::new(IsActiveUser));
2451		let request = build_request("/items/");
2452		request.extensions.insert("legacy-user".to_string());
2453
2454		// Act
2455		let result = handler.list(&request).await;
2456
2457		// Assert
2458		let error = result.expect_err("bare user ID extensions must not grant authorization");
2459		assert!(matches!(error, ViewError::Permission(_)));
2460	}
2461
2462	#[rstest]
2463	#[tokio::test]
2464	async fn test_retrieve_strips_quotes_from_numeric_pk() {
2465		// Arrange
2466		let items = vec![
2467			TestItem {
2468				id: Some(1),
2469				name: "first".to_string(),
2470				organization: None,
2471			},
2472			TestItem {
2473				id: Some(2),
2474				name: "second".to_string(),
2475				organization: None,
2476			},
2477		];
2478		let handler = build_model_handler(items);
2479		let request = build_request("/items/1/");
2480
2481		// Act - pass pk with surrounding quotes (as JSON string value)
2482		let pk = serde_json::json!("1");
2483		let result = handler.retrieve(&request, pk).await;
2484
2485		// Assert - should find the item despite quotes in pk
2486		assert!(result.is_ok(), "retrieve should succeed with quoted pk");
2487		let response = result.unwrap();
2488		assert_eq!(response.status, hyper::StatusCode::OK);
2489		let body: TestItem =
2490			serde_json::from_slice(&response.body).expect("response should be valid JSON");
2491		assert_eq!(body.name, "first");
2492		assert_eq!(body.id, Some(1));
2493	}
2494
2495	#[rstest]
2496	#[tokio::test]
2497	async fn test_retrieve_works_with_unquoted_numeric_pk() {
2498		// Arrange
2499		let items = vec![TestItem {
2500			id: Some(42),
2501			name: "answer".to_string(),
2502			organization: None,
2503		}];
2504		let handler = build_model_handler(items);
2505		let request = build_request("/items/42/");
2506
2507		// Act - pass pk as JSON number (no quotes)
2508		let pk = serde_json::json!(42);
2509		let result = handler.retrieve(&request, pk).await;
2510
2511		// Assert
2512		assert!(result.is_ok(), "retrieve should succeed with numeric pk");
2513		let response = result.unwrap();
2514		assert_eq!(response.status, hyper::StatusCode::OK);
2515		let body: TestItem =
2516			serde_json::from_slice(&response.body).expect("response should be valid JSON");
2517		assert_eq!(body.name, "answer");
2518		assert_eq!(body.id, Some(42));
2519	}
2520
2521	#[rstest]
2522	#[tokio::test]
2523	async fn test_retrieve_returns_not_found_for_nonexistent_pk() {
2524		// Arrange
2525		let items = vec![TestItem {
2526			id: Some(1),
2527			name: "only".to_string(),
2528			organization: None,
2529		}];
2530		let handler = build_model_handler(items);
2531		let request = build_request("/items/999/");
2532
2533		// Act
2534		let pk = serde_json::json!(999);
2535		let result = handler.retrieve(&request, pk).await;
2536
2537		// Assert
2538		assert!(result.is_err(), "retrieve should fail for nonexistent pk");
2539		let err = result.unwrap_err();
2540		assert!(
2541			matches!(err, ViewError::NotFound(_)),
2542			"error should be NotFound, got: {:?}",
2543			err
2544		);
2545	}
2546}