Export a Table or Query Result to a CSV File from Postgres

To export data from a table T (or any result of a query) in a PostgreSQL database use the following command:

$ psql -h localhost
       -U database_usr
       -d database_name
       -c "COPY (SELECT * FROM T) 
           TO '/path/file.csv' 
           DELIMITER ',' CSV HEADER;"

Notes:

  • The query should be on one line; it is split here for readability.
  • Make sure you have the correct permissions to write to the directory referenced. The command may need to be run with sudo.

 

Simulate any HTTP Status Code from a URL for Testing

Testing code which calls APIs often involves handling various HTTP status codes from an endpoint.
When calling an external service, it may be difficult to trigger specific HTTP status codes for errors to test out code paths triggered only by those status codes being returned.
We can call the service httpstat.us with the desired response code in the URL path to get any arbitrary HTTP status code returned.

For example, using cURL:

$ curl -v http://httpstat.us/503

The result is:

> GET /503 HTTP/1.1
> Host: httpstat.us
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 503 Service Unavailable
...

Less common success status codes can be simulated as well:

$ curl -v http://httpstat.us/204

Result:

> GET /204 HTTP/1.1
> Host: httpstat.us
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 204 No Content
...

In a config file, we can use httpstat.us URLs instead of our actual dependencies to trigger error cases for tests.

See the full feature list of the HTTP Status service:

http://httpstat.us/

REST API Design: Transitive Inclusion, or Inlining Associated Objects

Transitive Inclusion (Transclusion for short) is a feature of REST APIs useful for clients wishing to get more than just the resource in the URL path, in one request.
We use a query string parameter called inline, or perhaps include, equal to the name of the associated objects to include.

For example, suppose that in a Books API, author objects have associated books.
A request for an author:

GET /authors/12345
{
  "id": 12345,
  "name": "Ralph Ellison"
}

The list of books associated with the author:

GET /authors/12345/books
[
  {
    "id": 1,
    "title": "Invisible Man"
  },
  {
    "id": 2,
    "title": "Juneteenth"
  }
]

We can pass the inline parameter on an author request:

GET /authors/12345?inline=books
{
  "id": 12345,
  "name": "Ralph Ellison",
  "books": [
    {
      "id": 1,
      "title": "Invisible Man"
    },
    {
      "id": 2,
      "title": "Juneteenth"
    }
  ]
}

Note the extra field “books” is included or inlined in the author object.
This way a client app can get the author object and associated books in one request, reducing round-trips. Of course if the objects are small, including the associated objects by default is the best option; this is mostly useful for large, expensive-to-retrieve associated objects.

The transitive inclusion feature can be even more powerful if we get a list of all authors in the API, inlining all of their associated books:

GET /authors?inline=books

Or we can include many associated objects:

GET /authors?include=books,articles

The result is a comprehensive list object, all in one request:

[
  {
    "id": 12345,
    "name": "Ralph Ellison",
    "books": [
      {
        "id": 1,
        "title": "Invisible Man"
      },
      {
        "id": 2,
        "title": "Juneteenth"
      }
    ],
    "articles": [ ... ]
  },
  {
    "id": 67890,
    "name": "Doris Lessing",
    "books": [
      {
        "id": 10,
        "title": "The Golden Notebook"
      },
      {
        "id": 11,
        "title": "The Fifth Child"
      },
      ...
    ],
    "articles": [ ... ]
  },
  ...
]

Such a comprehensive response object can be convenient for an app to build a page listing authors and books, for example; only a single HTTP request can be used .
Note that if the set is large, pagination can be used in addition.

 

Base64 Encode and Decode in Node.js

Using Node on the server side, we find that we cannot use the JavaScript functions atob and btoa. They are not defined; we get the following errors:

ReferenceError: btoa is not defined
ReferenceError: atob is not defined

The functions are defined in JavaScript in the browser, but not in server-side Node.js.

To encode to base-64, instead of btoa use the following:

const myString = 'hello'
const encoded = Buffer.from(myString)
                      .toString('base64')
console.log(encoded)

Output:

aGVsbG8=

To decode from base-64, instead of atob use the following:

const base64String = 'aGVsbG8='
const decoded = Buffer.from(base64String, 'base64')
                      .toString('utf-8')
console.log(decoded)

Output:

hello

 

Mock Only a Single Function from a Module with Jest

Recall that using jest.mock(module) mocks every function exported from the module.

But sometimes we need to mock only one or some functions in a module, leaving the others’ real implementations as-is.

Suppose we are using the following module of functions:

my-functions.js:

const f = () => 'Return from f'
const g = () => 'Return from g'
const h = () => 'Return from h'

module.exports = {
  f,
  g,
  h
}

The code below uses a Jest spy with a mock implementation to mock out just one function while leaving alone the original implementations of the other two.

my-functions.test.js:

const functions = require('./my-functions')

describe('mock only one function from module', () => {
  it('should return only one mocked result', () => {
    jest.spyOn(functions, 'g')
      .mockImplementation(() => '_mock_')

    console.log(functions.f())
    console.log(functions.g())
    console.log(functions.h())

    expect(functions.f()).toEqual('Return from f')
    expect(functions.g()).toEqual('_mock_')
    expect(functions.h()).toEqual('Return from h')
  })
})

Running the tests:

$ jest my-functions.test.js
PASS ./my-functions.test.js
mock only one function from module
✓ should return only one mocked result (14ms)

console.log my-functions.test.js:8
Return from f

console.log my-functions.test.js:9
_mock_

console.log my-functions.test.js:10
Return from h

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 0.956s
Ran all test suites matching /my-functions.test.js/i.

Note that only g() returns a mocked string.

 

Jest Mock Behaviour with mockReturnValueOnce

A Jest mock function can be set to return a specific value for all calls, or just once.

Note that if we define a return value with mockReturnValueOnce, the mock function will return undefined for all subsequent calls.
It will not throw an error and may go unnoticed, causing undesirable behaviour.

If a Jest mock returns undefined incorrectly check to make sure how it was defined and how many times it was called.

The code below shows the different behaviours:

describe('mock once tests', () => {
  test('many returns', () => {
    const f = jest.fn()
    f.mockReturnValueOnce('result')

    const result1 = f()
    console.log(result1)

    const result2 = f()
    console.log(result2)

    const result3 = f()
    console.log(result3)
  })

  test('one return', () => {
    const f = jest.fn()
    f.mockReturnValue('result')

    const result1 = f()
    console.log(result1)

    const result2 = f()
    console.log(result2)

    const result3 = f()
    console.log(result3)
  })
})

Output:

result
undefined
undefined

result
result
result

 

Force Vagrant to Re-download the Box File

Sometimes we want to download the operating system image file again and start from scratch when building a Vagrant VM.

If vagrant up does not load a new box even after a vagrant destroy of the existing VM, do the following.

Ensure the box_url variable in the Vagrantfile is set to the correct URL of the new box (config.vm.box_url).

View existing boxes to get the existing box name:

$ vagrant box list

Output:

myBox (virtualbox, 0)

Fully remove the box file:

$ vagrant box remove myBox

Now the box file listed in the Vagrantfile will be downloaded again when running vagrant up.

 

Format a Date as a Year-Month-Day String in JavaScript

To format a date in YYYYMMDD or similar string format in JavaScript, we can use the following. In this example we use the current date.

Using dateformat:

$ npm install dateformat
const dateFormat = require('dateformat')

const now = new Date()
const dateString = dateFormat(now, 'yyyymmdd')

console.log(dateString)

Result:

20210313

Using moment.js:

$ npm install moment
const moment = require('moment')

const now = new Date()
const dateString = moment(now).format('YYYYMMDD')

console.log(dateString)

Result:

20210313

References

https://www.npmjs.com/package/dateformat

https://www.npmjs.com/package/moment

 

Make Commit Message Lint Git Hook Run First with Commitlint and Husky

Enforcing a standard for commit messages with a commit-msg hook using something like commitlint is useful, but ideally if we have a commit message hook set up to lint the commit message, it should run first, before any test suite.
That is, if we have a large unit test suite which must pass before committing is possible, and it takes a long time to run (i.e. a minute or two), it is better to have a commit message problem fail first, quickly. It is annoying to run through a large, slow test suite successfully only to have a commit message lint prevent the entire commit at the end!

It is not possible to change the order of git hooks execution. Git does not have access to the commit message at that stage of processing.

However, using commitlint and Husky, we can achieve the desired order by simply using the commit-msg hook to trigger our tests instead of the pre-commit hook.
Inside .huskyrc (or the “husky” field inside package.json) we can change this:

{
  "hooks": {
    "commit-msg": "commitlint -e $GIT_PARAMS",
    "pre-commit": "npm test"
  }
}

Into this:

{
  "hooks": {
    "commit-msg": "commitlint -e $GIT_PARAMS && npm test"
  }
}

The commit-msg hook will run before the commit is actually made, so this is still a pre-commit hook requiring successful run of the unit tests before one can commit.
But any problem with the commit message itself will show up immediately.

 

Change Commit Message Length Limit in Commitlint Config

Writing descriptive commit messages is helpful to readers of code; sometimes the default limit for the number of characters enforced by Commitlint in a given configuration is too short for descriptions of very specific changes. To change the character length limit do the following.
Suppose we are using an existing set of rules (in this example, the Angular config) and just want to change the character limit to 200.
The config file below should achieve this:

commitlint.config.js

module.exports = {
  extends: ['@commitlint/config-angular'],
  rules: {
    'header-max-length': [2, 'always', 200],
  }
}

This will use all of the rules from config-angular but override the commit message length rule (header-max-length).

The first element 2 means “throw error” (1 means “warning”, 0 means “disable the rule”).

References

https://commitlint.js.org/#/reference-rules