NAME

App::FargateStack::Builder::Utils

SYNOPSIS

# can be used as a role with Role::Tiny or you can import methods

with 'App::FargateStack::Builder::Utils';

use App::FargateStack::Builder::Utils qw(choose log_die);

METHODS AND SUBROUTINES

choose

A clever little helper that makes your code look awesome. Instead of this:

my $foo;

if ( $bar ) {
  $foo = 'biz';
}
else {
  $foo = 'baz';
}

my $foo = choose {
  return 'biz'
    if $bar;

  return 'baz';
}

The example above would probably be handled by a ternary, but imagine more complex logic and you'll see why the assignment and declaration sometimes get separated. Since I hate to do that...choose was born.

normalize_timestamp

fetch_*

Use the fetch_* methods to retrieve an instance of one of the AWS API classes. The fetch method caches class instances and instantiates them if necessary by providing common arguments (like profile).

my $ecs = $self->fetch_ecs;

normalize_time_range

my ($from_ms, $to_ms) = normalize_time_range($start, $end);

Normalizes a human-friendly time range into Unix epoch timestamps in **milliseconds**.

Given a required $start and an optional $end, this routine parses each value into epoch seconds (using "str2time" in Date::Parse for absolute dates, or a compact “duration” syntax), validates the range, and returns a two-element list: (start_ms, end_ms_or_undef).

Returns an empty list if $start is false/undefined (useful for “no time filter” cases).

Arguments

$start (required)

Either:

  • A relative duration: /^\d+[dmh]$/i

    Examples: "5m" (5 minutes), "2h" (2 hours), "7d" (7 days). Zero durations (e.g., "0m") are rejected.

  • An absolute date/time string parsed by str2time.

    Examples: "2025-08-12 08:00", "2025-08-12T08:00:00Z", RFC-822 style, etc. If no timezone is present, parsing uses the local timezone.

$end (optional)

Same accepted formats as $start. If omitted, the end of the range is left undefined.

Behavior

  • A single “now” is captured at the start of the call, so when both $start and $end are durations (e.g., "15m" and "5m") they are evaluated relative to the same instant.

  • Validation:

    • start is in the future if $start resolves after “now”.

    • end is in the future if $end resolves after “now”.

    • start end> if both are defined and $start resolves after $end.

    • duration cannot be zero for 0d, 0h, or 0m.

    • unrecognized date format: [VALUE] if str2time cannot parse.

Returns

A two-element list in **milliseconds since the Unix epoch**:

( $start_ms, $end_ms_or_undef )

List context is expected. In scalar context, Perl will return the last element of the list (which may be undef); don’t rely on that.

Examples

# Last 15 minutes, open-ended end:
my ($from, $to) = normalize_time_range('15m');         # $to is undef

# Absolute window (local timezone if none given):
my ($from, $to) = normalize_time_range('2025-08-12 00:00',
                                       '2025-08-12 06:00');

# Mixed: from 2 hours ago to 30 minutes ago:
my ($from, $to) = normalize_time_range('2h', '30m');

Notes

  • The return values are in milliseconds. Some AWS APIs expect seconds; divide by 1000 if needed.

  • Duration units supported are days (d), hours (h), and minutes (m). Seconds/weeks are not accepted.

  • Absolute parsing is delegated to "str2time" in Date::Parse; pass a timezone (e.g., trailing Z) to avoid local-TZ assumptions.

jmespath_mapping

my $expr = jmespath_mapping($prefix, $elems, $ucfirst);

Builds a JMESPath object-projection expression by combining a prefix (e.g., 'tasks[]') with a field mapping rendered in JMESPath syntax, such as {TaskArn:taskArn,StartedAt:startedAt}. Quotes are stripped from the JSON representation to form valid JMESPath.

Arguments

  • $prefix (Str)

    A JMESPath prefix to project over, e.g., 'tasks[]' or 'events[]'.

  • $elems (HashRef|ArrayRef)

    Either a hashref mapping output keys to source field names, or a list of source field names. When a list/arrayref is provided, keys are auto-generated via camel-casing utilities (see $ucfirst below).

    Examples:

    # HashRef form (used as-is):
    { TaskArn => 'taskArn', StartedAt => 'startedAt' }
    
    # ArrayRef form (auto-mapped):
    [ 'taskArn', 'startedAt', 'stoppedAt' ]
  • $ucfirst (Bool, optional; default 0)

    Controls how output keys are generated when $elems is not a hashref.

    - If false (default), keys use lower camel case via toCamelCase(). - If true, keys use upper camel case via ToCamelCase().

    When $elems is a hashref, this flag is ignored.

Returns

(Str) A JMESPath expression of the form:

"$prefix.{Key1:field1,Key2:field2,...}"

For example:

jmespath_mapping('tasks[]', [ 'taskArn', 'startedAt' ], 1)
  => 'tasks[].{TaskArn:taskArn,StartedAt:startedAt}'

jmespath_mapping('events[]', { Id => 'eventID', Time => 'eventTime' }, 0)
  => 'events[].{Id:eventID,Time:eventTime}'

Notes

- When $elems is a hashref, it is used directly as the key->field map. - When $elems is a list/arrayref, the keys are derived from each field name using toCamelCase() or ToCamelCase() depending on $ucfirst. - The need to handle both camel case styles exists because AWS services and JMESPath queries are not consistent in field naming conventions. Some AWS APIs return structures with lower camel case keys (e.g., taskArn), while others or UI tools expect upper camel case (e.g., TaskArn). This helper accommodates both without requiring the caller to manually reformat keys. - Internally, the method JSON-encodes the map and then removes double quotes to yield valid JMESPath object projection syntax.

See Also

JMESPath specification for object projections.

AUTHOR

Rob Lauer - <rlauer@treasurersbriefcase.com>

SEE ALSO

Role::Tiny

1 POD Error

The following errors were encountered while parsing the POD:

Around line 601:

Non-ASCII character seen before =encoding in '“duration”'. Assuming UTF-8