Skip to main content

wp_model_core/model/data/
record.rs

1use crate::model::format::LevelFormatAble;
2use crate::model::{DataType, FNameStr, FValueStr, Value};
3use crate::model::{FieldRef, Maker};
4use crate::traits::AsValueRef;
5use serde_derive::{Deserialize, Serialize};
6use std::convert::TryFrom;
7use std::fmt::{Display, Formatter};
8use std::net::{IpAddr, Ipv4Addr};
9use std::sync::Arc;
10
11use super::field::Field;
12use super::storage::FieldStorage;
13pub const WP_EVENT_ID: &str = "wp_event_id";
14/// 记录中每一项需要暴露的行为
15pub trait RecordItem {
16    fn get_name(&self) -> &str;
17    fn get_meta(&self) -> &DataType;
18    fn get_value(&self) -> &Value;
19    fn get_value_mut(&mut self) -> &mut Value;
20}
21
22/// 为 Record 生成字段所需的工厂方法
23pub trait RecordItemFactory {
24    fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self;
25    fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self;
26    fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self;
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30pub struct Record<T> {
31    pub id: u64,
32    pub items: Vec<T>,
33}
34
35impl<T> Default for Record<T> {
36    fn default() -> Self {
37        Self {
38            id: 0,
39            items: Vec::with_capacity(10),
40        }
41    }
42}
43
44impl<T> From<Vec<T>> for Record<T> {
45    fn from(value: Vec<T>) -> Self {
46        Self {
47            id: 0,
48            items: value,
49        }
50    }
51}
52
53impl<T> Display for Record<T>
54where
55    T: RecordItem + LevelFormatAble,
56{
57    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58        writeln!(f)?;
59        for (i, o) in self.items.iter().enumerate() {
60            if *o.get_meta() != DataType::Ignore {
61                write!(f, "NO:{:<5}", i + 1)?;
62                o.level_fmt(f, 1)?;
63            }
64        }
65        Ok(())
66    }
67}
68
69impl<T> Record<T>
70where
71    T: RecordItem + RecordItemFactory,
72{
73    pub fn set_id(&mut self, id: u64) {
74        // 设置 id 字段
75        self.id = id;
76
77        // 如果已存在 wp_event_id 字段,避免重复追加
78        if self.items.iter().any(|f| f.get_name() == WP_EVENT_ID) {
79            return;
80        }
81        let Ok(id_i64) = i64::try_from(id) else {
82            // 事件 ID 超出 i64 无法表示,保持记录原状
83            return;
84        };
85        self.items.insert(0, T::from_digit(WP_EVENT_ID, id_i64));
86    }
87    pub fn test_value() -> Self {
88        let data = vec![
89            T::from_ip("ip", IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
90            T::from_chars("chars", "test"),
91        ];
92        Self { id: 0, items: data }
93    }
94}
95
96impl<T> Record<T>
97where
98    T: RecordItem,
99{
100    pub fn get_value(&self, key: &str) -> Option<&Value> {
101        self.items
102            .iter()
103            .find(|x| x.get_name() == key)
104            .map(|x| x.get_value())
105    }
106}
107
108impl<T> Record<T> {
109    pub fn len(&self) -> usize {
110        self.items.len()
111    }
112
113    pub fn is_empty(&self) -> bool {
114        self.items.is_empty()
115    }
116
117    /// Append a field to the record.
118    ///
119    /// Accepts any type that can be converted into `T`. For `DataRecord`,
120    /// this means you can pass [`DataField`], [`FieldStorage`], or `Arc<DataField>` directly.
121    pub fn append(&mut self, data: impl Into<T>) {
122        self.items.push(data.into());
123    }
124
125    /// Alias for [`append`](Self::append) following Vec naming convention.
126    pub fn push(&mut self, data: impl Into<T>) {
127        self.items.push(data.into());
128    }
129
130    pub fn merge(&mut self, mut other: Self) {
131        self.items.append(&mut other.items);
132    }
133}
134
135impl<T> Record<T>
136where
137    T: RecordItem,
138{
139    // 存在同名字段时取第一个字段返回值
140    pub fn field(&self, key: &str) -> Option<&T> {
141        self.items.iter().find(|item| item.get_name() == key)
142    }
143
144    pub fn field_mut(&mut self, key: &str) -> Option<&mut T> {
145        self.items.iter_mut().find(|item| item.get_name() == key)
146    }
147
148    pub fn get2(&self, name: &str) -> Option<&T> {
149        self.items.iter().find(|x| x.get_name() == name)
150    }
151    pub fn get_value_mut(&mut self, name: &str) -> Option<&mut T> {
152        self.items.iter_mut().find(|x| x.get_name() == name)
153    }
154    pub fn remove_field(&mut self, name: &str) -> bool {
155        let pos = self.items.iter().position(|x| x.get_name() == name);
156        if let Some(pos) = pos {
157            self.items.remove(pos);
158            true
159        } else {
160            false
161        }
162    }
163}
164
165impl<V> RecordItem for Field<V>
166where
167    V: AsValueRef<Value>,
168{
169    fn get_name(&self) -> &str {
170        Field::get_name(self)
171    }
172
173    fn get_meta(&self) -> &DataType {
174        Field::get_meta(self)
175    }
176
177    fn get_value(&self) -> &Value {
178        Field::get_value(self)
179    }
180
181    fn get_value_mut(&mut self) -> &mut Value {
182        Field::get_value_mut(self)
183    }
184}
185
186impl<V> RecordItemFactory for Field<V>
187where
188    V: Maker<i64> + Maker<FValueStr> + Maker<IpAddr>,
189{
190    fn from_digit<S: Into<FNameStr>>(name: S, val: i64) -> Self {
191        Field::from_digit(name, val)
192    }
193
194    fn from_ip<S: Into<FNameStr>>(name: S, ip: IpAddr) -> Self {
195        Field::from_ip(name, ip)
196    }
197
198    fn from_chars<N: Into<FNameStr>, Val: Into<FValueStr>>(name: N, val: Val) -> Self {
199        Field::from_chars(name, val)
200    }
201}
202
203// Convenience construction for Record<FieldStorage> from Vec<DataField>
204impl From<Vec<Field<Value>>> for Record<FieldStorage> {
205    fn from(fields: Vec<Field<Value>>) -> Self {
206        let items: Vec<FieldStorage> = fields.into_iter().map(FieldStorage::from_owned).collect();
207        Self { id: 0, items }
208    }
209}
210
211// Convenience construction for Record<FieldStorage> from a single DataField
212impl From<Field<Value>> for Record<FieldStorage> {
213    fn from(field: Field<Value>) -> Self {
214        Self {
215            id: 0,
216            items: vec![FieldStorage::from_owned(field)],
217        }
218    }
219}
220
221// Convenience methods for Record<FieldStorage> (DataRecord with mixed storage)
222impl Record<FieldStorage> {
223    /// Push a shared field (Arc-wrapped) to the record
224    ///
225    /// # Examples
226    ///
227    /// ```
228    /// use std::sync::Arc;
229    /// use wp_model_core::model::{DataRecord, Field, Value, DataType, FieldStorage};
230    ///
231    /// let mut record = DataRecord::default();
232    /// let field = Arc::new(Field::new(DataType::Chars, "app_name", Value::from("myapp")));
233    /// record.push_shared(field);
234    /// ```
235    pub fn push_shared(&mut self, field: Arc<Field<Value>>) {
236        self.items.push(FieldStorage::from_shared(field));
237    }
238
239    /// Push an owned field to the record
240    ///
241    /// # Examples
242    ///
243    /// ```
244    /// use wp_model_core::model::{DataRecord, Field, Value, DataType};
245    ///
246    /// let mut record = DataRecord::default();
247    /// let field = Field::new(DataType::Digit, "count", Value::from(42));
248    /// record.push_owned(field);
249    /// ```
250    pub fn push_owned(&mut self, field: Field<Value>) {
251        self.items.push(FieldStorage::from_owned(field));
252    }
253
254    /// Get a reference to the underlying field by index
255    ///
256    /// # Examples
257    ///
258    /// ```
259    /// use wp_model_core::model::{DataRecord, Field, Value, DataType};
260    ///
261    /// let mut record = DataRecord::default();
262    /// let field = Field::new(DataType::Digit, "x", Value::from(10));
263    /// record.push_owned(field);
264    ///
265    /// let retrieved = record.field_at(0);
266    /// assert!(retrieved.is_some());
267    /// assert_eq!(retrieved.unwrap().get_name(), "x");
268    /// ```
269    pub fn field_at(&self, index: usize) -> Option<&Field<Value>> {
270        self.items.get(index).map(|s| s.as_field())
271    }
272
273    /// Get a [`FieldRef`] by name (zero-copy, cur_name-aware).
274    ///
275    /// Returns a [`FieldRef`] that respects the `cur_name` override.
276    /// For owned field access, use [`get_field_owned()`](Self::get_field_owned).
277    ///
278    /// # Examples
279    ///
280    /// ```ignore
281    /// use wp_model_core::model::{DataRecord, DataField};
282    ///
283    /// let record = DataRecord::from(vec![
284    ///     DataField::from_chars("name", "Alice"),
285    /// ]);
286    /// assert_eq!(record.get_field("name").map(|f| f.get_name()), Some("name"));
287    /// assert!(record.get_field("missing").is_none());
288    /// ```
289    pub fn get_field(&self, name: &str) -> Option<FieldRef<'_>> {
290        self.field(name).map(|s| s.field_ref())
291    }
292
293    /// Get owned field by name with cur_name applied.
294    ///
295    /// Use when you need to modify the field or transfer ownership.
296    pub fn get_field_owned(&self, name: &str) -> Option<Field<Value>> {
297        self.get_field(name).map(|f| f.to_owned())
298    }
299
300    /// Get a mutable reference to the underlying [`DataField`] by name.
301    ///
302    /// For `Shared` fields, this converts to `Owned` first (clone-on-write).
303    ///
304    /// # Examples
305    ///
306    /// ```ignore
307    /// use wp_model_core::model::{DataRecord, DataField};
308    ///
309    /// let mut record = DataRecord::from(vec![
310    ///     DataField::from_chars("name", "Alice"),
311    /// ]);
312    /// if let Some(field) = record.get_field_mut("name") {
313    ///     field.set_name("renamed");
314    /// }
315    /// ```
316    pub fn get_field_mut(&mut self, name: &str) -> Option<&mut Field<Value>> {
317        self.field_mut(name).map(|s| s.as_field_mut())
318    }
319
320    /// Iterate over all fields as [`DataField`] references.
321    ///
322    /// Note: Returns underlying field references. Field names may not reflect
323    /// `cur_name` overrides. Use [`field_refs()`](Self::field_refs) for cur_name-aware iteration.
324    pub fn fields(&self) -> impl Iterator<Item = &Field<Value>> + '_ {
325        self.items.iter().map(|s| s.as_field())
326    }
327
328    /// Iterate over all fields as [`FieldRef`] (zero-copy, cur_name-aware).
329    pub fn field_refs(&self) -> impl Iterator<Item = FieldRef<'_>> + '_ {
330        self.items.iter().map(|s| s.field_ref())
331    }
332
333    /// Iterate over all fields as mutable [`DataField`] references.
334    ///
335    /// For `Shared` fields, this converts them to `Owned` (clone-on-write).
336    pub fn fields_mut(&mut self) -> impl Iterator<Item = &mut Field<Value>> + '_ {
337        self.items.iter_mut().map(|s| s.as_field_mut())
338    }
339
340    /// Get statistics about storage types (shared vs owned)
341    ///
342    /// Returns (shared_count, owned_count)
343    ///
344    /// # Examples
345    ///
346    /// ```
347    /// use std::sync::Arc;
348    /// use wp_model_core::model::{DataRecord, Field, Value, DataType};
349    ///
350    /// let mut record = DataRecord::default();
351    /// let static_field = Arc::new(Field::new(DataType::Chars, "static", Value::from("val")));
352    /// record.push_shared(static_field);
353    ///
354    /// let dynamic_field = Field::new(DataType::Digit, "dynamic", Value::from(10));
355    /// record.push_owned(dynamic_field);
356    ///
357    /// let (shared, owned) = record.storage_stats();
358    /// assert_eq!(shared, 1);
359    /// assert_eq!(owned, 1);
360    /// ```
361    pub fn storage_stats(&self) -> (usize, usize) {
362        let mut shared_count = 0;
363        let mut owned_count = 0;
364        for item in &self.items {
365            if item.is_shared() {
366                shared_count += 1;
367            } else {
368                owned_count += 1;
369            }
370        }
371        (shared_count, owned_count)
372    }
373
374    /// Convert to a fully owned record (Record<Field<Value>>)
375    ///
376    /// This is useful when you need to pass the record to code that expects
377    /// the old Record<Field<Value>> type.
378    ///
379    /// # Examples
380    ///
381    /// ```
382    /// use wp_model_core::model::{DataRecord, Field, Value, DataType};
383    ///
384    /// let mut record = DataRecord::default();
385    /// let field = Field::new(DataType::Digit, "x", Value::from(10));
386    /// record.push_owned(field);
387    ///
388    /// let owned_record = record.into_owned_record();
389    /// assert_eq!(owned_record.items.len(), 1);
390    /// ```
391    pub fn into_owned_record(self) -> Record<Field<Value>> {
392        Record {
393            id: self.id,
394            items: self
395                .items
396                .into_iter()
397                .map(|storage| storage.into_owned())
398                .collect(),
399        }
400    }
401}
402
403// ValueGetter impl removed from core; use function-style adapters in extension crates.
404
405#[cfg(test)]
406mod tests {
407    use super::*;
408    use crate::model::{DataField, DataRecord, FieldStorage};
409    use std::net::Ipv4Addr;
410
411    fn make_test_record() -> DataRecord {
412        let fields = vec![
413            FieldStorage::from_chars("name", "Alice"),
414            FieldStorage::from_digit("age", 30),
415            FieldStorage::from_ip("ip", IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1))),
416        ];
417        Record::from(fields)
418    }
419
420    // ========== Record creation tests ==========
421
422    #[test]
423    fn test_record_default() {
424        let record: DataRecord = Record::default();
425        assert!(record.items.is_empty());
426    }
427
428    #[test]
429    fn test_record_from_vec() {
430        let fields: Vec<FieldStorage> = vec![
431            FieldStorage::from_digit("x", 1),
432            FieldStorage::from_digit("y", 2),
433        ];
434        let record: DataRecord = Record::from(fields);
435        assert_eq!(record.items.len(), 2);
436    }
437
438    #[test]
439    fn test_record_test_value() {
440        let record: DataRecord = Record::test_value();
441        assert_eq!(record.items.len(), 2);
442        assert!(record.field("ip").is_some());
443        assert!(record.field("chars").is_some());
444    }
445
446    // ========== Record field access tests ==========
447
448    #[test]
449    fn test_record_field() {
450        let record = make_test_record();
451
452        let name_field = record.field("name");
453        assert!(name_field.is_some());
454        assert_eq!(name_field.unwrap().get_name(), "name");
455
456        let missing = record.field("missing");
457        assert!(missing.is_none());
458    }
459
460    #[test]
461    fn test_record_get2() {
462        let record = make_test_record();
463
464        let age_field = record.get2("age");
465        assert!(age_field.is_some());
466        assert_eq!(age_field.unwrap().get_meta(), &DataType::Digit);
467    }
468
469    #[test]
470    fn test_record_get_value() {
471        let record = make_test_record();
472
473        let age_value = record.get_value("age");
474        assert!(age_value.is_some());
475        assert_eq!(age_value.unwrap(), &Value::Digit(30));
476
477        let missing = record.get_value("missing");
478        assert!(missing.is_none());
479    }
480
481    #[test]
482    fn test_record_get_value_mut() {
483        let mut record = make_test_record();
484
485        let field = record.get_value_mut("age");
486        assert!(field.is_some());
487
488        // Modify the value through mutable reference
489        if let Some(f) = field {
490            *f.get_value_mut() = Value::Digit(31);
491        }
492
493        assert_eq!(record.get_value("age"), Some(&Value::Digit(31)));
494    }
495
496    // ========== Record mutation tests ==========
497
498    #[test]
499    fn test_record_append() {
500        let mut record: DataRecord = Record::default();
501        assert_eq!(record.items.len(), 0);
502
503        record.append(FieldStorage::from_digit("count", 100));
504        assert_eq!(record.items.len(), 1);
505
506        record.append(FieldStorage::from_chars("msg", "hello"));
507        assert_eq!(record.items.len(), 2);
508    }
509
510    #[test]
511    fn test_record_merge() {
512        let mut record1: DataRecord = Record::from(vec![FieldStorage::from_digit("a", 1)]);
513        let record2: DataRecord = Record::from(vec![
514            FieldStorage::from_digit("b", 2),
515            FieldStorage::from_digit("c", 3),
516        ]);
517
518        record1.merge(record2);
519        assert_eq!(record1.items.len(), 3);
520        assert!(record1.field("a").is_some());
521        assert!(record1.field("b").is_some());
522        assert!(record1.field("c").is_some());
523    }
524
525    #[test]
526    fn test_record_remove_field() {
527        let mut record = make_test_record();
528        assert_eq!(record.items.len(), 3);
529
530        let removed = record.remove_field("age");
531        assert!(removed);
532        assert_eq!(record.items.len(), 2);
533        assert!(record.field("age").is_none());
534
535        let not_found = record.remove_field("nonexistent");
536        assert!(!not_found);
537        assert_eq!(record.items.len(), 2);
538    }
539
540    // ========== set_id tests ==========
541
542    #[test]
543    fn test_record_set_id() {
544        let mut record = make_test_record();
545        let original_len = record.items.len();
546
547        record.set_id(12345);
548
549        // ID should be set in both the id field and added to items
550        assert_eq!(record.id, 12345);
551        assert_eq!(record.items.len(), original_len + 1);
552        // ID should be inserted at position 0
553        assert_eq!(record.items[0].get_name(), WP_EVENT_ID);
554        assert_eq!(record.items[0].get_value(), &Value::Digit(12345));
555    }
556
557    #[test]
558    fn test_record_set_id_no_duplicate() {
559        let mut record = make_test_record();
560
561        record.set_id(100);
562        assert_eq!(record.id, 100);
563        let len_after_first = record.items.len();
564
565        // Try to set ID again - should update id field but not add duplicate to items
566        record.set_id(200);
567        assert_eq!(record.id, 200);
568        assert_eq!(record.items.len(), len_after_first);
569        // Original ID in items should remain
570        assert_eq!(record.get_value(WP_EVENT_ID), Some(&Value::Digit(100)));
571    }
572
573    // ========== RecordItem trait tests ==========
574
575    #[test]
576    fn test_field_as_record_item() {
577        let field: DataField = Field::from_chars("key", "value");
578
579        // Test RecordItem trait methods
580        assert_eq!(field.get_name(), "key");
581        assert_eq!(field.get_meta(), &DataType::Chars);
582        assert_eq!(field.get_value(), &Value::Chars("value".into()));
583    }
584
585    #[test]
586    fn test_field_record_item_get_value_mut() {
587        let mut field: DataField = Field::from_digit("num", 10);
588
589        *field.get_value_mut() = Value::Digit(20);
590        assert_eq!(field.get_value(), &Value::Digit(20));
591    }
592
593    // ========== FieldStorage RecordItem tests ==========
594
595    #[test]
596    fn test_field_storage_as_record_item() {
597        let storage: FieldStorage = FieldStorage::from_chars("key", "value");
598
599        // Test RecordItem trait methods
600        assert_eq!(storage.get_name(), "key");
601        assert_eq!(storage.get_meta(), &DataType::Chars);
602        assert_eq!(storage.get_value(), &Value::Chars("value".into()));
603    }
604
605    #[test]
606    fn test_field_storage_record_item_get_value_mut() {
607        let mut storage: FieldStorage = FieldStorage::from_digit("num", 10);
608
609        *storage.get_value_mut() = Value::Digit(20);
610        assert_eq!(storage.get_value(), &Value::Digit(20));
611    }
612
613    // ========== RecordItemFactory trait tests ==========
614
615    #[test]
616    fn test_record_item_factory() {
617        let digit: FieldStorage = <FieldStorage as RecordItemFactory>::from_digit("n", 42);
618        assert_eq!(digit.get_meta(), &DataType::Digit);
619
620        let ip: FieldStorage = <FieldStorage as RecordItemFactory>::from_ip(
621            "addr",
622            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
623        );
624        assert_eq!(ip.get_meta(), &DataType::IP);
625
626        let chars: FieldStorage = <FieldStorage as RecordItemFactory>::from_chars("s", "hello");
627        assert_eq!(chars.get_meta(), &DataType::Chars);
628    }
629
630    // ========== Display test ==========
631
632    #[test]
633    fn test_record_display() {
634        let record = make_test_record();
635        let display = format!("{}", record);
636
637        assert!(display.contains("name"));
638        assert!(display.contains("age"));
639        assert!(display.contains("ip"));
640    }
641
642    // ========== Record<FieldStorage> convenience methods tests ==========
643
644    #[test]
645    fn test_push_shared() {
646        let mut record = DataRecord::default();
647        let field = Arc::new(Field::new(DataType::Chars, "static", Value::from("value")));
648
649        record.push_shared(field.clone());
650        assert_eq!(record.items.len(), 1);
651        assert!(record.items[0].is_shared());
652        assert_eq!(record.items[0].as_field().get_name(), "static");
653    }
654
655    #[test]
656    fn test_push_owned() {
657        let mut record = DataRecord::default();
658        let field = Field::new(DataType::Digit, "dynamic", Value::from(42));
659
660        record.push_owned(field);
661        assert_eq!(record.items.len(), 1);
662        assert!(!record.items[0].is_shared());
663        assert_eq!(record.items[0].as_field().get_name(), "dynamic");
664    }
665
666    #[test]
667    fn test_get_field() {
668        let mut record = DataRecord::default();
669        record.push_owned(Field::new(DataType::Chars, "test", Value::from("value")));
670
671        let field = record.field_at(0);
672        assert!(field.is_some());
673        assert_eq!(field.unwrap().get_name(), "test");
674
675        let missing = record.field_at(10);
676        assert!(missing.is_none());
677    }
678
679    #[test]
680    fn test_storage_stats() {
681        let mut record = DataRecord::default();
682
683        // Add shared fields
684        record.push_shared(Arc::new(Field::new(
685            DataType::Chars,
686            "s1",
687            Value::from("a"),
688        )));
689        record.push_shared(Arc::new(Field::new(
690            DataType::Chars,
691            "s2",
692            Value::from("b"),
693        )));
694
695        // Add owned fields
696        record.push_owned(Field::new(DataType::Digit, "o1", Value::from(1)));
697        record.push_owned(Field::new(DataType::Digit, "o2", Value::from(2)));
698        record.push_owned(Field::new(DataType::Digit, "o3", Value::from(3)));
699
700        let (shared, owned) = record.storage_stats();
701        assert_eq!(shared, 2);
702        assert_eq!(owned, 3);
703    }
704
705    #[test]
706    fn test_into_owned_record() {
707        let mut record = DataRecord::default();
708        record.push_shared(Arc::new(Field::new(
709            DataType::Chars,
710            "s",
711            Value::from("shared"),
712        )));
713        record.push_owned(Field::new(DataType::Digit, "o", Value::from(10)));
714
715        let owned_record = record.into_owned_record();
716        assert_eq!(owned_record.items.len(), 2);
717        assert_eq!(owned_record.items[0].get_name(), "s");
718        assert_eq!(owned_record.items[1].get_name(), "o");
719    }
720
721    // ========== New convenience API tests ==========
722
723    #[test]
724    fn test_record_len_and_is_empty() {
725        let mut record = DataRecord::default();
726        assert!(record.is_empty());
727        assert_eq!(record.len(), 0);
728
729        record.append(FieldStorage::from_chars("a", "1"));
730        assert!(!record.is_empty());
731        assert_eq!(record.len(), 1);
732    }
733
734    #[test]
735    fn test_from_vec_datafield() {
736        let fields: Vec<DataField> = vec![
737            DataField::from_chars("a", "1"),
738            DataField::from_chars("b", "2"),
739        ];
740        let record = DataRecord::from(fields);
741        assert_eq!(record.len(), 2);
742        assert!(record.field("a").is_some());
743        assert!(record.field("b").is_some());
744    }
745
746    #[test]
747    fn test_from_single_datafield() {
748        let field = DataField::from_chars("name", "Alice");
749        let record = DataRecord::from(field);
750        assert_eq!(record.len(), 1);
751        assert!(record.field("name").is_some());
752    }
753
754    #[test]
755    fn test_append_generic() {
756        let mut record = DataRecord::default();
757
758        // Append a DataField directly (auto-converts via Into<FieldStorage>)
759        record.append(DataField::from_chars("a", "1"));
760
761        // Append a FieldStorage directly (still works)
762        record.append(FieldStorage::from_chars("b", "2"));
763
764        // Append via Arc (auto-converts to Shared)
765        let arc_field = Arc::new(DataField::from_chars("c", "3"));
766        record.append(arc_field);
767
768        assert_eq!(record.len(), 3);
769        assert!(record.items[0].is_owned());
770        assert!(record.items[1].is_owned());
771        assert!(record.items[2].is_shared());
772    }
773
774    #[test]
775    fn test_push_alias() {
776        let mut record = DataRecord::default();
777        record.push(DataField::from_chars("a", "1"));
778        record.push(FieldStorage::from_chars("b", "2"));
779        assert_eq!(record.len(), 2);
780    }
781
782    #[test]
783    fn test_get_field_by_name() {
784        let record = DataRecord::from(vec![
785            DataField::from_chars("name", "Alice"),
786            DataField::from_digit("age", 30),
787        ]);
788
789        let field = record.get_field("name");
790        assert!(field.is_some());
791        assert_eq!(field.unwrap().get_name(), "name");
792
793        assert!(record.get_field("missing").is_none());
794    }
795
796    #[test]
797    fn test_get_field_mut_by_name() {
798        let mut record = DataRecord::from(vec![DataField::from_chars("name", "Alice")]);
799
800        if let Some(field) = record.get_field_mut("name") {
801            field.set_name("renamed");
802        }
803        assert_eq!(
804            record.get_field("renamed").map(|f| f.get_name()),
805            Some("renamed")
806        );
807    }
808
809    #[test]
810    fn test_field_mut() {
811        let mut record = DataRecord::from(vec![DataField::from_chars("name", "Alice")]);
812
813        let storage = record.field_mut("name");
814        assert!(storage.is_some());
815    }
816
817    #[test]
818    fn test_fields_iterator() {
819        let record = DataRecord::from(vec![
820            DataField::from_chars("a", "1"),
821            DataField::from_chars("b", "2"),
822            DataField::from_chars("c", "3"),
823        ]);
824
825        let names: Vec<&str> = record.fields().map(|f| f.get_name()).collect();
826        assert_eq!(names, vec!["a", "b", "c"]);
827    }
828
829    #[test]
830    fn test_fields_mut_iterator() {
831        let mut record = DataRecord::from(vec![DataField::from_chars("a", "1")]);
832
833        for field in record.fields_mut() {
834            field.set_name("renamed");
835        }
836        assert_eq!(
837            record.get_field("renamed").map(|f| f.get_name()),
838            Some("renamed")
839        );
840    }
841}