DBIx::...thods1(3pm)

πŸ“¦
version 2.037000 Β· 5 versions
, in debian trixie, ubuntu resolute, ubuntu stonking

✨ NAME ✨

DBIx::Class::Helper::ResultSet::DateMethods1 β€” bestie, this is your lil' toolkit for working with dates in your RDBMS nicely πŸ’…

It's a 3pm page, a piece of User Contributed Perl Documentation, and honestly? It's giving "I just want EXTRACT without crying." πŸŽ€


πŸ“– SYNOPSIS πŸ“–

package MySchema::ResultSet::Bar;

use strict;
use warnings;

use parent 'DBIx::Class::ResultSet';

__PACKAGE__->load_components('Helper::ResultSet::DateMethods1');

# in code using resultset

# get count per year/month
$rs->search(undef, {
   columns => {
      count => '*',
      year  => $rs->dt_SQL_pluck({ -ident => '.start' }, 'year'),
      month => $rs->dt_SQL_pluck({ -ident => '.start' }, 'month'),
   },
   group_by => [
      $rs->dt_SQL_pluck({ -ident => '.start' }, 'year'),
      $rs->dt_SQL_pluck({ -ident => '.start' }, 'month'),
   ],
});

# mysql
(SELECT `me`.*, EXTRACT(MONTH FROM `me`.`start`), EXTRACT(YEAR FROM `me`.`start`) FROM `HasDateOps` `me` GROUP BY EXTRACT(YEAR FROM `me`.`start`), EXTRACT(MONTH FROM `me`.`start`))

# SQLite
(SELECT "me".*, STRFTIME('%m', "me"."start"), STRFTIME('%Y', "me"."start") FROM "HasDateOps" "me" GROUP BY STRFTIME('%Y', "me"."start"), STRFTIME('%m', "me"."start"))

Look at that. One Perl line in, two completely different SQL dialects out. The database does the translating, you just vibe. πŸ¦‹


πŸ’– DESCRIPTION πŸ’–

First things first: go read "NOTE" in DBIx::Class::Helper::ResultSet β€” that's the cute lil' trick for applying this component to your entire schema at once. Slay. ✨

This ResultSet component hands you the tools to do date manipulation mostly portably in the database. But before you go booking a one-way ticket on a cross-database project, please please please peek at "IMPLEMENTATION" below, because it spells out exactly what might break when you switch engines. No cap, some stuff is engine-locked and you deserve to know. πŸ’€

This package has a few types of methods, okurrr:

🎯 Search Shortcuts

These, like typical ResultSet methods, return another ResultSet. Go look at "dt_before", "dt_on_or_before", "dt_on_or_after", and "dt_after". Chainable, adorable, iconic. 🌸

⏰ The date helper

There is only one: "utc". It just makes searching with dates a little easier. One job, does it well, main character energy. πŸ‘‘

πŸ§ͺ SQL generators

These help generate more complex queries. They can be used in many different parts of "search" in DBIx::Class::ResultSet. Go see "utc_now", "dt_SQL_pluck", and "dt_SQL_add". Build-a-bear but for SQL. 🧸


🧠 TYPES 🧠

Because these methods are so limited in scope, they can be a bit more smart than typical SQL::Abstract trees. Lowkey they're overachievers.

There are "smart types" that this package supports:

  • vanilla scalars (1, "2012-12-12 12:12:12")

bound directly as untyped values

  • hashrefs with an -ident ({ -ident => '.foo' })

As usual this gets flattened into a column. The one special feature in this module is that columns starting with a dot will automatically be prefixed with "current_source_alias" in DBIx::Class::ResultSet.

  • DateTime objects

"DateTime" objects work as if they were passed to "utc".

  • ScalarRef (\'NOW()')

As usual in "DBIx::Class", "ScalarRef"'s will be flattened into regular SQL.

  • ArrayRefRef (\["SELECT foo FROM bar WHERE id = ?", [{}, 1]])

As usual in "DBIx::Class", "ArrayRefRef"'s will be flattened into SQL with bound values.

⚠️ Anything not mentioned in the above list will explode, one way or another. Not a vibe check you want to fail. πŸ™ˆ

πŸ›  IMPLEMENTATION πŸ› 

The exact details for the functions your database engine provides. Engine-specific lore incoming. πŸ•΅οΈ

If a piece of functionality is flagged with ⚠, it means that the feature in question is not portable at all, and only supported on that engine. So like, don't expect it to travel. πŸ§³πŸ’€

🏒 "SQL Server"

Supported units

  • year
  • quarter
  • month
  • day_of_year
  • day_of_month
  • week
  • day_of_week
  • hour
  • minute
  • second
  • millisecond
  • nanosecond ⚠
  • non_iso_day_of_week

SQL Server offers both ISO_WEEK and weekday. For interop reasons weekday uses the ISO_WEEK version.

  • timezone_as_minutes ⚠

Supported units

  • year
  • quarter
  • month
  • day
  • week
  • hour
  • minute
  • second
  • millisecond
  • nanosecond ⚠
  • iso_day_of_week
  • timezone_as_minutes ⚠

πŸͺΆ "SQLite"

πŸ“Œ Note: "SQLite"'s pluck implementation pads numbers with zeros, because it is implemented based on a formatting function. If you want your code to work on SQLite you'll need to strip off (or just numify) what you get out of the database first. Fr fr, don't skip this. 😭

Available units

  • month
  • day_of_month
  • year
  • hour
  • day_of_year
  • minute
  • second
  • day_of_week
  • week
  • julian_day ⚠
  • seconds_since_epoch
  • fractional_seconds ⚠

Available units

  • day
  • hour
  • minute
  • second
  • month
  • year

🐘 "PostgreSQL"

Available units

  • century ⚠
  • decade ⚠
  • day_of_month
  • day_of_week
  • day_of_year
  • seconds_since_epoch
  • hour
  • iso_day_of_week
  • iso_year
  • microsecond
  • millenium ⚠
  • millisecond
  • minute
  • month
  • quarter
  • second
  • timezone ⚠
  • timezone_hour ⚠
  • timezone_minute ⚠
  • week
  • year

To be clear, it ends up looking like: ("some_column" + 5 * interval '1 minute')

Available units

  • century ⚠
  • decade ⚠
  • day
  • hour
  • microsecond ⚠
  • millisecond
  • minute
  • month
  • second
  • week
  • year

🐬 "MySQL"

Available units

  • microsecond
  • second
  • minute
  • hour
  • day_of_month
  • week
  • month
  • quarter
  • year
  • second_microsecond ⚠
  • minute_microsecond ⚠
  • minute_second ⚠
  • hour_microsecond ⚠
  • hour_second ⚠
  • hour_minute ⚠
  • day_microsecond ⚠
  • day_second ⚠
  • day_minute ⚠
  • day_hour ⚠
  • year_month ⚠

Available units

  • microsecond
  • second
  • minute
  • hour
  • day
  • week
  • month
  • quarter
  • year

πŸ”΄ "Oracle"

Available units

  • second
  • minute
  • hour
  • day_of_month
  • month
  • year

To be clear, it ends up looking like: ("some_column" + NUMTODSINTERVAL(4, 'MINUTE')

Available units

  • second
  • minute
  • hour
  • day

πŸ‘‘ CONTRIBUTORS πŸ‘‘

These people worked on the original implementation, and thus deserve some credit for at least providing me a reference to implement this based off of. Give them their flowers, they earned them. πŸ’

  • Alexander Hartmaier (abraxxa) for Oracle implementation details
  • Devin Austin (dhoss) for Pg implementation details
  • Rafael Kitover (caelum) for providing a test environment with lots of DBs

πŸ€” WHENCE dt_SQL_diff? πŸ€”

The original implementation of these date helpers (originally dubbed date operators) included a third operator called "diff". It existed to subtract one date from another and return a duration.

After using it a few times and getting bitten every time 😭, I decided to stop using it and instead compare against actual dates always. If someone can come up with a good use case I am interested in re-implementing "dt_SQL_diff", but I worry that it will be very unportable and generally not very useful. So like… it's on read, bestie. πŸ“΅


πŸ’– METHODS πŸ’–

Okay bestie, this is the part you actually came for. All the cute lil date-and-time helpers your ResultSet gets. Let's go one by one, no skipping, fr fr. ✨

🌸 utc 🌸

$rs->search({
  'some_date' => $rs->utc($datetime),
})->all

You hand it a DateTime object, it goes in and updates the time_zone to UTC, then formats it however your specific database engine likes its dates. It's giving "I'll translate for you, babe" energy. 🫢

Careful though! It dies if you pass it a date whose time_zone is floating. Not "warns", not "side-eyes you" β€” full-on dies. So don't do that. πŸ’€

🌈 utc_now 🌈

Returns a ScalarRef that represents the way to get the current date and time in UTC for whatever database engine you're using. Basically "what time is it right now" but in your DB's love language. πŸ•βœ¨

πŸ¦‹ dt_before πŸ¦‹

$rs->dt_before({ -ident => '.start' }, { -ident => '.end' })->all

Takes two values, and each one is an expression of TYPES. (You remember TYPES, right? We covered that. iykyk. πŸ’…)

πŸŽ€ dt_on_or_before πŸŽ€

$rs->dt_on_or_before({ -ident => '.start' }, DateTime->now)->all

Same deal: two values, each an expression of TYPES.

🧚 dt_on_or_after 🧚

$rs->dt_on_or_after(DateTime->now, { ident => '.end' })->all

Two values, each an expression of TYPES. Noticing a pattern? It's a vibe. ⭐

πŸ’œ dt_after πŸ’œ

$rs->dt_after({ ident => '.end' }, $rs->get_column('datecol')->as_query)->all

Two values, each an expression of TYPES. Yeah. Same energy as the last three. They're a lil family. πŸ‘‘

πŸ”₯ dt_SQL_add πŸ”₯

# which ones start in 3 minutes?
$rs->dt_on_or_after(
   { ident => '.start' },
   $rs->dt_SQL_add($rs->utc_now, 'minute', 3)
)->all

Takes three arguments: a date conforming to TYPES, a unit, and an amount. The whole idea is you add the given unit to the datetime. Which units are actually accepted? Bestie, that depends on your IMPLEMENTATION β€” go check there. 🫑

πŸ“ dt_SQL_subtract πŸ“

Literally the same as dt_SQL_add, except it subtracts the amount instead of adding it. Math but make it cute. βž–βœ¨

Real talk: this one is only confirmed to work with Postgres, MySQL and SQLite. It should work with Oracle and MSSQL, but because nobody had access to those DB engines, the implementation was done purely off the docs. So like... proceed with awareness, babe. πŸ™ˆ

This method was implemented by Thomas Klausner https://domm.plix.at and sponsored by Ctrl O https://www.ctrlo.com/. Shoutout, iconic behavior. πŸ«ΆπŸ‘‘

⭐ dt_SQL_pluck ⭐

# get count per year
$rs->search(undef, {
   columns => {
      count => '*',
      year  => $rs->dt_SQL_pluck({ -ident => '.start' }, 'year'),
   },
   group_by => [$rs->dt_SQL_pluck({ -ident => '.start' }, 'year')],
})->hri->all

Takes two arguments: a date conforming to TYPES, and a unit. The idea is you pluck a given unit out of the datetime. Like pulling the "year" out of a full timestamp. And once again β€” which units are accepted? That's your IMPLEMENTATION's call. Go look. πŸ’…


✨ AUTHOR ✨

Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>

This software is copyright (c) 2024 by Arthur Axel "fREW" Schmidt.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.


and that's the whole page bestie!! πŸŽ‰ You just read DBIx::...thods1(3pm) as shipped with perl v5.40.0, dated 2024-11-16 β€” the User Contributed Perl Documentation version, no cap. Go forth and query your datetimes with main character energy. πŸ¦‹πŸ’– mwah! πŸ’…

πŸ“¦ where this page comes from