Skip to content

Commit ec56c2b

Browse files
fatbobmanclaude
andcommitted
feat: Add convenience factory methods for ColumnOutputTypes
Added static factory methods for all column output types to provide cleaner syntax in custom mappings: - Non-optional variants: `.string()`, `.double()`, `.int()`, `.date()`, `.bool()`, `.url()`, `.percentage()` - Optional variants: preserve nil values for Column's nilHandling mechanism - All methods properly documented with usage examples - Maintains clear separation between type creation and nil handling strategy This enhancement simplifies column declarations in custom mappings while maintaining the flexibility of the Column API's defaultValue mechanism. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent d7e99c9 commit ec56c2b

File tree

1 file changed

+300
-0
lines changed

1 file changed

+300
-0
lines changed

Sources/Objects2XLSX/Column/ColumnOutputType.swift

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,303 @@ public struct PercentageColumnType: ColumnOutputTypeProtocol {
365365
PercentageColumnType(PercentageColumnConfig(value: config.value ?? value, precision: config.precision))
366366
}
367367
}
368+
369+
extension ColumnOutputTypeProtocol where Self == TextColumnType {
370+
/// Creates a TextColumnType from a non-optional String value.
371+
///
372+
/// This convenience factory method provides a cleaner syntax for creating
373+
/// text column types in custom mappings.
374+
///
375+
/// Example usage:
376+
/// ```swift
377+
/// Column(name: "Status", keyPath: \.status) { status in
378+
/// .string(status.rawValue.uppercased())
379+
/// }
380+
/// ```
381+
///
382+
/// - Parameter text: The non-optional String value to display in the cell
383+
/// - Returns: A configured TextColumnType instance
384+
public static func string(_ text: String) -> TextColumnType {
385+
.init(TextColumnConfig(value: text))
386+
}
387+
}
388+
389+
extension ColumnOutputTypeProtocol where Self == DateColumnType {
390+
/// Creates a DateColumnType from a non-optional Date value with timezone configuration.
391+
///
392+
/// This convenience factory method simplifies date column creation in custom mappings
393+
/// while providing timezone control for accurate date representation.
394+
///
395+
/// Example usage:
396+
/// ```swift
397+
/// Column(name: "Last Modified", keyPath: \.timestamp) { timestamp in
398+
/// .date(timestamp, timeZone: .utc)
399+
/// }
400+
/// ```
401+
///
402+
/// - Parameters:
403+
/// - date: The non-optional Date value to display
404+
/// - timeZone: The timezone for date interpretation (default: current system timezone)
405+
/// - Returns: A configured DateColumnType instance
406+
public static func date(_ date: Date, timeZone: TimeZone = .current) -> DateColumnType {
407+
.init(DateColumnConfig(value: date, timeZone: timeZone))
408+
}
409+
}
410+
411+
extension ColumnOutputTypeProtocol where Self == BoolColumnType {
412+
/// Creates a BoolColumnType from a non-optional Bool value.
413+
///
414+
/// This convenience factory method provides a cleaner syntax for creating
415+
/// boolean column types in custom mappings. Uses default boolean expressions
416+
/// and case strategy settings.
417+
///
418+
/// Example usage:
419+
/// ```swift
420+
/// Column(name: "Is Premium", keyPath: \.subscriptionLevel) { level in
421+
/// .bool(level == .premium)
422+
/// }
423+
/// ```
424+
///
425+
/// - Parameter value: The non-optional Bool value to display
426+
/// - Returns: A configured BoolColumnType instance with default formatting
427+
public static func bool(_ value: Bool) -> BoolColumnType {
428+
.init(BoolColumnConfig(value: value))
429+
}
430+
}
431+
432+
extension ColumnOutputTypeProtocol where Self == URLColumnType {
433+
/// Creates a URLColumnType from a non-optional URL value.
434+
///
435+
/// This convenience factory method provides a cleaner syntax for creating
436+
/// URL column types in custom mappings. URLs are displayed as their absolute
437+
/// string representation.
438+
///
439+
/// Example usage:
440+
/// ```swift
441+
/// Column(name: "Documentation", keyPath: \.productId) { id in
442+
/// .url(URL(string: "https://docs.example.com/\(id)")!)
443+
/// }
444+
/// ```
445+
///
446+
/// - Parameter url: The non-optional URL value to display
447+
/// - Returns: A configured URLColumnType instance
448+
public static func url(_ url: URL) -> URLColumnType {
449+
.init(URLColumnConfig(value: url))
450+
}
451+
}
452+
453+
extension ColumnOutputTypeProtocol where Self == DoubleColumnType {
454+
/// Creates a DoubleColumnType from a non-optional Double value.
455+
///
456+
/// This convenience factory method provides a cleaner syntax for creating
457+
/// numeric column types in custom mappings with floating-point values.
458+
///
459+
/// Example usage:
460+
/// ```swift
461+
/// Column(name: "Calculated Price", keyPath: \.basePrice) { price in
462+
/// .double(price * 1.2) // Add 20% markup
463+
/// }
464+
/// ```
465+
///
466+
/// - Parameter value: The non-optional Double value to display
467+
/// - Returns: A configured DoubleColumnType instance
468+
public static func double(_ value: Double) -> DoubleColumnType {
469+
.init(DoubleColumnConfig(value: value))
470+
}
471+
}
472+
473+
extension ColumnOutputTypeProtocol where Self == IntColumnType {
474+
/// Creates an IntColumnType from a non-optional Int value.
475+
///
476+
/// This convenience factory method provides a cleaner syntax for creating
477+
/// integer column types in custom mappings.
478+
///
479+
/// Example usage:
480+
/// ```swift
481+
/// Column(name: "Days Until Due", keyPath: \.dueDate) { date in
482+
/// .int(Calendar.current.dateComponents([.day], from: Date(), to: date).day ?? 0)
483+
/// }
484+
/// ```
485+
///
486+
/// - Parameter value: The non-optional Int value to display
487+
/// - Returns: A configured IntColumnType instance
488+
public static func int(_ value: Int) -> IntColumnType {
489+
.init(IntColumnConfig(value: value))
490+
}
491+
}
492+
493+
extension ColumnOutputTypeProtocol where Self == PercentageColumnType {
494+
/// Creates a PercentageColumnType from a non-optional Double value with precision control.
495+
///
496+
/// This convenience factory method provides a cleaner syntax for creating
497+
/// percentage column types in custom mappings. Values should be provided as
498+
/// decimals (0.5 = 50%).
499+
///
500+
/// Example usage:
501+
/// ```swift
502+
/// Column(name: "Completion", keyPath: \.completed) { completed in
503+
/// .percentage(completed / total, precision: 1) // Shows as "50.0%"
504+
/// }
505+
/// ```
506+
///
507+
/// - Parameters:
508+
/// - value: The non-optional percentage value as decimal (0.5 = 50%)
509+
/// - precision: Number of decimal places to display (default: 2)
510+
/// - Returns: A configured PercentageColumnType instance
511+
public static func percentage(_ value: Double, precision: Int = 2) -> PercentageColumnType {
512+
.init(PercentageColumnConfig(value: value, precision: precision))
513+
}
514+
}
515+
516+
// MARK: - Optional Support
517+
518+
extension ColumnOutputTypeProtocol where Self == TextColumnType {
519+
/// Creates a TextColumnType from an optional String value.
520+
///
521+
/// This convenience factory method handles optional String values in custom mappings.
522+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
523+
///
524+
/// Example usage:
525+
/// ```swift
526+
/// Column(name: "Notes", keyPath: \.metadata) { metadata in
527+
/// .string(metadata["notes"]) // Returns String?
528+
/// }
529+
/// .defaultValue("No notes")
530+
/// ```
531+
///
532+
/// - Parameter text: The optional String value to display
533+
/// - Returns: A configured TextColumnType instance that preserves nil
534+
public static func string(_ text: String?) -> TextColumnType {
535+
.init(TextColumnConfig(value: text))
536+
}
537+
}
538+
539+
extension ColumnOutputTypeProtocol where Self == DoubleColumnType {
540+
/// Creates a DoubleColumnType from an optional Double value.
541+
///
542+
/// This convenience factory method handles optional numeric values in custom mappings.
543+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
544+
///
545+
/// Example usage:
546+
/// ```swift
547+
/// Column(name: "Discount", keyPath: \.couponCode) { code in
548+
/// .double(discountMap[code]) // Returns Double?
549+
/// }
550+
/// .defaultValue(0.0)
551+
/// ```
552+
///
553+
/// - Parameter value: The optional Double value to display
554+
/// - Returns: A configured DoubleColumnType instance that preserves nil
555+
public static func double(_ value: Double?) -> DoubleColumnType {
556+
.init(DoubleColumnConfig(value: value))
557+
}
558+
}
559+
560+
extension ColumnOutputTypeProtocol where Self == IntColumnType {
561+
/// Creates an IntColumnType from an optional Int value.
562+
///
563+
/// This convenience factory method handles optional integer values in custom mappings.
564+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
565+
///
566+
/// Example usage:
567+
/// ```swift
568+
/// Column(name: "Priority", keyPath: \.tags) { tags in
569+
/// .int(tags.first { $0.type == .priority }?.value) // Returns Int?
570+
/// }
571+
/// .defaultValue(0)
572+
/// ```
573+
///
574+
/// - Parameter value: The optional Int value to display
575+
/// - Returns: A configured IntColumnType instance that preserves nil
576+
public static func int(_ value: Int?) -> IntColumnType {
577+
.init(IntColumnConfig(value: value))
578+
}
579+
}
580+
581+
extension ColumnOutputTypeProtocol where Self == DateColumnType {
582+
/// Creates a DateColumnType from an optional Date value with timezone configuration.
583+
///
584+
/// This convenience factory method handles optional date values in custom mappings.
585+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
586+
///
587+
/// Example usage:
588+
/// ```swift
589+
/// Column(name: "Completed At", keyPath: \.status) { status in
590+
/// .date(status.isCompleted ? status.completionDate : nil, timeZone: .utc)
591+
/// }
592+
/// .defaultValue(Date())
593+
/// ```
594+
///
595+
/// - Parameters:
596+
/// - date: The optional Date value to display
597+
/// - timeZone: The timezone for date interpretation (default: current system timezone)
598+
/// - Returns: A configured DateColumnType instance that preserves nil
599+
public static func date(_ date: Date?, timeZone: TimeZone = .current) -> DateColumnType {
600+
.init(DateColumnConfig(value: date, timeZone: timeZone))
601+
}
602+
}
603+
604+
extension ColumnOutputTypeProtocol where Self == BoolColumnType {
605+
/// Creates a BoolColumnType from an optional Bool value.
606+
///
607+
/// This convenience factory method handles optional boolean values in custom mappings.
608+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
609+
///
610+
/// Example usage:
611+
/// ```swift
612+
/// Column(name: "Verified", keyPath: \.profile) { profile in
613+
/// .bool(profile?.isVerified) // Returns Bool?
614+
/// }
615+
/// .defaultValue(false)
616+
/// ```
617+
///
618+
/// - Parameter value: The optional Bool value to display
619+
/// - Returns: A configured BoolColumnType instance that preserves nil
620+
public static func bool(_ value: Bool?) -> BoolColumnType {
621+
.init(BoolColumnConfig(value: value))
622+
}
623+
}
624+
625+
extension ColumnOutputTypeProtocol where Self == URLColumnType {
626+
/// Creates a URLColumnType from an optional URL value.
627+
///
628+
/// This convenience factory method handles optional URL values in custom mappings.
629+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
630+
///
631+
/// Example usage:
632+
/// ```swift
633+
/// Column(name: "Profile Link", keyPath: \.username) { username in
634+
/// .url(URL(string: "https://example.com/\(username)")) // Might fail
635+
/// }
636+
/// .defaultValue(URL(string: "https://example.com")!)
637+
/// ```
638+
///
639+
/// - Parameter url: The optional URL value to display
640+
/// - Returns: A configured URLColumnType instance that preserves nil
641+
public static func url(_ url: URL?) -> URLColumnType {
642+
.init(URLColumnConfig(value: url))
643+
}
644+
}
645+
646+
extension ColumnOutputTypeProtocol where Self == PercentageColumnType {
647+
/// Creates a PercentageColumnType from an optional Double value with precision control.
648+
///
649+
/// This convenience factory method handles optional percentage values in custom mappings.
650+
/// Nil values are preserved and can be handled by Column's nilHandling mechanism.
651+
///
652+
/// Example usage:
653+
/// ```swift
654+
/// Column(name: "Success Rate", keyPath: \.metrics) { metrics in
655+
/// .percentage(metrics?.successRate, precision: 1) // Returns Double?
656+
/// }
657+
/// .defaultValue(0.0) // Shows as "0.0%"
658+
/// ```
659+
///
660+
/// - Parameters:
661+
/// - value: The optional percentage value as decimal (0.5 = 50%)
662+
/// - precision: Number of decimal places to display (default: 2)
663+
/// - Returns: A configured PercentageColumnType instance that preserves nil
664+
public static func percentage(_ value: Double?, precision: Int = 2) -> PercentageColumnType {
665+
.init(PercentageColumnConfig(value: value, precision: precision))
666+
}
667+
}

0 commit comments

Comments
 (0)