Today I Learned

A Hashrocket project

Ready to join Hashrocket? Find Openings here and apply today.

Resize Window Keyboard Shortcuts in Windows 10

After using Magnet, a window manager in OSX, I remembered hearing that there was a similar facility built into Windows. Turns out, they are very easy-to-remember shortcuts for resizing windows.

  • Win + Right Arrow - Snap to right half of screen**
  • Win + Left Arrow - Snap to left half of screen**
  • Win + Up Arrow - Maximize current window
  • Win + Down Arrow - Minimize window if not currently maximized

**(will maximize the window if it is currently split on the opposite side of the screen)

There’s a few others too, but these 4 I’m finding super useful. If you’re interested in other Windows shortcuts, I found some other cool ones in this Lifewire article

Select first element from array_agg

It’s as simple as:

select zip_code, (array_agg(company_name))[1]
from locations
group by zip_code
;

 zip_code |        array_agg
----------+--------------------------
 90210    | In-N-out
 46368    | Johnny's Round the Clock
(2 rows)

source:

create table locations (
  id bigint generated by default as identity primary key,
  zip_code text not null,
  company_name text not null
);

insert into locations (zip_code, company_name) values 
  ('46368', 'Johnny''s Round the Clock'),
  ('90210', 'In-N-out'),
  ('46368', 'Albanese Candy');

Add global variables in typescript

In this example, we need to put placeholder values on global.window to allow us to use Ruby on Rails’ ActionCable websocket framework where no window exists:

// Fix to prevent crash from ActionCable
global.window.removeEventListener = () => {};
global.window.addEventListener = () => {};

But we need to add a type:

declare global {
    var window: {
        addEventListener(): void;
        removeEventListener(): void;
    };
}

HTML Tab Index Gotcha

The tabindex attribute on HTML elements behaves differently than one might first expect.

The default tabindex for an element is 0, all elements with this index will be tabbed to in the order they appear in the document.

Giving an element a positive tabindex will prioritize it over all elements with a 0 index, in the order they appear.

Consider the following code

<ul>
  {
    [0,1,2].map((n) => (
      <li><button tabindex={n}>{n}</button></li>
    )
  }
</ul>

The order that the buttons will be focused when tabbing is 1, then 2, and finally 0.

Control video playback with keyboard controls

For a macOS app to show up in the Now Playing media center (which enables media keys [F7, F8, F9]) you just need to configure the MPNowPlayingInfoCenter’s playbackState

func play() {
  self.player.play()
  MPNowPlayingInfoCenter.default().playbackState = .playing
}

And then subscribe to RemoteCommand changes:

let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
  self.player.pause()
  MPNowPlayingInfoCenter.default().playbackState = .paused
  return .success
}
commandCenter.playCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
  self.player.play()
  MPNowPlayingInfoCenter.default().playbackState = .playing
  return .success
}
Screen Shot 2021-12-26 at 12 05 47

Keep 5 most recent files in a directory

One can keep the most recent n files in a directory with just three shell programs: ls, tail, and xargs.

Here is an example to use in a nightly database backup cron job:

#!/bin/bash
# Keep last 5 files ending in .dump
# Don't forget to 

# Installation
# 1. cp pg-backups.sh /usr/local/bin/
# 2. chmod u+x /usr/local/bin/pg-backups.sh
# 3. Set the DB variable
# 4. Set the BACKUP_DIR variable

# Example usage for cron to run at 4:05 am every day:
# 5 4 * * * /usr/local/bin/pg-backups.sh

DB=mydatabase
BACKUP_DIR=/mnt/object/production/db-backups

DATE=$(date "+%Y-%m-%d_%H%M")
pg_dump -Fc $DB > $BACKUP_DIR/$DATE.dump

/bin/ls -t $BACKUP_DIR/*.dump | tail +6 | xargs rm

Be Careful with JavaScript Numbers

Today I Learned that you need to be careful when working with numbers in JavaScript. This is because of the way that JavaScript implements the Number type.

The JavaScript Number type is a double-precision 64-bit binary format IEEE 754 value, like double in Java or C#. This means it can represent fractional values …

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number

Take for example the following Ruby snippet:

> 2 / 5
=> 0

Our division here returns 0, which is what I expected. And if you want the remainder, you can get it with the modulus operator %

Now here’s the same snippet in JavaScript, which returns a double-precision number that is not zero

> 2 / 5
0.5

If you’re looking to do integer-like division in JavaScript, here’s a few ways you can accomplish that:

> Math.floor(2 / 5)
0

> Math.trunc(2 / 5)
0

> (2 / 5) >> 0
0

Docs

Here’s a callback to another JavaScript number TIL 😅

https://til.hashrocket.com/posts/e04ffe1d76-because-javascript

Use created_at in Ecto

You can use created_at in Ecto/phoenix app with timestamps/1. When migrating data from a rails application to a phoenix application you will have many tables with a created_at column.

defmodule Phoenix.Accounts.User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :email, :string
    field :password, :string, virtual: true, redact: true
    field :hashed_password, :string, redact: true
    field :confirmed_at, :utc_datetime

    timestamps(inserted_at: :created_at, type: :utc_datetime)
  end

end

Ruby Squeeze

Ruby has a method to remove repeating characters in a string called squeeze

"foobar".squeeze
# => "fobar"

"foo foo bar".squeeze
# => "fo fo bar"

It also accepts args to narrow down the specific characters for which you would want to remove repeats:

"foobar hello world".squeeze("o")
# => "fobar hello world"

"foobar  hello  world".squeeze(" ")
# => "foobar hello world"

How to install sqlite3 on heroku

Using sqlite to persist data is superfluous on heroku, duh, but sometimes a third party service wants my rails app to read configuration in a sqlite db file. In order to read the read-only database file, I need to install the sqlite3 gem. To get this to work on heroku I needed to do two things:

  1. Install the apt buildpack
  2. Add an Aptfile in the root of the project
heroku buildpacks:add --index 1 heroku-community/apt

Then create an apt file:

# Aptfile
libsqlite3-dev
libsqlite3-0

Export CSV of query without COPY

Clients task me to export data to a CSV from time to time. My favorite workflow for authoring queries is a split tmux session, vim (with the excellent coc-sql) on one side, and a psql session on the other. I modify my query and then re-execute via \i.

This is great, until I’m ready to export the CSV. historically I’ve edited the query, cumbersomely breaking my REPL flow by turning it into a COPY command. Now I do this:

\pset format csv
\o output-file.csv
\i my-query.sql

To reset my psql session output…

\pset format aligned
\o

And thus my-query.sql remains a working query.

Elixir Compilation Cycles with `--fail-above`

Elixir 1.13.0 introduced a --fail-above flag for the mix xref task which will fail that task execution under a certain criteria.

With that we can verify, for example, that our code is ok to have 1 cycle that goes over length of 4, but not 2 cycles. Let’s see how it works:

$ mix xref graph --format cycles --min-cycle-size 4 --fail-above 1
2 cycles found. Showing them in decreasing size:

Cycle of length 6:

    lib/my_app_web/endpoint.ex
    lib/my_app_web/router.ex
    lib/my_app_web/views/layout_view.ex
    lib/my_app_web/live/components/sorting_link.ex
    lib/my_app_web/live/components/icon.ex
    lib/my_app_web/endpoint.ex

Cycle of length 5:

    lib/my_app_web/live/components/sorting_link.ex
    lib/my_app_web/live/components/icon.ex
    lib/my_app_web/router.ex
    lib/my_app_web/views/layout_view.ex
    lib/my_app_web/live/components/sorting_link.ex

** (Mix) Too many cycles (found: 2, permitted: 1)

In this case xref found 2 cycles with a length greater than 4, and as I allowed only 1 then we can see the error.

PostgreSQL Indexes on Partition tables

When we CREATE INDEX in a partitioned table, PostgreSQL automatically “recursively” creates the same index on all its partitions.

As this operation could take a while we can specify the ONLYparameter to the main table index to avoid the index to be created on all partitions and later creating the same index on each partition individually.

CREATE INDEX index_users_on_country ON ONLY users USING btree (country);

CREATE INDEX users_shard_0_country_idx ON users_shard_0 USING btree (country);
CREATE INDEX users_shard_1_country_idx ON users_shard_0 USING btree (country);

Elixir __struct__/0

When we define a struct via defstruct macro we end up getting a __struct__/0 function on both struct module definition and on each struct map. The intriguing part is that the implementation of the module and the map are different, check this out:

iex(1)> defmodule Book do
...(1)>   defstruct title: nil, pages_count: 0
...(1)> end

iex(2)> Book.__struct__()
%Book{pages_count: 0, title: nil}

iex(3)> Book.__struct__().__struct__()
Book

As we can see Book.__struct__() returns a new %Book{} struct with its defaults, meanwhile %Book{}.__struct() returns the Book module.

Elixir IEX multi-line command

A change on Elixir 1.12.0 made possible to pipe |> multi-line commands in iex where the |> operator is in the beginning of new lines.

That means that we can:

iex(1)> :foo
:foo
iex(2)>       |> to_string()
"foo"
iex(3)>       |> String.upcase()
"FOO"

The docs also mention that all other binary operators works the same way, except+/2 and -/2, so that’s also valid:

iex(1)> [:foo]
[:foo]
iex(2)> ++ [:bar]
[:foo, :bar]
iex(3)> |> Enum.join(" ")
"foo bar"
iex(4)> |> String.upcase()
"FOO BAR"

Each line will run at a new command, so if you assign a variable in the first line you may not have what you expect, so watch out.

Create Struct with Keyword Args in Ruby

I use Ruby Structs all the time. They’re great… if you don’t, check them out!

However I have found them a bit cumbersome to set up because they are generally used with positional arguments:

Money = Struct.new(:price, :currency)
Money.new(1.23, "USD")

Be cumbered no more! I have found a different approach.

Money = Struct.new(:price, :currency, keyword_init: true)
Money.new(currency: "USD", price: 1.23)

Using the keyword_init argument allows the new Struct instantiation to accept keyword arguments which, I find, clearer to read and also do not need to be positional.

Phoenix Live View enable Profiling

Phoenix LiveView has a way to enable Profiling in the client side by just adding this into the app.js file:

// app.js
liveSocket.enableProfiling();

That will enable a log into your browser console such as:

toString diff (update): 1.224853515625 ms
premorph container prep: 0.006103515625 ms
morphdom: 397.676025390625 ms
full patch complete: 411.117919921875 ms

In this case we can see that the morphdom library is taking a considerable time to apply my DOM patches as my page has a huge html table full of data.

BTW, this function adds to 2 other very useful ones for debugging the client:

  • enableDebug ()
  • enableLatencySim(ms)

Enable key repeat in VSCode

Even if your operating system enables key repeat, VSCode will disable it. To turn it on you need to update a default value and restart vscode:

defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
osascript -e 'tell application "Visual Studio Code" to quit'
osascript -e 'tell application "Visual Studio Code" to activate'

Get the Values for a Ecto Schema Enum Column

I recently started learning Elixir and had a model with an enum column with the following attributes:

 schema "keyboards" do
   field :nickname, :string
   field :form_factor, Ecto.Enum, values: [:macro, :num, :custom, :split, :forty, :sixty, :sixty_five, :seventy_five, :tkl, :full]

   timestamps()
 end

In my view, I had a form object where I wanted to have a select input with the values from my enum column, form_factor. Luckily, the Ecto.Enum module has a few functions that can help with this - mappings/2, values/2, and dump_values/2.

I ended up using the following in my form:

  <%= label f, :form_factor %>
  <%= select f, :form_factor, Ecto.Enum.mappings(Keyboard, :form_factor)  %>
  <%= error_tag f, :form_factor %>

https://hexdocs.pm/ecto/Ecto.Enum.html

Rails ActiveRecord count on groups

Rails ActiveRecord can count queries with GROUP BY clauses, and in this case the result is not just an integer, but a Hash with the grouped values and the count for each group. Check this out:

Project.group(:status, :city).count
# SELECT COUNT(*) AS count_all, "projects"."status" AS projects_status, "projects"."city" AS projects_city
# FROM "projects"
# GROUP BY "projects"."status", "projects"."city"
=> {
  [:pending, "Jacksonville Beach"] => 21,
  [:finished, "Jacksonville Beach"] => 1061
  [:pending, "Chicago"] => 10,
  [:finished, "Chicago"] => 980,
}

So rails manipulates the select statement to have all grouped by fields and the count(*) as well, which is pretty neat.

Get Elixir GenServer current state

Today I learned that we can use :sys.get_state/1 to get the current state of a GenServer.

Check this out:

iex(1)> pid = Process.whereis(MyApp.Repo)
iex(2)> :sys.get_state(pid)

{:state, {:local, MyApp.Repo}, :one_for_one,
 {[DBConnection.ConnectionPool],
  %{
    DBConnection.ConnectionPool => {:child, #PID<0.421.0>,
     DBConnection.ConnectionPool,
     {Ecto.Repo.Supervisor, :start_child,
      [
        {DBConnection.ConnectionPool, :start_link,
         [
           {Postgrex.Protocol,
            [
              types: Postgrex.DefaultTypes,
              repo: MyApp.Repo,
              telemetry_prefix: [:my_app, :repo],
              otp_app: :my_app,
              timeout: 15000,
              database: "my_app_dev",
              hostname: "localhost",
              port: 5432,
              show_sensitive_data_on_connection_error: true,
              pool_size: 10,
              pool: DBConnection.ConnectionPool
            ]}
         ]},
        MyApp.Repo,
        Ecto.Adapters.Postgres,
        %{
          cache: #Reference<0.1645792067.2416050178.91334>,
          opts: [
            timeout: 15000,
            pool_size: 10,
            pool: DBConnection.ConnectionPool
          ],
          repo: MyApp.Repo,
          sql: Ecto.Adapters.Postgres.Connection,
          telemetry: {MyApp.Repo, :debug, [:my_app, :repo, :query]}
        }
      ]}, :permanent, false, 5000, :worker, [Ecto.Repo.Supervisor]}
  }}, :undefined, 0, 5, [], 0, :never, Ecto.Repo.Supervisor,
 {MyApp.Repo, MyApp.Repo, :my_app, Ecto.Adapters.Postgres, []}}

Disable broken VSCode feature

TL;DR in the command palette choose “Workspaces: Configure Workspace Trust” and change “Start Prompt” to “never”

VSCode has a nice security feature warning about the risks of unknown file authors, but it is too naive to be useful; it actually has the reverse effect of being insecure (due to the fact most of these folders have been used in vscode for years before this feature was introduced). For example, I have over 200 projects on my machine:

ls ~/dev | wc -l
     213

The start prompt is simply training me to continually click “Yes I trust this code” over and over again, not only does this have no effect, but actually has a negative effect of making VSCode think I gave careful consideration to the folder, when instead, I was just trying to open my files.

Rails scopes might just return all resources

ActiveRecord’s scopes are meant to be composable and intended to only ever return an ActiveRecord relation.

If you make a mistake with your scope and have it return something like a nil or false, Rails will return all records for that class in order to maintain composability.

If you are intentionally writing something that might return an empty value, use a class method rather than adding a scope in order to prevent bugs

Explicitly Use Index For EXPLAIN in PostgreSQL

Sometimes when checking the EXPLAIN of a query results in a sequential scan where you expected an index to be used. This is expected as an optimization of PostgreSQL to decide which is the best method to use.

                                    QUERY PLAN
-----------------------------------------------------------------------------------
 Seq Scan on widgets  (cost=0.00..70.92 rows=1038 width=402)
   Filter: ((deleted_at IS NULL) AND ((widget_type)::text = 'foo'::text))

But what if you WANT to see how the index will be used? Well you can force sequential scanning to be turned off.

SET enable_seqscan TO off;

Now if we view the query plan again we can see the index in use.

                                    QUERY PLAN
-----------------------------------------------------------------------------------------------
 Bitmap Heap Scan on widgets  (cost=32.87..100.76 rows=1038 width=402)
   Recheck Cond: ((widget_type)::text = 'foo'::text)
   Filter: (deleted_at IS NULL)
   ->  Bitmap Index Scan on index_widgets_on_widget_type  (cost=0.00..32.61 rows=1111 width=0)
         Index Cond: ((widget_type)::text = 'foo'::text)

Hooray!

Now just don’t forget to re-enable the previous functionality

SET enable_seqscan TO on;

Increase size of ProgressView

You can increase the size of a ProgressView by using the .scaleEffect method:

AsyncImage(url: URL(string: video.poster_url)) { phase in
  if let image = phase.image {
      image
        .resizable()
        .aspectRatio(contentMode: .fill)
  } else if phase.error != nil {
    Color.red
  } else {
    ProgressView()
      .scaleEffect(x: 2, y: 2, anchor: .center)
  }
}
.frame(width: width, height: height)

Compact a Hash in Ruby

I use Array#compact all the time… you know the one that gets rid of all the nils.

Well I have no idea why it never occured to me that Hash ALSO has a #compact method.

It removes all the key/value pairs where the value is nil.

{
  a: "Alluro",
  b: nil,
  c: "Cheetara"
}.compact

=> {a: "Alluro", c: "Cheetara"}

Ensure Ruby returns the correct value

Ruby has implicit returns for any possible block that I can think of, except ensure. There might be more, but this is the only one that I can think of now.

So in order to return something from inside the ensure block we must use the return reserved word explicitly. Check this out:

def check_this_out
  yield if block_given?
  :ok
rescue
  :error
ensure
  :ensured
end

irb()> check_this_out { "should work" }
=> :ok

irb()> check_this_out { raise "should fail" }
=> :error

As we can see even though the ensure code runs on all calls it does not return :ensured.

Here’s the code with the explicit return:

def check_this_out_explicit_ensure_return
  yield if block_given?
  :ok
rescue
  :error
ensure
  return :ensured
end

irb()> check_this_out_explicit_ensure_return { "should work" }
=> :ensured

irb()> check_this_out_explicit_ensure_return { raise "should fail" }
=> :ensured

Rename a local git branch

Ever wanted to rename a local git branch? The git branch -m command is your friend

Want to rename a branch that’s not currently checked out?

git branch -m <original_name> <new_name>

Or to rename your current local branch, you can exclude the original name in the git branch args:

git branch -m <new_name>

Return difference between Lambda and Proc in Ruby

More differences between Procs & Lambdas

If a Proc has an explicit return then that return bubbles up to where it is being used.

Let’s take a look at a Proc’s behavior:

# Explicit return
def work_it
  p = Proc.new { puts "Workout"; return }
  puts "Pre workout"
  p.call
  puts "Post workout"
end

=> work_it
Pre workout
Workout
=> nil
# No explicit return
def work_it
  p = Proc.new { puts "Workout" }
  puts "Pre workout"
  p.call
  puts "Post workout"
end

=> work_it
Pre workout
Workout
Post workout
=> nil

Now let’s look at lambdas:

# Explicit return
def work_it
  l = -> { puts "Workout"; return }
  puts "Pre workout"
  l.call
  puts "Post workout"
end

=> work_it
Pre workout
Workout
Post workout
=> nil

Now even with the explicit return in the lambda, the method is able to complete its own logic path.

Arity difference between Lambda and Proc in Ruby

Many devs think Procs & Lambas in Ruby are interchangable… and it a lot of cases they can be.

However I did come across a difference to be aware of.

Procs do not enforce arity where a Lambda will.

Let’s take a look at a Proc’s behavior:

# Argument provided
p = Proc.new { |arg| puts arg }
p.call("TEST")
TEST
=> nil
# No argument provided
p = Proc.new { |arg| puts arg }
p.call

=> nil

Now let’s look at lambdas:

# Argument provided
l = ->(arg) { puts arg }
l.call("TEST")
TEST
=> nil
# No argument provided
l = ->(arg) { puts arg }
l.call

=> wrong number of arguments (given 0, expected 1) (ArgumentError)

See how there is strict arity on a lambda where the proc will not complain.

Comparison Validate more than Numbers in Rails

As of Rails 7 we can now use comparisions in validations for more than just numbers!

Previously we could do this but only against an integer

class Procedure
  validates :appointment_count, numericality: { less_than: 5 }
end

Now we can compare against many other types. Here is a quick example validating that an end date is further in the future than a start date.

class Procedure
  validates :start_date, comparison: { greater_than: ->(_) { Date.current }
  validates :end_date, comparison: { greater_than: :start_date }
end

Cool thing is you can pass a Proc or Symbol. A symbol can represent a method on the class. The Proc can represent anything. Its argument is the instance of the class.

For more info, check out this PR.

Always declare columns for SQL query in Rails

When ignoring a column in an ActiveRecord query you’ll receive a query that declares the column names of the table explicitly versus using *.

What if you do not want to ignore a column to get this functionality? Rails 7 will introduce an ActiveRecord class attribute to do just this.

class Procedure < ApplicationRecord
  self.enumerate_columns_in_select_statements = true
end
Procedure.all

=> SELECT "procedures"."id", "procedures"."name", "procedures"."created_at", "procedures"."updated_at" FROM "procedures"

When enumerate_columns_in_select_statements is set to true, ActiveRecord SELECT queries will always include column names explicitly over using a wildcard. This change was introduced to provide consistency in query generation and avoid prepared statment issues.

Note: it can be declared at the app configuration level as well.

module MyApp
  class Application < Rails::Application
    config.active_record.enumerate_columns_in_select_statements = true
  end
end

With that change, all ActiveRecord queries will avoid the wildcard.

Ignore columns on ActiveRecord queries in Rails

ActiveRecord models have ignored_columns defined as a class attribute. This allows us to, just like it says, ignore a particular column from our queries and returning ActiveRecords.

class Procedure < ApplicationRecord
    self.ignored_columns = [:created_at, :updated_at]
end

If we perform a lookup, this is what we’ll now see.

Procedure.all

=> SELECT "procedures"."id", "procedures"."name" FROM "procedures"

Notice the subtle difference?

Without the ignored_columns declaration, we’d see a query like this:

Procedure.all

=> SELECT "procedures".* FROM "procedures"

Using NULLS FIRST / NULLS LAST ordering in Rails

Methods nulls_first & nulls_last were added to Arel in Rails 6.1 for PostgreSQL and in most other databases in Rails 7.

In an earlier TIL, I showed how to order using Arel.

Procedure.order(Procedure.arel_table[:name].desc.nulls_first)

=> SELECT "procedures".* FROM "procedures" ORDER BY "procedures"."name" DESC NULLS FIRST
Procedure.order(Procedure.arel_table[:name].desc.nulls_last)

=> SELECT "procedures".* FROM "procedures" ORDER BY "procedures"."name" DESC NULLS LAST

Here the desc method is wrapping the Arel attribute in a node so that it can be utilized in order. nulls_first/nulls_last is just wrapping the previous ordering node.

Procedure.arel_table[:name].desc.nulls_first

=> 
#<Arel::Nodes::NullsFirst:0x00007fb73ebf18f8
 @expr=
  #<Arel::Nodes::Descending:0x00007fb73ebf1920
   @expr=
    #<struct Arel::Attributes::Attribute
     relation=
      #<Arel::Table:0x00007fb735a02dc0
       @klass=Procedure(id: integer, name: string, created_at: datetime, updated_at: datetime),
       @name="procedures",
       @table_alias=nil,
       @type_caster=
        #<ActiveRecord::TypeCaster::Map:0x00007fb735a02cd0
         @klass=Procedure(id: integer, name: string, created_at: datetime, updated_at: datetime)>>,
     name="name">>>

I mention this as you need to define the order before utilizing the nulls methods.

Using Arel in ActiveRecord ORDER Queries

I utilize Arel in ActiveRecord where all the time but it never occured to me that order can also take an Arel node.

Procedure.order(Procedure.arel_table[:name].desc)

=> SELECT "procedures".* FROM "procedures" ORDER BY "procedures"."name" DESC

For such a trivial example I’d say that it’s much clearer to just use ActiveRecord in this case.

Procedure.order(name: :desc)

=> SELECT "procedures".* FROM "procedures" ORDER BY "procedures"."name" DESC

Cool piece of knowledge for possible use in a more complex ordering case.