mirror of
https://github.com/jbranchaud/til
synced 2026-01-13 20:18:03 +00:00
Compare commits
11 Commits
68fa39da4f
...
7215496ded
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7215496ded | ||
|
|
84e2c9c6f4 | ||
|
|
39614e975e | ||
|
|
44e626a086 | ||
|
|
48d2ecffa0 | ||
|
|
6fb3b95ade | ||
|
|
51880975d4 | ||
|
|
03980ab291 | ||
|
|
cea4ffc0a3 | ||
|
|
b325522d06 | ||
|
|
f9efe3174f |
12
README.md
12
README.md
@@ -2,15 +2,15 @@
|
||||
|
||||
> Today I Learned
|
||||
|
||||
A collection of concise write-ups on small things I learn day to day across a
|
||||
variety of languages and technologies. These are things that don't really
|
||||
A collection of concise write-ups on small things I learn day to day across a
|
||||
variety of languages and technologies. These are things that don't
|
||||
warrant a full blog post. These are things I've picked up by [Learning In
|
||||
Public™](https://dev.to/jbranchaud/how-i-built-a-learning-machine-45k9) and
|
||||
pairing with smart people at Hashrocket.
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186).
|
||||
|
||||
_1427 TILs and counting..._
|
||||
_1433 TILs and counting..._
|
||||
|
||||
---
|
||||
|
||||
@@ -462,6 +462,7 @@ _1427 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)
|
||||
@@ -610,6 +611,7 @@ _1427 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)
|
||||
@@ -732,6 +734,7 @@ _1427 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)
|
||||
@@ -822,10 +825,12 @@ _1427 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
|
||||
@@ -1373,6 +1378,7 @@ _1427 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)
|
||||
|
||||
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.
|
||||
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.
|
||||
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)
|
||||
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")
|
||||
}
|
||||
```
|
||||
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.
|
||||
Reference in New Issue
Block a user