1
0
mirror of https://github.com/jbranchaud/til synced 2026-01-17 05:58:01 +00:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Nuno Vieira
2d74f9c88a Merge 460473a87f into 84e2c9c6f4 2024-05-21 10:06:13 +05:30
jbranchaud
84e2c9c6f4 Add Override Table Name For Prisma Model as a Prisma TIL 2024-05-20 09:05:44 -05:00
jbranchaud
39614e975e Add Find Top-Level Directories Matching A Pattern as a Unix TIL 2024-05-19 10:08:45 -05:00
jbranchaud
44e626a086 Add source link for latest TIL 2024-05-16 14:50:34 -05:00
jbranchaud
48d2ecffa0 Add Get Row Count For Most Recent Query as a Postgres TIL 2024-05-16 14:49:37 -05:00
jbranchaud
6fb3b95ade Add Check If Database And Schema Are Not In Sync as a Prisma TIL 2024-05-15 12:21:38 -05:00
jbranchaud
51880975d4 Add Set Value On Null JSON Column as a MySQL TIL 2024-05-14 11:01:17 -05:00
jbranchaud
03980ab291 Add Format Time Zone Identifier as a JavaScript TIL 2024-05-13 12:59:15 -05:00
jbranchaud
bef492fe3a Add Generate Base64 Encoding Without Newlines as a Unix TIL 2024-05-05 11:39:10 -05:00
jbranchaud
36004e6d20 Add Remove Untracked Files From A Directory as a Git TIL 2024-05-03 10:11:00 -05:00
jbranchaud
18e52b9dbb Add Get A List Of Locales On Your System as a Unix TIL 2024-05-02 14:31:01 -05:00
jbranchaud
01c9c0d19b Add Add Only Tracked Files From A Directory as a Git TIL 2024-05-01 09:31:52 -05:00
jbranchaud
c06bb2ea7b Add Find The Location Of User Settings JSON File as a VSCode TIL 2024-04-28 20:28:57 -05:00
jbranchaud
7dad6508d0 Fix typo in code snippet for latest TIL 2024-04-27 23:00:38 -05:00
jbranchaud
5bcdbbb3c7 Add Include Columns In A Covering Index as a Postgres TIL 2024-04-27 22:48:32 -05:00
jbranchaud
41f5b526d2 Add Ensure Lookup Can Be Retried as an Inngest TIL 2024-04-26 23:26:51 -05:00
jbranchaud
e974a184c6 Add Check If Clusters Are Upgrade Compatible as a Postgres TIL 2024-04-25 20:25:48 -05:00
jbranchaud
c832b9a70d Add Look Up Time Zone Info For Identifier as a Rails TIL 2024-04-25 10:50:49 -05:00
jbranchaud
42854fdc38 Add Create A Cluster In A Specific Data Directory as a Postgres TIL 2024-04-23 18:04:45 -05:00
jbranchaud
eff2c548cd Add List All Services Managed By Brew as a Brew TIL 2024-04-23 15:41:01 -05:00
jbranchaud
1b229b39f1 Add Use The llm CLI With Claude Models as an LLM TIL 2024-04-22 20:54:58 -05:00
jbranchaud
2543651ec0 Add Use pipx To Install End User Apps as a Python TIL 2024-04-22 19:47:09 -05:00
jbranchaud
f3d7cf8a06 Add Access 1Password Credential From CLI as a Workflow TIL 2024-04-21 19:57:10 -05:00
jbranchaud
72089e11db Add Send cURL To Claude Text Completion API as an LLM TIL 2024-04-21 19:06:13 -05:00
jbranchaud
b766f20012 Add Define Multiline Strings With Heredocs as a Ruby TIL 2024-04-21 13:46:04 -05:00
jbranchaud
505220d9de Add Convert Seconds To Date Object as a JavaScript TIL 2024-04-19 14:38:40 -05:00
jbranchaud
9684c6a6db Add Get Formatted UTC Offset Value as a Rails TIL 2024-04-18 14:32:46 -05:00
jbranchaud
3b0d76e805 Add Get UTC Offset For Different Time Zones as a Ruby TIL 2024-04-18 10:49:29 -05:00
jbranchaud
b6c8192a04 Add Make Elements Non-Interactive With Inert as an HTML TIL 2024-04-12 11:54:52 -06:00
Nuno Vieira
460473a87f Fix expected result of immutable remove operation 2020-07-30 14:32:08 +01:00
28 changed files with 983 additions and 5 deletions

View File

@@ -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)

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View 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.

View File

@@ -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.

View 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)

View 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.

View 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.

View 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.

View 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
```

View 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)

View 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).

View 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.
```

View 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")
}
```

View 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
```

View 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"
```

View 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.

View 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
```

View 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
```

View 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.

View 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
```

View 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)

View 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)

View 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)" ...
```