mirror of
https://github.com/jbranchaud/til
synced 2026-01-17 05:58:01 +00:00
Compare commits
30 Commits
16155bd063
...
2d74f9c88a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d74f9c88a | ||
|
|
84e2c9c6f4 | ||
|
|
39614e975e | ||
|
|
44e626a086 | ||
|
|
48d2ecffa0 | ||
|
|
6fb3b95ade | ||
|
|
51880975d4 | ||
|
|
03980ab291 | ||
|
|
bef492fe3a | ||
|
|
36004e6d20 | ||
|
|
18e52b9dbb | ||
|
|
01c9c0d19b | ||
|
|
c06bb2ea7b | ||
|
|
7dad6508d0 | ||
|
|
5bcdbbb3c7 | ||
|
|
41f5b526d2 | ||
|
|
e974a184c6 | ||
|
|
c832b9a70d | ||
|
|
42854fdc38 | ||
|
|
eff2c548cd | ||
|
|
1b229b39f1 | ||
|
|
2543651ec0 | ||
|
|
f3d7cf8a06 | ||
|
|
72089e11db | ||
|
|
b766f20012 | ||
|
|
505220d9de | ||
|
|
9684c6a6db | ||
|
|
3b0d76e805 | ||
|
|
b6c8192a04 | ||
|
|
460473a87f |
32
README.md
32
README.md
@@ -10,7 +10,7 @@ pairing with smart people at Hashrocket.
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
||||
|
||||
_1407 TILs and counting..._
|
||||
_1433 TILs and counting..._
|
||||
|
||||
---
|
||||
|
||||
@@ -41,6 +41,7 @@ _1407 TILs and counting..._
|
||||
* [jq](#jq)
|
||||
* [Kitty](#kitty)
|
||||
* [Linux](#linux)
|
||||
* [LLM](#llm)
|
||||
* [Mac](#mac)
|
||||
* [MongoDB](#mongodb)
|
||||
* [MySQL](#mysql)
|
||||
@@ -98,6 +99,7 @@ _1407 TILs and counting..._
|
||||
### Brew
|
||||
|
||||
- [Configure Brew Environment Variables](brew/configure-brew-environment-variables.md)
|
||||
- [List All Services Managed By Brew](brew/list-all-services-managed-by-brew.md)
|
||||
|
||||
### Chrome
|
||||
|
||||
@@ -259,6 +261,7 @@ _1407 TILs and counting..._
|
||||
|
||||
- [Accessing a Lost Commit](git/accessing-a-lost-commit.md)
|
||||
- [Add A Range Of Filename To gitignore](git/add-a-range-of-filenames-to-gitignore.md)
|
||||
- [Add Only Tracked Files From A Directory](git/add-only-tracked-files-from-a-directory.md)
|
||||
- [Amend Author Of Previous Commit](git/amend-author-of-previous-commit.md)
|
||||
- [Auto-Squash Those Fixup Commits](git/auto-squash-those-fixup-commits.md)
|
||||
- [Caching Credentials](git/caching-credentials.md)
|
||||
@@ -318,6 +321,7 @@ _1407 TILs and counting..._
|
||||
- [Quicker Commit Fixes With The Fixup Flag](git/quicker-commit-fixes-with-the-fixup-flag.md)
|
||||
- [Rebase Commits With An Arbitrary Command](git/rebase-commits-with-an-arbitrary-command.md)
|
||||
- [Reference A Commit Via Commit Message Pattern Matching](git/reference-a-commit-via-commit-message-pattern-matching.md)
|
||||
- [Remove Untracked Files From A Directory](git/remove-untracked-files-from-a-directory.md)
|
||||
- [Rename A Remote](git/rename-a-remote.md)
|
||||
- [Renaming A Branch](git/renaming-a-branch.md)
|
||||
- [Resetting A Reset](git/resetting-a-reset.md)
|
||||
@@ -397,6 +401,7 @@ _1407 TILs and counting..._
|
||||
- [Adding Alt Text To An Image](html/adding-alt-text-to-an-image.md)
|
||||
- [Determine Which Button Submitted The Form](html/determine-which-button-submitted-the-form.md)
|
||||
- [Disable Auto-Completion For A Form Input](html/disable-auto-completion-for-a-form-input.md)
|
||||
- [Make Elements Non-Interactive With Inert](html/make-elements-non-interactive-with-inert.md)
|
||||
- [Prevent Search Engines From Indexing A Page](html/prevent-search-engines-from-indexing-a-page.md)
|
||||
- [Render Text As Superscript](html/render-text-as-superscript.md)
|
||||
- [Submit A Form With A Button Outside The Form](html/submit-a-form-with-a-button-outside-the-form.md)
|
||||
@@ -407,6 +412,7 @@ _1407 TILs and counting..._
|
||||
|
||||
### Inngest
|
||||
|
||||
- [Ensure Lookup Can Be Retried](inngest/ensure-lookup-can-be-retried.md)
|
||||
- [Exit Function Early Without Retries](inngest/exit-function-early-without-retries.md)
|
||||
|
||||
### Internet
|
||||
@@ -436,6 +442,7 @@ _1407 TILs and counting..._
|
||||
- [Computed Property Names In ES6](javascript/computed-property-names-in-es6.md)
|
||||
- [Conditionally Include Pairs In An Object](javascript/conditionally-include-pairs-in-an-object.md)
|
||||
- [Configure Jest To Run A Test Setup File](javascript/configure-jest-to-run-a-test-setup-file.md)
|
||||
- [Convert Seconds To Date Object](javascript/convert-seconds-to-date-object.md)
|
||||
- [Create A Cancelable Promise With PCancelable](javascript/create-a-cancelable-promise-with-pcancelable.md)
|
||||
- [Create An Array Containing 1 To N](javascript/create-an-array-containing-1-to-n.md)
|
||||
- [Create An Object With No Properties](javascript/create-an-object-with-no-properties.md)
|
||||
@@ -455,6 +462,7 @@ _1407 TILs and counting..._
|
||||
- [Find Where Yarn Is Installing Binaries](javascript/find-where-yarn-is-installing-binaries.md)
|
||||
- [for...in Iterates Over Object Properties](javascript/for-in-iterates-over-object-properties.md)
|
||||
- [Format A Decimal To A Fixed Number Of Digits](javascript/format-a-decimal-to-a-fixed-number-of-digits.md)
|
||||
- [Format Time Zone Identifier](javascript/format-time-zone-identifier.md)
|
||||
- [Formatting Values With Units For Display](javascript/formatting-values-with-units-for-display.md)
|
||||
- [Freeze An Object, Sorta](javascript/freeze-an-object-sorta.md)
|
||||
- [Generate A V4 UUID In The Browser](javascript/generate-a-v4-uuid-in-the-browser.md)
|
||||
@@ -552,6 +560,11 @@ _1407 TILs and counting..._
|
||||
- [Show Used And Available System Memory](linux/show-used-and-available-system-memory.md)
|
||||
- [Upgrading Ubuntu](linux/upgrading-ubuntu.md)
|
||||
|
||||
### LLM
|
||||
|
||||
- [Send cURL To Claude Text Completion API](llm/send-curl-to-claude-text-completion-api.md)
|
||||
- [Use The llm CLI With Claude Models](llm/use-the-llm-cli-with-claude-models.md)
|
||||
|
||||
### Mac
|
||||
|
||||
- [Access All Screen And Video Capture Options](mac/access-all-screen-and-video-capture-options.md)
|
||||
@@ -598,6 +611,7 @@ _1407 TILs and counting..._
|
||||
- [List Databases And Tables](mysql/list-databases-and-tables.md)
|
||||
- [Run Statements In A Transaction](mysql/run-statements-in-a-transaction.md)
|
||||
- [Select Rows After An Offset](mysql/select-rows-after-an-offset.md)
|
||||
- [Set Value On Null JSON Column](mysql/set-value-on-null-json-column.md)
|
||||
- [Show Create Statement For A Table](mysql/show-create-statement-for-a-table.md)
|
||||
- [Show Tables That Match A Pattern](mysql/show-tables-that-match-a-pattern.md)
|
||||
- [Show Indexes For A Table](mysql/show-indexes-for-a-table.md)
|
||||
@@ -663,6 +677,7 @@ _1407 TILs and counting..._
|
||||
- [Capitalize All The Words](postgres/capitalize-all-the-words.md)
|
||||
- [Change The Current Directory For psql](postgres/change-the-current-directory-for-psql.md)
|
||||
- [Change The Owner Of A Sequence](postgres/change-the-owner-of-a-sequence.md)
|
||||
- [Check If Clusters Are Upgrade Compatible](postgres/check-if-clusters-are-upgrade-compatible.md)
|
||||
- [Check If The Local Server Is Running](postgres/check-if-the-local-server-is-running.md)
|
||||
- [Check If User Role Exists For Database](postgres/check-if-user-role-exists-for-database.md)
|
||||
- [Check Table For Any Oprhaned Records](postgres/check-table-for-any-orphaned-records.md)
|
||||
@@ -679,6 +694,7 @@ _1407 TILs and counting..._
|
||||
- [Count How Many Records There Are Of Each Type](postgres/count-how-many-records-there-are-of-each-type.md)
|
||||
- [Count Records By Type](postgres/count-records-by-type.md)
|
||||
- [Count The Number Of Trues In An Aggregate Query](postgres/count-the-number-of-trues-in-an-aggregate-query.md)
|
||||
- [Create A Cluster In A Specific Data Directory](postgres/create-a-cluster-in-a-specific-data-directory.md)
|
||||
- [Create A Composite Primary Key](postgres/create-a-composite-primary-key.md)
|
||||
- [Create A Table From The Structure Of Another](postgres/create-a-table-from-the-structure-of-another.md)
|
||||
- [Create An Index Across Two Columns](postgres/create-an-index-across-two-columns.md)
|
||||
@@ -718,6 +734,7 @@ _1407 TILs and counting..._
|
||||
- [Generate Series Of Numbers](postgres/generate-series-of-numbers.md)
|
||||
- [Generating UUIDs With pgcrypto](postgres/generating-uuids-with-pgcrypto.md)
|
||||
- [Get A Quick Approximate Count Of A Table](postgres/get-a-quick-approximate-count-of-a-table.md)
|
||||
- [Get Row Count For Most Recent Query](postgres/get-row-count-for-most-recent-query.md)
|
||||
- [Get The Size On Disk of An Index](postgres/get-the-size-on-disk-of-an-index.md)
|
||||
- [Get The Size Of A Database](postgres/get-the-size-of-a-database.md)
|
||||
- [Get The Size Of A Table](postgres/get-the-size-of-a-table.md)
|
||||
@@ -726,6 +743,7 @@ _1407 TILs and counting..._
|
||||
- [Group By The Result Of A Function Call](postgres/group-by-the-result-of-a-function-call.md)
|
||||
- [Idempotent Inserts](postgres/idempotent-inserts.md)
|
||||
- [Include All Queries In The Log File](postgres/include-all-queries-in-the-log-file.md)
|
||||
- [Include Columns In A Covering Index](postgres/include-columns-in-a-covering-index.md)
|
||||
- [Include Multiple Tables In A pg_dump](postgres/include-multiple-tables-in-a-pg-dump.md)
|
||||
- [Insert A Bunch Of Records With Generate Series](postgres/insert-a-bunch-of-records-with-generate-series.md)
|
||||
- [Insert Just The Defaults](postgres/insert-just-the-defaults.md)
|
||||
@@ -807,10 +825,12 @@ _1407 TILs and counting..._
|
||||
|
||||
- [Apply Separate Formatting With A Blank Line](prisma/apply-separate-formatting-with-a-blank-line.md)
|
||||
- [Batch Insert Records With createMany](prisma/batch-insert-records-with-create-many.md)
|
||||
- [Check If Database And Schema Are Not In Sync](prisma/check-if-database-and-schema-are-not-in-sync.md)
|
||||
- [Configure Client To Log SQL Queries](prisma/configure-client-to-log-sql-queries.md)
|
||||
- [Execute A Raw SQL Query](prisma/execute-a-raw-sql-query.md)
|
||||
- [Grab A Limited Set Of Records](prisma/grab-a-limited-set-of-records.md)
|
||||
- [Open Connections To Multiple Databases](prisma/open-connections-to-multiple-databases.md)
|
||||
- [Override Table Name For Prisma Model](prisma/override-table-name-for-prisma-model.md)
|
||||
- [Specify Alternate Location For Prisma Schema](prisma/specify-alternate-location-for-prisma-schema.md)
|
||||
|
||||
### Python
|
||||
@@ -818,6 +838,7 @@ _1407 TILs and counting..._
|
||||
- [Access Instance Variables](python/access-instance-variables.md)
|
||||
- [Create A Dummy DataFrame In Pandas](python/create-a-dummy-dataframe-in-pandas.md)
|
||||
- [Test A Function With Pytest](python/test-a-function-with-pytest.md)
|
||||
- [Use pipx To Install End User Apps](python/use-pipx-to-install-end-user-apps.md)
|
||||
|
||||
### Rails
|
||||
|
||||
@@ -878,6 +899,7 @@ _1407 TILs and counting..._
|
||||
- [Get ActiveRecord Attribute Directly From Database](rails/get-active-record-attribute-directly-from-database.md)
|
||||
- [Get An Array Of Values From The Database](rails/get-an-array-of-values-from-the-database.md)
|
||||
- [Get An Empty ActiveRecord Relation](rails/get-an-empty-activerecord-relation.md)
|
||||
- [Get Formatted UTC Offset Value](rails/get-formatted-utc-offset-value.md)
|
||||
- [Get Help With A Rails App Update](rails/get-help-with-a-rails-app-update.md)
|
||||
- [Get The Column Names For A Model](rails/get-the-column-names-for-a-model.md)
|
||||
- [Get The Current Time](rails/get-the-current-time.md)
|
||||
@@ -893,6 +915,7 @@ _1407 TILs and counting..._
|
||||
- [Load A File When Starting Rails Console](rails/load-a-file-when-starting-rails-console.md)
|
||||
- [Load Records In Batches With find_each](rails/load-records-in-batches-with-find-each.md)
|
||||
- [Log SQL Queries Executed By ActiveRecord](rails/log-sql-queries-executed-by-activerecord.md)
|
||||
- [Look Up Time Zone Info For Identifier](rails/look-up-time-zone-info-for-identifier.md)
|
||||
- [Mark A Migration As Irreversible](rails/mark-a-migration-as-irreversible.md)
|
||||
- [Make A String Attribute Easy To Inquire About](rails/make-a-string-attribute-easy-to-inquire-about.md)
|
||||
- [Make ActionMailer Synchronous In Test](rails/make-action-mailer-synchronous-in-test.md)
|
||||
@@ -1113,6 +1136,7 @@ _1407 TILs and counting..._
|
||||
- [Defaulting To Frozen String Literals](ruby/defaulting-to-frozen-string-literals.md)
|
||||
- [Define A Custom RSpec Matcher](ruby/define-a-custom-rspec-matcher.md)
|
||||
- [Define A Method On A Struct](ruby/define-a-method-on-a-struct.md)
|
||||
- [Define Multiline Strings With Heredocs](ruby/define-multiline-strings-with-heredocs.md)
|
||||
- [Destructure The First Item From An Array](ruby/destructure-the-first-item-from-an-array.md)
|
||||
- [Destructuring Arrays In Blocks](ruby/destructuring-arrays-in-blocks.md)
|
||||
- [Disassemble Some Codes](ruby/disassemble-some-codes.md)
|
||||
@@ -1136,6 +1160,7 @@ _1407 TILs and counting..._
|
||||
- [Generate Ruby Version And Gemset Files With RVM](ruby/generate-ruby-version-and-gemset-files-with-rvm.md)
|
||||
- [Get Info About Your RubyGems Environment](ruby/get-info-about-your-ruby-gems-environment.md)
|
||||
- [Get The Output Of Running A System Program](ruby/get-the-output-of-running-a-system-program.md)
|
||||
- [Get UTC Offset For Different Time Zones](ruby/get-utc-offset-for-different-time-zones.md)
|
||||
- [Identify Outdated Gems](ruby/identify-outdated-gems.md)
|
||||
- [If You Detect None](ruby/if-you-detect-none.md)
|
||||
- [Iterate With An Offset Index](ruby/iterate-with-an-offset-index.md)
|
||||
@@ -1353,10 +1378,13 @@ _1407 TILs and counting..._
|
||||
- [Find Files With fd](unix/find-files-with-fd.md)
|
||||
- [Find Newer Files](unix/find-newer-files.md)
|
||||
- [Find Occurrences Of Multiple Values With Ripgrep](unix/find-occurrences-of-multiple-values-with-ripgrep.md)
|
||||
- [Find Top-Level Directories Matching A Pattern](unix/find-top-level-directories-matching-a-pattern.md)
|
||||
- [Fix Unlinked Node Binaries With asdf](unix/fix-unlinked-node-binaries-with-asdf.md)
|
||||
- [Forward Multiple Ports Over SSH](unix/forward-multiple-ports-over-ssh.md)
|
||||
- [Generate A SAML Key And Certificate Pair](unix/generate-a-saml-key-and-certificate-pair.md)
|
||||
- [Generate Base64 Encoding Without Newlines](unix/generate-base64-encoding-without-newlines.md)
|
||||
- [Generate Random 20-Character Hex String](unix/generate-random-20-character-hex-string.md)
|
||||
- [Get A List Of Locales On Your System](unix/get-a-list-of-locales-on-your-system.md)
|
||||
- [Get Matching Filenames As Output From Grep](unix/get-matching-filenames-as-output-from-grep.md)
|
||||
- [Get The Unix Timestamp](unix/get-the-unix-timestamp.md)
|
||||
- [Global Substitution On The Previous Command](unix/global-substitution-on-the-previous-command.md)
|
||||
@@ -1611,6 +1639,7 @@ _1407 TILs and counting..._
|
||||
- [Add The VSCode CLI To Your Path](vscode/add-the-vscode-cli-to-your-path.md)
|
||||
- [Advance Through Search Results](vscode/advance-through-search-results.md)
|
||||
- [Enable Breadcrumbs For Version 1.26 Release](vscode/enable-breadcrumbs-for-version-126-release.md)
|
||||
- [Find The Location Of User Settings JSON File](vscode/find-the-location-of-user-settings-json-file.md)
|
||||
- [Open An Integrated Terminal Window](vscode/open-an-integrated-terminal-window.md)
|
||||
- [Pop Open The Quick Fix Window](vscode/pop-open-the-quick-fix-window.md)
|
||||
- [Step Through Project-Wide Search Results](vscode/step-through-project-wide-search-results.md)
|
||||
@@ -1628,6 +1657,7 @@ _1407 TILs and counting..._
|
||||
### Workflow
|
||||
|
||||
- [Add Subtitles To Existing Mux Video Asset](workflow/add-subtitles-to-existing-mux-video-asset.md)
|
||||
- [Access 1Password Credential From CLI](workflow/access-1password-credential-from-cli.md)
|
||||
- [Change Window Name In iTerm](workflow/change-window-name-in-iterm.md)
|
||||
- [Convert An ePub Document To PDF On Mac](workflow/convert-an-epub-document-to-pdf-on-mac.md)
|
||||
- [Create A Local Sanity Dataset Backup](workflow/create-a-local-sanity-dataset-backup.md)
|
||||
|
||||
28
brew/list-all-services-managed-by-brew.md
Normal file
28
brew/list-all-services-managed-by-brew.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# List All Services Managed By Brew
|
||||
|
||||
Daemonized services, such as PostgreSQL, can be installed and managed with
|
||||
Homebrew. Under the hood `brew` uses `launchctl` on Mac to manage these
|
||||
services — i.e. starting, restarting, and stopping them.
|
||||
|
||||
Assuming you've already installed some services, you can run `brew services
|
||||
list` to see what services there are and what their current status is.
|
||||
|
||||
```bash
|
||||
$ brew services list
|
||||
Name Status User File
|
||||
mailhog none
|
||||
mysql none
|
||||
postgresql@11 started jbranchaud ~/Library/LaunchAgents/homebrew.mxcl.postgresql@11.plist
|
||||
postgresql@13 none
|
||||
postgresql@16 none
|
||||
unbound none
|
||||
```
|
||||
|
||||
This is the default behavior if you just run `brew services` without a subcommand.
|
||||
|
||||
This is helpful if you are, for instance, trying to see which PostgreSQL server
|
||||
version you are currently running and which other ones are available to run. I
|
||||
might then issue a `stop` to `postgresql@11` so that I can then `start` the
|
||||
`postgresql@16` service.
|
||||
|
||||
See `brew services --help` for more details.
|
||||
26
git/add-only-tracked-files-from-a-directory.md
Normal file
26
git/add-only-tracked-files-from-a-directory.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Add Only Tracked Files From A Directory
|
||||
|
||||
The two extremes of staging files in a git repo are to either selectively pick
|
||||
each individual chunk of changes with `git add --patch` (my preference!) or to
|
||||
run `git add -A` to add everything.
|
||||
|
||||
Now let's say I have large directory full of files that get generated during
|
||||
test runs. Most of these files are tracked (already checked in to the
|
||||
repository). There are also many new files generated as part of the most recent
|
||||
test run.
|
||||
|
||||
I want to staging the changes to files that are already tracked, but hold off
|
||||
on doing anything with the new files.
|
||||
|
||||
Running `git add spec/cassettes` won't do the track because that will pull in
|
||||
everything. Running `git add --patch spec/cassettes` will take long and be
|
||||
tedious. Instead what I want is the `-u` flag. It's short for _update_ which
|
||||
means it will only stage already tracked files.
|
||||
|
||||
```bash
|
||||
$ git add -u spec/cassettes
|
||||
```
|
||||
|
||||
That will stage every change to any already known files in `spec/cassettes`.
|
||||
|
||||
See `man git-add` for more details.
|
||||
26
git/remove-untracked-files-from-a-directory.md
Normal file
26
git/remove-untracked-files-from-a-directory.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Remove Untracked Files From A Directory
|
||||
|
||||
Let's say I have a directory (`spec/cassettes`) full of a ton of generated YAML
|
||||
files. Most of these files are tracked by git. However, I just generated a
|
||||
bunch of new ones that are untracked. For whatever reason, I don't want these
|
||||
files. I need to delete them.
|
||||
|
||||
Running `rm` on each of them is going to be too tedious. And it is tricky to
|
||||
target them for a bulk delete since there are a ton of other files in that
|
||||
directory that I want to keep.
|
||||
|
||||
One way to approach this is have `git ls-files` help out with listing all files in the
|
||||
directory that are untracked. The `--others` flag filters to untracked files.
|
||||
|
||||
```bash
|
||||
git ls-files --others --exclude-standard spec/cassettes
|
||||
```
|
||||
|
||||
From there, I can pipe it to `rm` (with `xargs` collapsing all the files into a
|
||||
single line):
|
||||
|
||||
```bash
|
||||
git ls-files --others --exclude-standard spec/cassettes | xargs rm
|
||||
```
|
||||
|
||||
See `man git-ls-files` for more details.
|
||||
25
html/make-elements-non-interactive-with-inert.md
Normal file
25
html/make-elements-non-interactive-with-inert.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Make Elements Non-Interactive With Inert
|
||||
|
||||
The [`inert`
|
||||
attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/inert)
|
||||
global attribute is a boolean that can be applied to an element or section of
|
||||
content in an HTML document. When it is `true`, that elements and anything
|
||||
nested within it will not be interactive.
|
||||
|
||||
```html
|
||||
<div class="fancy-animation" inert>
|
||||
<!-- ... -->
|
||||
</div>
|
||||
```
|
||||
|
||||
This has a couple different implications:
|
||||
|
||||
1. Click events are not fired on these elements.
|
||||
|
||||
2. These elements will not be able to gain focus.
|
||||
|
||||
3. These elements and content are hidden from assistive technology.
|
||||
|
||||
This is useful for a variety of things. In particular, it is good for
|
||||
accessibility when a portion of the document, like a fancy animation, isn't
|
||||
meant to be traversed by assistive technology.
|
||||
57
inngest/ensure-lookup-can-be-retried.md
Normal file
57
inngest/ensure-lookup-can-be-retried.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Ensure Lookup Can Be Retried
|
||||
|
||||
A common thing to do in a workflow step is to look up a record. This might be a
|
||||
record that was created or updated around the time that the workflow was
|
||||
triggered.
|
||||
|
||||
You need to be sure the record was found before proceeding. That might end up
|
||||
looking like this:
|
||||
|
||||
```typescript
|
||||
export default inngest.createFunction(
|
||||
{ id: "record-user-purchase" },
|
||||
{ event: "app/record.purchase" },
|
||||
async ({ event, step }) => {
|
||||
const checkoutSession =
|
||||
await step.run("find checkout session", async () => {
|
||||
const cs = provider.lookupSession(event.checkoutSessionId)
|
||||
|
||||
return cs;
|
||||
});
|
||||
|
||||
if(!checkoutSession) {
|
||||
throw new Error('Checkout session not found')
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
This approach has a subtle problem which is that the error for a missing
|
||||
checkout session is raised _outside_ the step that sets `checkoutSession`. As
|
||||
inngest does a series of retries, the memorized `checkoutSession` step won't be
|
||||
rerun and the error will continue to be thrown.
|
||||
|
||||
It is better to raise the error _within_ the lookup step:
|
||||
|
||||
```typescript
|
||||
export default inngest.createFunction(
|
||||
{ id: "record-user-purchase" },
|
||||
{ event: "app/record.purchase" },
|
||||
async ({ event, step }) => {
|
||||
const checkoutSession =
|
||||
await step.run("find checkout session", async () => {
|
||||
const cs = provider.lookupSession(event.checkoutSessionId)
|
||||
|
||||
if(!cs) {
|
||||
throw new Error('Checkout session not found')
|
||||
}
|
||||
|
||||
return cs;
|
||||
});
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
If the checkout session is missing on the first couple tries, the step will
|
||||
have a chance to retry the lookup and maybe eventually find what it is looking
|
||||
for.
|
||||
32
javascript/convert-seconds-to-date-object.md
Normal file
32
javascript/convert-seconds-to-date-object.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Convert Seconds To Date Object
|
||||
|
||||
Let's say you have an integer that represents the number of seconds since the
|
||||
unix epoch. This is a reasonably common way for systems to represent a date.
|
||||
|
||||
For example, `1713350171` is an _Expiration Date_ I just got from an API.
|
||||
|
||||
But how do we know what date that actually represents and how can we get a
|
||||
JavaScript `Date` object from that value?
|
||||
|
||||
The `new Date()` constructor can produce a date object given an integer. That
|
||||
integer is not supposed to be seconds since the unix epoch though. See what we
|
||||
get here:
|
||||
|
||||
```javascript
|
||||
> new Date(1713350171)
|
||||
1970-01-20T19:55:50.171Z
|
||||
```
|
||||
|
||||
Something is off. The integer that you pass to `new Date()` needs to be the
|
||||
_number of milliseconds_ since the unix epoch. We can get there by multiplying
|
||||
our _seconds_ value by `1000`.
|
||||
|
||||
```javascript
|
||||
> new Date(1713350171 * 1000)
|
||||
2024-04-17T10:36:11.000Z
|
||||
```
|
||||
|
||||
Not only can we, as humans, read that date, but we have a `Date` object that we
|
||||
can use within our program.
|
||||
|
||||
Note: if you execute `Date.now()`, the value you get is in milliseconds.
|
||||
34
javascript/format-time-zone-identifier.md
Normal file
34
javascript/format-time-zone-identifier.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Format Time Zone Identifier
|
||||
|
||||
Though there are surely libraries that can help with this task, we now have
|
||||
full support in the [`Intl.DateTimeFormat`
|
||||
API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat)
|
||||
for formatting a date's time zone identifier in various ways.
|
||||
|
||||
To do this, we have to create a formatter specifying the locale, the `timeZone`
|
||||
option, and any formatting options. For the formatting, I'll try the
|
||||
`timeZoneName` with both `short` and `longGeneric`.
|
||||
|
||||
Then we `formatToParts` on any date object and extract the `timeZoneName`
|
||||
value:
|
||||
|
||||
```javascript
|
||||
const options = { timeZone: 'America/Chicago', timeZoneName: "short" }
|
||||
const formatter = new Intl.DateTimeFormat("en-US", options)
|
||||
|
||||
formatter.formatToParts(new Date()).find((part) => part.type === "timeZoneName").value
|
||||
//=> 'CDT'
|
||||
```
|
||||
|
||||
Now, let's try this for `longGeneric`:
|
||||
|
||||
```javascript
|
||||
const options = { timeZone: 'America/Chicago', timeZoneName: "longGeneric" }
|
||||
const formatter = new Intl.DateTimeFormat("en-US", options)
|
||||
|
||||
formatter.formatToParts(new Date()).find((part) => part.type === "timeZoneName").value
|
||||
//=> 'Central Time'
|
||||
```
|
||||
|
||||
There are several more options for the `timeZoneName` as well as a bunch more
|
||||
you can do with the `Intl.DateTimeFormat` API.
|
||||
@@ -15,10 +15,8 @@ const remove = (items,index) => {
|
||||
};
|
||||
|
||||
const list = [1,2,3,4,5];
|
||||
remove(list, 2);
|
||||
// [1,2,3,4]
|
||||
list
|
||||
// [1,2,3,4,5]
|
||||
remove(list, 2); // [1,2,4,5]
|
||||
// list still [1,2,3,4,5]
|
||||
```
|
||||
|
||||
It only took a couple lines of code and immutability is baked in.
|
||||
|
||||
40
llm/send-curl-to-claude-text-completion-api.md
Normal file
40
llm/send-curl-to-claude-text-completion-api.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Send cURL To Claude Text Completion API
|
||||
|
||||
Here is how we can make a `cURL` (`POST`) request to the Claude text completion
|
||||
API. It requires already having a Claude API account with (paid) credits. At
|
||||
this time, you can get $5 in free credits to try it out.
|
||||
|
||||
Assuming all that, we can grab an API key, store it somewhere safe and
|
||||
accessible like 1Password, and then start formatting a request.
|
||||
|
||||
We need to specify a couple headers as well as `POST` body parameters.
|
||||
|
||||
```bash
|
||||
curl -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-api-key: $(op item get "Anthropic Claude API Key" --field credential)" \
|
||||
-H "anthropic-version: 2023-06-01" \
|
||||
-d \
|
||||
'{
|
||||
"model": "claude-2.1",
|
||||
"max_tokens_to_sample": 1024,
|
||||
"prompt": "Human: Show me an example of a simple Ruby program.\n\nAssistant:"
|
||||
}' \
|
||||
https://api.anthropic.com/v1/complete
|
||||
```
|
||||
|
||||
The required headers are:
|
||||
- `"Content-Type: application/json"`
|
||||
- `x-api-key` with our API key
|
||||
- `"anthropic-version: 2023-06-01"` (the latest Anthropic API version)
|
||||
|
||||
Then, in the body, we specify:
|
||||
- the `model` (e.g. `claude-2.1`)
|
||||
- the max number of tokens you want the model to use
|
||||
- a prompt that starts with `Human:` and then prompts the `Assistant:`
|
||||
|
||||
Note: this is a legacy API and the [Messages
|
||||
API](https://docs.anthropic.com/claude/reference/messages_post) should be
|
||||
preferred.
|
||||
|
||||
[source](https://docs.anthropic.com/claude/reference/complete_post)
|
||||
26
llm/use-the-llm-cli-with-claude-models.md
Normal file
26
llm/use-the-llm-cli-with-claude-models.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Use The llm CLI With Claude Models
|
||||
|
||||
[Simon Willison's `llm`](https://llm.datasette.io/en/stable/index.html) can be
|
||||
used with a bunch of different models (local and API). The whole thing is
|
||||
plugin driven. To use a specific model, you'll need to install the plugin for
|
||||
it. For instance, to use the [Claude 3 family of
|
||||
models](https://www.anthropic.com/news/claude-3-family) you need to install
|
||||
`llm-claude-3`.
|
||||
|
||||
```bash
|
||||
$ llm install llm-claude-3
|
||||
```
|
||||
|
||||
Then when prompting `llm`, specify which of the Claude models you want to use —
|
||||
`claude-3-haiku`, `claude-3-sonnet`, or `claude-3-opus` — with the `-m` flag:
|
||||
|
||||
```bash
|
||||
$ llm \
|
||||
-m claude-3-haiku \
|
||||
--key $CLAUDE_API_KEY \
|
||||
'Show me the SQL query to create a cocktails table.'
|
||||
```
|
||||
|
||||
Note: instead of adding my Claude API key to the key store, I've opted to
|
||||
include it with the `--key` flag via an environment variable that I've set
|
||||
ahead of time.
|
||||
44
mysql/set-value-on-null-json-column.md
Normal file
44
mysql/set-value-on-null-json-column.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Set Value On Null JSON Column
|
||||
|
||||
To set a key-value pair on a JSON field, you can reach for
|
||||
[MySQL's `json_set`](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html#function_json-set)
|
||||
or one of [the other JSON setter
|
||||
functions](https://dev.mysql.com/doc/refman/8.0/en/json-modification-functions.html).
|
||||
|
||||
However, if the JSON field you are updating is `null`, you might get an
|
||||
unexpected result.
|
||||
|
||||
```sql
|
||||
> update User
|
||||
set metadata = json_set(metadata, '$.discord_id', 'discord_123')
|
||||
where id = 123;
|
||||
|
||||
Query OK, 0 rows affected (0.00 sec)
|
||||
Rows matched: 1 Changed: 0 Warnings: 0
|
||||
```
|
||||
|
||||
We can see that the `where` clause matched on a single row as expected, but
|
||||
right above that it says _0 rows affected_.
|
||||
|
||||
What happened?
|
||||
|
||||
The `json_set` function is not able to set a key-value pair on `null`. It needs
|
||||
a JSON object to work on.
|
||||
|
||||
There are a number of ways to get around this. I find that
|
||||
[`coalesce`](https://dev.mysql.com/doc/refman/8.0/en/comparison-operators.html#function_coalesce)
|
||||
is a natural way to handle this. If `metadata` happens to be `null`, then we
|
||||
_coalesce_ it to `'{}'` (an empty object).
|
||||
|
||||
```sql
|
||||
> update User
|
||||
set metadata = json_set(coalesce(metadata, '{}'), '$.discord_id', 'discord_123')
|
||||
where id = 123;
|
||||
|
||||
Query OK, 1 row affected (0.02 sec)
|
||||
Rows matched: 1 Changed: 1 Warnings: 0
|
||||
```
|
||||
|
||||
It updates as expected. That same statement will work on a row where `metadata`
|
||||
already contains a JSON object since the `coalesce` will resolve to that
|
||||
instead of the empty object.
|
||||
42
postgres/check-if-clusters-are-upgrade-compatible.md
Normal file
42
postgres/check-if-clusters-are-upgrade-compatible.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Check If Clusters Are Upgrade Compatible
|
||||
|
||||
One of the ways to upgrade a PostgreSQL database from one server version to
|
||||
another is to use the built-in `pg_upgrade` command. This can be faster and
|
||||
require fewer manual steps than something like a `pg_dump` and `pg_restore`.
|
||||
|
||||
However, before you run the `pg_upgrade` command for real, you should check
|
||||
that the target database is compatible with the current database. To do this,
|
||||
write your `pg_update` command with all the flags you need and then tack on
|
||||
`--check` at the end. This does a dry-run reporting the results of a series of
|
||||
consistency checks.
|
||||
|
||||
Here is what a successful _check_ looks like:
|
||||
|
||||
```bash
|
||||
$ /usr/local/opt/postgresql@13/bin/pg_upgrade \
|
||||
--old-bindir $HOME/.asdf/installs/postgres/12.3/bin \
|
||||
--new-bindir /usr/local/opt/postgresql@13/bin \
|
||||
--old-datadir $HOME/.asdf/installs/postgres/12.3/data \
|
||||
--new-datadir ./postgres/data \
|
||||
--check
|
||||
|
||||
Performing Consistency Checks
|
||||
-----------------------------
|
||||
Checking cluster versions ok
|
||||
Checking database user is the install user ok
|
||||
Checking database connection settings ok
|
||||
Checking for prepared transactions ok
|
||||
Checking for system-defined composite types in user tables ok
|
||||
Checking for reg* data types in user tables ok
|
||||
Checking for contrib/isn with bigint-passing mismatch ok
|
||||
Checking for presence of required libraries ok
|
||||
Checking database user is the install user ok
|
||||
Checking for prepared transactions ok
|
||||
Checking for new cluster tablespace directories ok
|
||||
|
||||
*Clusters are compatible*
|
||||
```
|
||||
|
||||
If there is an issue, such as mismatched collation settings, the output will
|
||||
report the issue. You'll have to decide how to resolve those on a case-by-case
|
||||
basis.
|
||||
46
postgres/create-a-cluster-in-a-specific-data-directory.md
Normal file
46
postgres/create-a-cluster-in-a-specific-data-directory.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Create A Cluster In A Specific Data Directory
|
||||
|
||||
Let's say I want to create a PostgreSQL cluster near my app. So, I create a
|
||||
`postgres/data` directory next to my app. Then I run the `initdb` command
|
||||
pointing at that directory and specifying the UTF-8 locale.
|
||||
|
||||
Here is what that looks like:
|
||||
|
||||
```bash
|
||||
$ /usr/local/opt/postgresql@13/bin/initdb -D postgres/data --locale=en_US.UTF-8
|
||||
|
||||
The files belonging to this database system will be owned by user "jbranchaud".
|
||||
This user must also own the server process.
|
||||
|
||||
The database cluster will be initialized with locale "en_US.UTF-8".
|
||||
The default database encoding has accordingly been set to "UTF8".
|
||||
The default text search configuration will be set to "english".
|
||||
|
||||
Data page checksums are disabled.
|
||||
|
||||
fixing permissions on existing directory postgres/data ... ok
|
||||
creating subdirectories ... ok
|
||||
selecting dynamic shared memory implementation ... posix
|
||||
selecting default max_connections ... 100
|
||||
selecting default shared_buffers ... 128MB
|
||||
selecting default time zone ... America/Chicago
|
||||
creating configuration files ... ok
|
||||
running bootstrap script ... ok
|
||||
performing post-bootstrap initialization ... ok
|
||||
syncing data to disk ... ok
|
||||
|
||||
initdb: warning: enabling "trust" authentication for local connections
|
||||
You can change this by editing pg_hba.conf or using the option -A, or
|
||||
--auth-local and --auth-host, the next time you run initdb.
|
||||
|
||||
Success. You can now start the database server using:
|
||||
|
||||
'/usr/local/opt/postgresql@13/bin/pg_ctl' -D postgres/data -l logfile start
|
||||
```
|
||||
|
||||
As stated at the end of the command's output, I can run the `postgres` server
|
||||
with that data directory with:
|
||||
|
||||
```bash
|
||||
$ '/usr/local/opt/postgresql@13/bin/pg_ctl' -D postgres/data -l logfile start
|
||||
```
|
||||
65
postgres/get-row-count-for-most-recent-query.md
Normal file
65
postgres/get-row-count-for-most-recent-query.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Get Row Count For Most Recent Query
|
||||
|
||||
Anytime you execute a query in `psql`, there is a _row count_ associated with
|
||||
that query. This is most naturally understood with a `select` query where a
|
||||
discreet number of rows are returned. We typically see the row count (e.g. `(19
|
||||
rows)`) right below the result set.
|
||||
|
||||
You can always reference the row count of the most recent query with [the
|
||||
`:ROW_COUNT`
|
||||
variable](https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-VARIABLES-ROW-COUNT).
|
||||
Here we use `\echo` to print it out.
|
||||
|
||||
```sql
|
||||
> select generate_series(2,20);
|
||||
generate_series
|
||||
-----------------
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
20
|
||||
(19 rows)
|
||||
|
||||
Time: 12.338 ms
|
||||
> \echo :ROW_COUNT
|
||||
19
|
||||
```
|
||||
|
||||
For some queries, like one that induces a pager (e.g. `less`) to be used,
|
||||
you'll lose track of the row count once the pager closes. This is where being
|
||||
able to reference the row count without rerunning the query is most useful.
|
||||
|
||||
```sql
|
||||
> select generate_series(2,2000);
|
||||
Time: 9.815 ms
|
||||
> \echo :ROW_COUNT
|
||||
1999
|
||||
```
|
||||
|
||||
Notice, we can also get a row count from other kinds of queries like this
|
||||
`insert` statement.
|
||||
|
||||
```sql
|
||||
> insert into users (id) values (50001), (50002), (50003);
|
||||
INSERT 0 3
|
||||
Time: 2.804 ms
|
||||
> \echo :ROW_COUNT
|
||||
3
|
||||
```
|
||||
|
||||
[source](https://postgresql.verite.pro/blog/2024/05/13/advanced-psql-coproc.html)
|
||||
33
postgres/include-columns-in-a-covering-index.md
Normal file
33
postgres/include-columns-in-a-covering-index.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Include Columns In A Covering Index
|
||||
|
||||
A _covering index_ is a special type of B-Tree index that, in addition to
|
||||
indexing on a certain field, also _includes_ one or more columns as extra data
|
||||
in the leaves of the tree. When created correctly, this can speed up the
|
||||
queries it targets by achieving an _index-only scan_.
|
||||
|
||||
Let's say we have a frequently run query on a large `events` table that looks
|
||||
like this:
|
||||
|
||||
```sql
|
||||
select user_id, identifier, type
|
||||
from events
|
||||
where user_id = $1;
|
||||
```
|
||||
|
||||
Here is what it looks like to create an index for this query with the `include`
|
||||
keyword:
|
||||
|
||||
```sql
|
||||
create index user_id_on_events_idx
|
||||
on (user_id)
|
||||
include (identifier, type);
|
||||
```
|
||||
|
||||
An index on its own can already cause a significant speed up to the queries it
|
||||
targets, but may still need to retrieve some `select` attributes from the
|
||||
table. For hot-path queries with a set of specific columns always included in
|
||||
the select, there can be significant additional speed ups by having the index
|
||||
_cover_ those columns.
|
||||
|
||||
For more details, check out [A Close Look At The Index Include
|
||||
Clause](https://use-the-index-luke.com/blog/2019-04/include-columns-in-btree-indexes).
|
||||
37
prisma/check-if-database-and-schema-are-not-in-sync.md
Normal file
37
prisma/check-if-database-and-schema-are-not-in-sync.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Check If Database And Schema Are Not In Sync
|
||||
|
||||
The [`prisma migrate
|
||||
diff`](https://www.prisma.io/docs/orm/reference/prisma-cli-reference#migrate-diff)
|
||||
command is a versatile tool that can be used to check if there is a difference
|
||||
between two sources. In this case, we want to check if our database is in sync
|
||||
with the `schema.prisma` file for our project.
|
||||
|
||||
If we have made changes to the schema file, but haven't yet migrated or pushed
|
||||
those changes to our local database, then we want to be notified of that
|
||||
mismatch.
|
||||
|
||||
We'll point at the schema file with `--to-schema-datamodel` and at our local
|
||||
database with `--from-url`.
|
||||
|
||||
```bash
|
||||
❯ npx prisma migrate diff \
|
||||
--to-schema-datamodel ./prisma/schema.prisma \
|
||||
--from-url mysql://root@localhost:3309/kcd-products
|
||||
|
||||
[*] Changed the `User` table
|
||||
[+] Added column `metadata`
|
||||
```
|
||||
|
||||
In the case where there is a different, we see an output summary of the diff.
|
||||
|
||||
Let's say we've applied our changes (`prisma db push`) to our local database.
|
||||
If we now run that same command again, we can see that no difference is
|
||||
detected and our database is in sync with our schema.
|
||||
|
||||
```bash
|
||||
❯ npx prisma migrate diff \
|
||||
--to-schema-datamodel ./prisma/schema.prisma \
|
||||
--from-url mysql://root@localhost:3309/kcd-products
|
||||
|
||||
No difference detected.
|
||||
```
|
||||
42
prisma/override-table-name-for-prisma-model.md
Normal file
42
prisma/override-table-name-for-prisma-model.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Override Table Name For Prisma Model
|
||||
|
||||
When defining your Prisma schema, you'll add models to your
|
||||
`prisma/schema.prisma` file that look something like this:
|
||||
|
||||
```
|
||||
model Book {
|
||||
id BigInt @id @default(autoincrement()) @db.BigInt
|
||||
title String
|
||||
author String
|
||||
publication_year Int
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
}
|
||||
```
|
||||
|
||||
The prisma client (ORM-layer) that gets generated will have a `Book` type and
|
||||
you'll be able to reference the model to, for instance, create a record with
|
||||
`prisma.book.create(...)`. Both of these things are derived from the model
|
||||
name: `Book`.
|
||||
|
||||
The other thing that is derived from the model name is the name given to the
|
||||
underlying database table. So you end up with a table called `Book`. You may,
|
||||
however, prefer a table naming convention where this one would be named `books`
|
||||
(snake_case and pluralized).
|
||||
|
||||
To achieve that, you have to manually override the table name with [the `@@map`
|
||||
directive](https://www.prisma.io/docs/orm/reference/prisma-schema-reference#map-1).
|
||||
Add it toward the bottom of the model like so:
|
||||
|
||||
```
|
||||
model Book {
|
||||
id BigInt @id @default(autoincrement()) @db.BigInt
|
||||
title String
|
||||
author String
|
||||
publication_year Int
|
||||
created_at DateTime @default(now())
|
||||
updated_at DateTime @updatedAt
|
||||
|
||||
@@map("books")
|
||||
}
|
||||
```
|
||||
31
python/use-pipx-to-install-end-user-apps.md
Normal file
31
python/use-pipx-to-install-end-user-apps.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Use pipx To Install End User Apps
|
||||
|
||||
The [`pipx`](https://pipx.pypa.io/stable/) tool is an installer for the python
|
||||
ecosystem. It differs from `pip` in that it is for installing end-user
|
||||
applications and it does so in isolated environments.
|
||||
|
||||
You can install `pipx` with an OS-specific installer like Homebrew:
|
||||
|
||||
```bash
|
||||
$ brew install pipx
|
||||
```
|
||||
|
||||
Ensure `pipx`-installed apps are on your path:
|
||||
|
||||
```bash
|
||||
$ pipx ensurepath
|
||||
```
|
||||
|
||||
Then use `pipx` to install programs like
|
||||
[`cowsay`](https://pypi.org/project/cowsay/) or
|
||||
[`llm`](https://llm.datasette.io/en/stable/setup.html):
|
||||
|
||||
```bash
|
||||
$ pipx install llm
|
||||
|
||||
$ which llm
|
||||
/Users/jbranchaud/.local/bin/llm
|
||||
|
||||
$ llm --version
|
||||
llm, version 0.13.1
|
||||
```
|
||||
37
rails/get-formatted-utc-offset-value.md
Normal file
37
rails/get-formatted-utc-offset-value.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Get Formatted UTC Offset Value
|
||||
|
||||
The UTC offset (during DST) for Chicago is `-05:00`. And for Newfoundland it is
|
||||
`-02:30`.
|
||||
|
||||
Rails has an [`ActiveSupport::TimeZone`
|
||||
module](https://api.rubyonrails.org/v7.1.3.2/classes/ActiveSupport/TimeZone.html#method-c-seconds_to_utc_offset)
|
||||
that can turn the UTC offset in seconds into this formatted value.
|
||||
|
||||
```ruby
|
||||
> chicago = TZInfo::Timezone.get('America/Chicago')
|
||||
=> #<TZInfo::DataTimezone: America/Chicago>
|
||||
> ActiveSupport::TimeZone.seconds_to_utc_offset(chicago.utc_offset)
|
||||
=> "-05:00"
|
||||
|
||||
> newfoundland = TZInfo::Timezone.get('America/St_Johns')
|
||||
=> #<TZInfo::DataTimezone: America/St_Johns>
|
||||
> ActiveSupport::TimeZone.seconds_to_utc_offset(newfoundland.utc_offset)
|
||||
=> "-02:30"
|
||||
```
|
||||
|
||||
The underlying `tzinfo` gem is DST-aware and its database even knows which time
|
||||
zone identifiers don't observe DST, so you can run this anytime of the year and
|
||||
expect reliable results.
|
||||
|
||||
Here is another way at this:
|
||||
|
||||
```ruby
|
||||
> chicago = TZInfo::Timezone.get('America/Chicago')
|
||||
=> #<TZInfo::DataTimezone: America/Chicago>
|
||||
> ActiveSupport::TimeZone[chicago.name]
|
||||
=> #<ActiveSupport::TimeZone:0x00000001099d8140 @name="America/Chicago", @tzinfo=#<TZInfo::DataTimezone: America/Chicago>, @utc_offset=nil>
|
||||
> ActiveSupport::TimeZone[chicago.name].formatted_offset
|
||||
=> "-06:00"
|
||||
> ActiveSupport::TimeZone[chicago.name].formatted_offset(false)
|
||||
=> "-0600"
|
||||
```
|
||||
33
rails/look-up-time-zone-info-for-identifier.md
Normal file
33
rails/look-up-time-zone-info-for-identifier.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Look Up Time Zone Info For Identifier
|
||||
|
||||
The `ActiveSupport::TimeZone` class overrides the `#[]` method to be a lookup
|
||||
mechanism for IANA Time Zone Identifier strings. These are strings like
|
||||
`America/Chicago` (or anything else listed under `TZInfo::Timezone.all`).
|
||||
|
||||
Let's get an instance for `America/Chicago`.
|
||||
|
||||
```ruby
|
||||
> chi = ActiveSupport::TimeZone['America/Chicago']
|
||||
=> #<ActiveSupport::TimeZone:0x00000001099d8140
|
||||
@name="America/Chicago",
|
||||
@tzinfo=#<TZInfo::DataTimezone: America/Chicago>,
|
||||
@utc_offset=nil>
|
||||
```
|
||||
|
||||
Notice it has a `tzinfo` instance variable that we can access. That object
|
||||
contains all kinds of useful things.
|
||||
|
||||
```ruby
|
||||
> chi.tzinfo.name
|
||||
=> "America/Chicago"
|
||||
> chi.tzinfo.friendly_identifier
|
||||
=> "America - Chicago"
|
||||
> chi.tzinfo.abbr
|
||||
=> "CDT"
|
||||
> chi.tzinfo.utc_offset
|
||||
=> -18000
|
||||
> chi.tzinfo.dst?
|
||||
=> true
|
||||
```
|
||||
|
||||
All of these and more. Run `ls chi.tzinfo` in a `pry` session to see what else.
|
||||
47
ruby/define-multiline-strings-with-heredocs.md
Normal file
47
ruby/define-multiline-strings-with-heredocs.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# Define Multiline Strings With Heredocs
|
||||
|
||||
[A _heredoc_ (_here document_) is a special ruby
|
||||
syntax](https://ruby-doc.org/core-2.5.0/doc/syntax/literals_rdoc.html#label-Here+Documents)
|
||||
for defining formatted multiline strings. These are useful for any situation
|
||||
where you need to define a block of text where newlines and indentation are
|
||||
preserved -- e.g. output an error, help message, or some formatted SQL.
|
||||
|
||||
The standard syntax is defined with `<<` and some uppercase identifier (e.g.
|
||||
`TXT`, `DOC`, `SQL`, etc.) to open and close the multiline string.
|
||||
|
||||
```ruby
|
||||
def lookup_team(team_id)
|
||||
query = <<SQL
|
||||
select users.id from users
|
||||
join teams
|
||||
on teams.id = users.team_id
|
||||
where teams.id = #{team_id}
|
||||
order by created_at desc
|
||||
limit 10;
|
||||
SQL
|
||||
|
||||
team_member_ids = db.execute(query)
|
||||
end
|
||||
```
|
||||
|
||||
With the SQL formatted this way, it is easier to read and we can print/log out
|
||||
this nicely formatted version to make debugging easier.
|
||||
|
||||
Notice that the terminating `SQL` identifier is fully left justified. I find
|
||||
that visually off relative to the indentation of everything else, so I like to
|
||||
use the _indented_ heredoc syntax (`<<-`).
|
||||
|
||||
```ruby
|
||||
def lookup_team(team_id)
|
||||
query = <<-SQL
|
||||
select users.id from users
|
||||
join teams
|
||||
on teams.id = users.team_id
|
||||
where teams.id = #{team_id}
|
||||
order by created_at desc
|
||||
limit 10;
|
||||
SQL
|
||||
|
||||
team_member_ids = db.execute(query)
|
||||
end
|
||||
```
|
||||
42
ruby/get-utc-offset-for-different-time-zones.md
Normal file
42
ruby/get-utc-offset-for-different-time-zones.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# Get UTC Offset For Different Time Zones
|
||||
|
||||
The [IANA Time Zone Database](https://www.iana.org/time-zones) uses identifiers
|
||||
like `America/Chicago`, `Asia/Hong_Kong`, `Africa/Nairobi`, etc. as specifiers
|
||||
for notable locations with time zone information.
|
||||
|
||||
> Most timezones correspond to a notable location and the database records all
|
||||
> known clock transitions for that location; some timezones correspond instead
|
||||
> to a fixed UTC offset.
|
||||
—[Theory and pragmatics of the tz code and data](https://data.iana.org/time-zones/theory.html)
|
||||
|
||||
These identifiers can be used to look up time zone details with the [`tzinfo`
|
||||
gem](https://github.com/tzinfo/tzinfo).
|
||||
|
||||
Here is an example of passing one to the `#get` method and then getting the UTC
|
||||
offset in seconds.
|
||||
|
||||
```ruby
|
||||
> require 'tzinfo'
|
||||
|
||||
> mountain = TZInfo::Timezone.get('America/Denver')
|
||||
=> #<TZInfo::DataTimezone: America/Denver>
|
||||
> mountain.utc_offset
|
||||
=> -21600
|
||||
```
|
||||
|
||||
We can even get the base UTC offset that doesn't account for DST:
|
||||
|
||||
```ruby
|
||||
> moutain.base_utc_offset
|
||||
=> -25200
|
||||
```
|
||||
|
||||
Notice, this is the same as the standard offset for a time zone like Phoenix
|
||||
that doesn't observe DST.
|
||||
|
||||
```ruby
|
||||
> phoenix = TZInfo::Timezone.get('America/Phoenix')
|
||||
=> #<TZInfo::DataTimezone: America/Phoenix>
|
||||
> phoenix.utc_offset
|
||||
=> -25200
|
||||
```
|
||||
36
unix/find-top-level-directories-matching-a-pattern.md
Normal file
36
unix/find-top-level-directories-matching-a-pattern.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Find Top-Level Directories Matching A Pattern
|
||||
|
||||
I like using [`fd`](https://github.com/sharkdp/fd) as an alternative to `find`.
|
||||
In my experience it is more intuitive to use. For instance, I wanted to find
|
||||
all the top-level directories in my current directory that contained the word
|
||||
`next`. I was able to get the command mostly right by guessing the flags, only
|
||||
checking the man page once.
|
||||
|
||||
On my first attempt, it prompted me with a suggestion for a flag that wasn't
|
||||
quite right. I tried `--depth`, but it should have been `--maxdepth`.
|
||||
|
||||
```bash
|
||||
$ fd --depth 0 next ./
|
||||
error: Found argument '--depth' which wasn't expected, or isn't valid in this context
|
||||
Did you mean --maxdepth?
|
||||
```
|
||||
|
||||
Then I checked the man page for how to specify the file type as _directory_ --
|
||||
using `-t` or `--type` with `d`.
|
||||
|
||||
And here is the command that gets me all top-level directories matching `next`
|
||||
in my current directory:
|
||||
|
||||
```bash
|
||||
$ fd --maxdepth 1 --type d next ./
|
||||
|
||||
bookshelf-nextjs-prisma-postgres
|
||||
bookshelf-prisma-nextjs-planetscale
|
||||
my-next-app
|
||||
next-bookshelf
|
||||
next-personal-site
|
||||
next-sanity-v3-example
|
||||
try-trpc-next
|
||||
```
|
||||
|
||||
See `man fd` for more details.
|
||||
25
unix/generate-base64-encoding-without-newlines.md
Normal file
25
unix/generate-base64-encoding-without-newlines.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generate Base64 Encoding Without Newlines
|
||||
|
||||
There are a variety of tools that can generate a Base64 encoding of given text.
|
||||
Most of them that I've encountered have a number of characters at which they
|
||||
introduce a newline character. Here is `openssl` as an example:
|
||||
|
||||
```bash
|
||||
❯ echo "here is a long bit of text to base64 encode with openssl" | openssl base64
|
||||
aGVyZSBpcyBhIGxvbmcgYml0IG9mIHRleHQgdG8gYmFzZTY0IGVuY29kZSB3aXRo
|
||||
IG9wZW5zc2wK
|
||||
```
|
||||
|
||||
[The theory I've seen](https://superuser.com/a/1225139) is that this is to
|
||||
accommodate 80-character terminal screens when chunks of encoding were included
|
||||
in emails.
|
||||
|
||||
With the `openssl base64` command, there is not an option to exclude the
|
||||
newlines, but we can pipe it through `tr` to remove them.
|
||||
|
||||
```bash
|
||||
❯ echo "here is a long bit of text to base64 encode with openssl" | \
|
||||
openssl base64 | \
|
||||
tr -d '\n'
|
||||
aGVyZSBpcyBhIGxvbmcgYml0IG9mIHRleHQgdG8gYmFzZTY0IGVuY29kZSB3aXRoIG9wZW5zc2wK
|
||||
```
|
||||
36
unix/get-a-list-of-locales-on-your-system.md
Normal file
36
unix/get-a-list-of-locales-on-your-system.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# Get A List Of Locales On Your System
|
||||
|
||||
The `locale -a` command will list all the available locales on your system.
|
||||
|
||||
You'll see a giant list that probably includes these and many more values.
|
||||
|
||||
```bash
|
||||
$ locale -a
|
||||
|
||||
en_NZ
|
||||
nl_NL.UTF-8
|
||||
pt_BR.UTF-8
|
||||
fr_CH.ISO8859-15
|
||||
eu_ES.ISO8859-15
|
||||
en_US.US-ASCII
|
||||
af_ZA
|
||||
bg_BG
|
||||
cs_CZ.UTF-8
|
||||
fi_FI
|
||||
zh_CN.UTF-8
|
||||
eu_ES
|
||||
sk_SK.ISO8859-2
|
||||
nl_BE
|
||||
fr_BE
|
||||
sk_SK
|
||||
en_US.UTF-8
|
||||
...
|
||||
```
|
||||
|
||||
Each of these locales identifies itself by the language and the manner in which
|
||||
the language is used in a particular place. For example, `en_NZ` is _English as
|
||||
it is spoken in New Zealand_. `fr_BE` is _French as it is spoken in Belgium_.
|
||||
`en_US.UTF-8` is _English as it is spoken in the US, with a UTF-8 character set
|
||||
encoding_.
|
||||
|
||||
[source](https://www.postgresql.org/docs/current/locale.html#LOCALE-OVERVIEW)
|
||||
31
vscode/find-the-location-of-user-settings-json-file.md
Normal file
31
vscode/find-the-location-of-user-settings-json-file.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Find The Location Of User Settings JSON File
|
||||
|
||||
There are a ton ways to customize and fine-tune VS Code. All of the settings
|
||||
have defaults which can then be customized on a workspace and user level.
|
||||
Typically you'll access these files within VS Code via the Command Palette. I
|
||||
was curious though: since it is just a JSON file, surely I can view and modify
|
||||
it with any editor.
|
||||
|
||||
On a Mac, the user-level `settings.json` file is located at
|
||||
`~/Library/Application\ Support/Code/User/settings.json`.
|
||||
|
||||
Open it up and you might see something like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"window.zoomLevel": 1,
|
||||
"workbench.editor.showTabs": "single"
|
||||
}
|
||||
```
|
||||
|
||||
A handful of settings with specific overrides.
|
||||
|
||||
Feel free to edit what is in here or add other settings that you want to set.
|
||||
Just make sure you know what you're doing and that you set valid values.
|
||||
|
||||
The VS Code docs list [the locations of these files on other operating
|
||||
systems](https://code.visualstudio.com/docs/getstarted/settings#_settings-file-locations).
|
||||
|
||||
[source](https://stackoverflow.com/questions/53840644/location-of-vs-code-preferences)
|
||||
29
workflow/access-1password-credential-from-cli.md
Normal file
29
workflow/access-1password-credential-from-cli.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Access 1Password Credential From CLI
|
||||
|
||||
With the `op` CLI, I can store things like API keys and secrets in my 1Password
|
||||
vault and then access them from the command line. This assumes I've already
|
||||
installed the CLI (`brew install 1password-cli`) and connected it to the
|
||||
1Password app via the _Developer_ settings.
|
||||
|
||||
The `op item get` command takes a credential name and returns all the details
|
||||
for the entry with that _Title_. Here is how I can access my _Anthropic Claude
|
||||
API Key_ details.
|
||||
|
||||
```bash
|
||||
$ op item get "Anthropic Claude API Key"
|
||||
```
|
||||
|
||||
With the `--field` flag, I can grab a specific field, such as the `credential`,
|
||||
from that entry.
|
||||
|
||||
```bash
|
||||
$ op item get "Anthropic Claude API Key" --field credential
|
||||
sk-ant-api03-abc......xyz
|
||||
```
|
||||
|
||||
A command like this can be embedded in other commands as a way of referencing
|
||||
secrets without explicitly entering them into your shell history.
|
||||
|
||||
```bash
|
||||
$ curl https://api -H "x-api-key: $(op item get "Anthropic Claude API Key" --field credential)" ...
|
||||
```
|
||||
Reference in New Issue
Block a user