neonctl 1.29.1 → 1.29.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/analytics.js +78 -0
  2. package/api.js +35 -0
  3. package/auth.js +101 -0
  4. package/{src/cli.ts → cli.js} +0 -1
  5. package/commands/auth.js +102 -0
  6. package/commands/auth.test.js +42 -0
  7. package/commands/branches.js +303 -0
  8. package/commands/branches.test.js +321 -0
  9. package/commands/connection_string.js +156 -0
  10. package/commands/connection_string.test.js +236 -0
  11. package/commands/databases.js +79 -0
  12. package/commands/databases.test.js +51 -0
  13. package/commands/help.test.js +11 -0
  14. package/{src/commands/index.ts → commands/index.js} +10 -11
  15. package/commands/ip_allow.js +135 -0
  16. package/commands/ip_allow.test.js +78 -0
  17. package/commands/operations.js +28 -0
  18. package/commands/operations.test.js +11 -0
  19. package/commands/projects.js +186 -0
  20. package/commands/projects.test.js +132 -0
  21. package/commands/roles.js +57 -0
  22. package/commands/roles.test.js +42 -0
  23. package/commands/set_context.js +22 -0
  24. package/commands/set_context.test.js +53 -0
  25. package/commands/user.js +15 -0
  26. package/config.js +11 -0
  27. package/context.js +48 -0
  28. package/env.js +6 -0
  29. package/errors.js +16 -0
  30. package/help.js +146 -0
  31. package/index.js +168 -0
  32. package/log.js +15 -0
  33. package/package.json +1 -1
  34. package/parameters.gen.js +322 -0
  35. package/pkg.js +3 -45
  36. package/test_utils/mock_server.js +16 -0
  37. package/test_utils/oauth_server.js +9 -0
  38. package/test_utils/test_cli_command.js +80 -0
  39. package/types.js +1 -0
  40. package/utils/enrichers.js +49 -0
  41. package/utils/formats.js +5 -0
  42. package/utils/formats.test.js +32 -0
  43. package/utils/middlewares.js +20 -0
  44. package/utils/point_in_time.js +50 -0
  45. package/utils/psql.js +24 -0
  46. package/utils/string.js +5 -0
  47. package/utils/ui.js +59 -0
  48. package/writer.js +87 -0
  49. package/writer.test.js +86 -0
  50. package/.bump +0 -1
  51. package/.editorconfig +0 -7
  52. package/.eslintrc.cjs +0 -15
  53. package/.github/workflows/commitlint.yml +0 -46
  54. package/.github/workflows/pr.yml +0 -25
  55. package/.github/workflows/release.yml +0 -30
  56. package/.husky/commit-msg +0 -4
  57. package/.husky/pre-commit +0 -4
  58. package/.nvmrc +0 -1
  59. package/.prettierignore +0 -3
  60. package/.prettierrc.json +0 -3
  61. package/.releaserc.json +0 -47
  62. package/LICENSE +0 -202
  63. package/commitlint.config.cjs +0 -7
  64. package/generateOptionsFromSpec.ts +0 -68
  65. package/jest/setup.js +0 -5
  66. package/jest.config.ts +0 -199
  67. package/mocks/bin/psql.cjs +0 -9
  68. package/mocks/main/projects/GET.js +0 -27
  69. package/mocks/main/projects/POST.js +0 -22
  70. package/mocks/main/projects/shared/GET.js +0 -16
  71. package/mocks/main/projects/test/DELETE.json +0 -7
  72. package/mocks/main/projects/test/GET.json +0 -13
  73. package/mocks/main/projects/test/PATCH.js +0 -18
  74. package/mocks/main/projects/test/branches/GET.json +0 -25
  75. package/mocks/main/projects/test/branches/POST.js +0 -83
  76. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/DELETE.json +0 -7
  77. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/GET.json +0 -9
  78. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/PATCH.js +0 -14
  79. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/GET.json +0 -6
  80. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/POST.js +0 -13
  81. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/databases/test_db/DELETE.json +0 -6
  82. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/GET.json +0 -26
  83. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/endpoints/POST.json +0 -6
  84. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/GET.json +0 -3
  85. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/POST.js +0 -14
  86. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/DELETE.json +0 -6
  87. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/roles/test_role/reveal_password/GET.json +0 -3
  88. package/mocks/main/projects/test/branches/br-cloudy-branch-12345678/set_as_primary/POST.json +0 -9
  89. package/mocks/main/projects/test/branches/br-numbered-branch-123456/GET.json +0 -10
  90. package/mocks/main/projects/test/branches/br-sunny-branch-123456/DELETE.json +0 -7
  91. package/mocks/main/projects/test/branches/br-sunny-branch-123456/GET.json +0 -10
  92. package/mocks/main/projects/test/branches/br-sunny-branch-123456/PATCH.js +0 -14
  93. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/GET.json +0 -6
  94. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/POST.js +0 -13
  95. package/mocks/main/projects/test/branches/br-sunny-branch-123456/databases/test_db/DELETE.json +0 -6
  96. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/GET.json +0 -26
  97. package/mocks/main/projects/test/branches/br-sunny-branch-123456/endpoints/POST.json +0 -6
  98. package/mocks/main/projects/test/branches/br-sunny-branch-123456/restore/POST.js +0 -16
  99. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/GET.json +0 -3
  100. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/POST.js +0 -14
  101. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/DELETE.json +0 -6
  102. package/mocks/main/projects/test/branches/br-sunny-branch-123456/roles/test_role/reveal_password/GET.json +0 -3
  103. package/mocks/main/projects/test/branches/br-sunny-branch-123456/set_as_primary/POST.json +0 -9
  104. package/mocks/main/projects/test/endpoints/GET.json +0 -9
  105. package/mocks/main/projects/test/endpoints/POST.js +0 -32
  106. package/mocks/main/projects/test/endpoints/test_endpoint_id/DELETE.json +0 -7
  107. package/mocks/main/projects/test/endpoints/test_endpoint_id/GET.json +0 -9
  108. package/mocks/main/projects/test/endpoints/test_endpoint_id/PATCH.js +0 -17
  109. package/mocks/main/projects/test/operations/GET.json +0 -22
  110. package/mocks/main/users/me/GET.json +0 -5
  111. package/mocks/restore/projects/test/branches/GET.json +0 -21
  112. package/mocks/restore/projects/test/branches/br-another-branch-123456/GET.json +0 -6
  113. package/mocks/restore/projects/test/branches/br-another-branch-123456/restore/POST.js +0 -13
  114. package/mocks/restore/projects/test/branches/br-any-branch-123456/GET.json +0 -6
  115. package/mocks/restore/projects/test/branches/br-parent-tots-123456/GET.json +0 -7
  116. package/mocks/restore/projects/test/branches/br-parent-tots-123456/restore/POST.js +0 -14
  117. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/GET.json +0 -6
  118. package/mocks/restore/projects/test/branches/br-self-tolsn-123456/restore/POST.js +0 -15
  119. package/mocks/single_project/projects/GET.json +0 -10
  120. package/mocks/single_project/projects/test-project-123456/GET.json +0 -14
  121. package/mocks/single_project/projects/test-project-123456/branches/GET.json +0 -11
  122. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/databases/GET.json +0 -3
  123. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/endpoints/GET.json +0 -10
  124. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/GET.json +0 -3
  125. package/mocks/single_project/projects/test-project-123456/branches/br-main-branch-123456/roles/test_role/reveal_password/GET.json +0 -3
  126. package/rollup.config.js +0 -20
  127. package/snapshots/commands/branches.test.snap +0 -221
  128. package/snapshots/commands/connection_string.test.snap +0 -70
  129. package/snapshots/commands/databases.test.snap +0 -20
  130. package/snapshots/commands/ip_allow.test.snap +0 -55
  131. package/snapshots/commands/operations.test.snap +0 -17
  132. package/snapshots/commands/projects.test.snap +0 -141
  133. package/snapshots/commands/roles.test.snap +0 -19
  134. package/snapshots/commands/set_context.test.snap +0 -30
  135. package/snapshots/writer.test.snap +0 -60
  136. package/snapshotsResolver.cjs +0 -32
  137. package/src/analytics.ts +0 -95
  138. package/src/api.ts +0 -44
  139. package/src/auth.ts +0 -137
  140. package/src/commands/auth.test.ts +0 -62
  141. package/src/commands/auth.ts +0 -148
  142. package/src/commands/branches.test.ts +0 -354
  143. package/src/commands/branches.ts +0 -451
  144. package/src/commands/connection_string.test.ts +0 -250
  145. package/src/commands/connection_string.ts +0 -210
  146. package/src/commands/databases.test.ts +0 -55
  147. package/src/commands/databases.ts +0 -129
  148. package/src/commands/help.test.ts +0 -13
  149. package/src/commands/ip_allow.test.ts +0 -86
  150. package/src/commands/ip_allow.ts +0 -202
  151. package/src/commands/operations.test.ts +0 -13
  152. package/src/commands/operations.ts +0 -41
  153. package/src/commands/projects.test.ts +0 -147
  154. package/src/commands/projects.ts +0 -275
  155. package/src/commands/roles.test.ts +0 -46
  156. package/src/commands/roles.ts +0 -100
  157. package/src/commands/set_context.test.ts +0 -64
  158. package/src/commands/set_context.ts +0 -27
  159. package/src/commands/user.ts +0 -21
  160. package/src/config.ts +0 -22
  161. package/src/context.ts +0 -61
  162. package/src/env.ts +0 -7
  163. package/src/errors.ts +0 -24
  164. package/src/help.ts +0 -185
  165. package/src/index.ts +0 -180
  166. package/src/log.ts +0 -16
  167. package/src/parameters.gen.ts +0 -332
  168. package/src/pkg.ts +0 -9
  169. package/src/test_utils/mock_server.ts +0 -27
  170. package/src/test_utils/oauth_server.ts +0 -10
  171. package/src/test_utils/test_cli_command.ts +0 -117
  172. package/src/types.ts +0 -25
  173. package/src/utils/enrichers.ts +0 -73
  174. package/src/utils/formats.test.ts +0 -41
  175. package/src/utils/formats.ts +0 -11
  176. package/src/utils/middlewares.ts +0 -23
  177. package/src/utils/point_in_time.ts +0 -86
  178. package/src/utils/psql.ts +0 -29
  179. package/src/utils/string.ts +0 -8
  180. package/src/utils/ui.ts +0 -64
  181. package/src/writer.test.ts +0 -98
  182. package/src/writer.ts +0 -131
  183. package/tsconfig.json +0 -17
  184. /package/{src/callback.html → callback.html} +0 -0
@@ -0,0 +1,321 @@
1
+ import { describe } from '@jest/globals';
2
+ import { testCliCommand } from '../test_utils/test_cli_command.js';
3
+ describe('branches', () => {
4
+ /* list */
5
+ testCliCommand({
6
+ name: 'list',
7
+ args: ['branches', 'list', '--project-id', 'test'],
8
+ expected: {
9
+ snapshot: true,
10
+ },
11
+ });
12
+ /* create */
13
+ testCliCommand({
14
+ name: 'create by default with r/w endpoint',
15
+ args: [
16
+ 'branches',
17
+ 'create',
18
+ '--project-id',
19
+ 'test',
20
+ '--name',
21
+ 'test_branch',
22
+ ],
23
+ expected: {
24
+ snapshot: true,
25
+ },
26
+ });
27
+ testCliCommand({
28
+ name: 'create branch and connect with psql',
29
+ args: [
30
+ 'branches',
31
+ 'create',
32
+ '--project-id',
33
+ 'test',
34
+ '--name',
35
+ 'test_branch',
36
+ '--psql',
37
+ ],
38
+ expected: {
39
+ snapshot: true,
40
+ },
41
+ });
42
+ testCliCommand({
43
+ name: 'create branch and connect with psql and psql args',
44
+ args: [
45
+ 'branches',
46
+ 'create',
47
+ '--project-id',
48
+ 'test',
49
+ '--name',
50
+ 'test_branch',
51
+ '--psql',
52
+ '--',
53
+ '-c',
54
+ 'SELECT 1',
55
+ ],
56
+ expected: {
57
+ snapshot: true,
58
+ },
59
+ });
60
+ testCliCommand({
61
+ name: 'create with readonly endpoint',
62
+ args: [
63
+ 'branches',
64
+ 'create',
65
+ '--project-id',
66
+ 'test',
67
+ '--name',
68
+ 'test_branch',
69
+ '--type',
70
+ 'read_only',
71
+ ],
72
+ expected: {
73
+ snapshot: true,
74
+ },
75
+ });
76
+ testCliCommand({
77
+ name: 'create without endpoint',
78
+ args: [
79
+ 'branches',
80
+ 'create',
81
+ '--project-id',
82
+ 'test',
83
+ '--name',
84
+ 'test_branch',
85
+ '--no-compute',
86
+ ],
87
+ expected: {
88
+ snapshot: true,
89
+ },
90
+ });
91
+ testCliCommand({
92
+ name: 'create with parent by name',
93
+ args: [
94
+ 'branches',
95
+ 'create',
96
+ '--project-id',
97
+ 'test',
98
+ '--name',
99
+ 'test_branch_with_parent_name',
100
+ '--parent',
101
+ 'main',
102
+ ],
103
+ expected: {
104
+ snapshot: true,
105
+ },
106
+ });
107
+ testCliCommand({
108
+ name: 'create with parent by lsn',
109
+ args: [
110
+ 'branches',
111
+ 'create',
112
+ '--project-id',
113
+ 'test',
114
+ '--name',
115
+ 'test_branch_with_parent_lsn',
116
+ '--parent',
117
+ '0/123ABC',
118
+ ],
119
+ expected: {
120
+ snapshot: true,
121
+ },
122
+ });
123
+ testCliCommand({
124
+ name: 'create with parent by timestamp',
125
+ args: [
126
+ 'branches',
127
+ 'create',
128
+ '--project-id',
129
+ 'test',
130
+ '--name',
131
+ 'test_branch_with_parent_timestamp',
132
+ '--parent',
133
+ '2021-01-01T00:00:00.000Z',
134
+ ],
135
+ expected: {
136
+ snapshot: true,
137
+ },
138
+ });
139
+ testCliCommand({
140
+ name: 'create with suspend timeout',
141
+ args: [
142
+ 'branches',
143
+ 'create',
144
+ '--project-id',
145
+ 'test',
146
+ '--name',
147
+ 'test_branch_with_suspend_timeout',
148
+ '--suspend-timeout',
149
+ '60',
150
+ ],
151
+ expected: {
152
+ snapshot: true,
153
+ },
154
+ });
155
+ /* delete */
156
+ testCliCommand({
157
+ name: 'delete by id',
158
+ args: [
159
+ 'branches',
160
+ 'delete',
161
+ 'br-sunny-branch-123456',
162
+ '--project-id',
163
+ 'test',
164
+ ],
165
+ expected: {
166
+ snapshot: true,
167
+ },
168
+ });
169
+ /* rename */
170
+ testCliCommand({
171
+ name: 'rename',
172
+ args: [
173
+ 'branches',
174
+ 'rename',
175
+ 'test_branch',
176
+ 'new_test_branch',
177
+ '--project-id',
178
+ 'test',
179
+ ],
180
+ expected: {
181
+ snapshot: true,
182
+ },
183
+ });
184
+ /* set primary */
185
+ testCliCommand({
186
+ name: 'set primary by id',
187
+ args: [
188
+ 'branches',
189
+ 'set-primary',
190
+ 'br-sunny-branch-123456',
191
+ '--project-id',
192
+ 'test',
193
+ ],
194
+ expected: {
195
+ snapshot: true,
196
+ },
197
+ });
198
+ /* get */
199
+ testCliCommand({
200
+ name: 'get by id',
201
+ args: ['branches', 'get', 'br-sunny-branch-123456', '--project-id', 'test'],
202
+ expected: {
203
+ snapshot: true,
204
+ },
205
+ });
206
+ testCliCommand({
207
+ name: 'get by id',
208
+ args: [
209
+ 'branches',
210
+ 'get',
211
+ 'br-cloudy-branch-12345678',
212
+ '--project-id',
213
+ 'test',
214
+ ],
215
+ expected: {
216
+ snapshot: true,
217
+ },
218
+ });
219
+ testCliCommand({
220
+ name: 'get by name',
221
+ args: ['branches', 'get', 'test_branch', '--project-id', 'test'],
222
+ expected: {
223
+ snapshot: true,
224
+ },
225
+ });
226
+ testCliCommand({
227
+ name: 'get by name with numeric name',
228
+ args: ['branches', 'get', '123', '--project-id', 'test'],
229
+ expected: {
230
+ snapshot: true,
231
+ },
232
+ });
233
+ /* add compute */
234
+ testCliCommand({
235
+ name: 'add compute',
236
+ args: ['branches', 'add-compute', 'test_branch', '--project-id', 'test'],
237
+ expected: {
238
+ snapshot: true,
239
+ },
240
+ });
241
+ /* reset */
242
+ testCliCommand({
243
+ name: 'reset branch to parent',
244
+ args: [
245
+ 'branches',
246
+ 'reset',
247
+ 'test_branch',
248
+ '--project-id',
249
+ 'test',
250
+ '--parent',
251
+ ],
252
+ expected: {
253
+ snapshot: true,
254
+ },
255
+ });
256
+ /* restore */
257
+ testCliCommand({
258
+ name: 'restore branch to lsn',
259
+ args: [
260
+ 'branches',
261
+ 'restore',
262
+ 'br-self-tolsn-123456',
263
+ '^self@0/123ABC',
264
+ '--project-id',
265
+ 'test',
266
+ '--preserve-under-name',
267
+ 'backup',
268
+ ],
269
+ mockDir: 'restore',
270
+ expected: {
271
+ snapshot: true,
272
+ },
273
+ });
274
+ testCliCommand({
275
+ name: 'restore to parent branch timestamp by name',
276
+ args: [
277
+ 'branches',
278
+ 'restore',
279
+ 'parent-tots',
280
+ '^parent@2021-01-01T00:00:00.000Z',
281
+ '--project-id',
282
+ 'test',
283
+ ],
284
+ mockDir: 'restore',
285
+ expected: {
286
+ snapshot: true,
287
+ },
288
+ });
289
+ testCliCommand({
290
+ name: 'restore to another branch head',
291
+ args: [
292
+ 'branches',
293
+ 'restore',
294
+ 'br-another-branch-123456',
295
+ 'br-any-branch-123456',
296
+ '--project-id',
297
+ 'test',
298
+ ],
299
+ mockDir: 'restore',
300
+ expected: {
301
+ snapshot: true,
302
+ },
303
+ });
304
+ testCliCommand({
305
+ name: 'restore with unexisted branch outputs error',
306
+ args: [
307
+ 'branches',
308
+ 'restore',
309
+ 'unexisting-branch',
310
+ '^parent',
311
+ '--project-id',
312
+ 'test',
313
+ ],
314
+ mockDir: 'restore',
315
+ expected: {
316
+ code: 1,
317
+ stderr: `ERROR: Branch unexisting-branch not found.
318
+ Available branches: self-tolsn-123456, any-branch, parent-tots, another-branch`,
319
+ },
320
+ });
321
+ });
@@ -0,0 +1,156 @@
1
+ import { EndpointType } from '@neondatabase/api-client';
2
+ import { branchIdFromProps, fillSingleProject } from '../utils/enrichers.js';
3
+ import { writer } from '../writer.js';
4
+ import { psql } from '../utils/psql.js';
5
+ import { parsePITBranch } from '../utils/point_in_time.js';
6
+ const SSL_MODES = ['require', 'verify-ca', 'verify-full', 'omit'];
7
+ export const command = 'connection-string [branch]';
8
+ export const aliases = ['cs'];
9
+ export const describe = 'Get connection string';
10
+ export const builder = (argv) => {
11
+ return argv
12
+ .usage('$0 connection-string [branch] [options]')
13
+ .example('$0 cs main', 'Get connection string for the main branch')
14
+ .example('$0 cs main@2024-01-01T00:00:00Z', 'Get connection string for the main branch at a specific point in time')
15
+ .example('$0 cs main@0/234235', 'Get connection string for the main branch at a specific LSN')
16
+ .positional('branch', {
17
+ describe: `Branch name or id. Defaults to the primary branch if omitted. Can be written in the point-in-time format: "branch@timestamp" or "branch@lsn"`,
18
+ type: 'string',
19
+ })
20
+ .options({
21
+ 'project-id': {
22
+ type: 'string',
23
+ describe: 'Project ID',
24
+ },
25
+ 'role-name': {
26
+ type: 'string',
27
+ describe: 'Role name',
28
+ },
29
+ 'database-name': {
30
+ type: 'string',
31
+ describe: 'Database name',
32
+ },
33
+ pooled: {
34
+ type: 'boolean',
35
+ describe: 'Use pooled connection',
36
+ default: false,
37
+ },
38
+ prisma: {
39
+ type: 'boolean',
40
+ describe: 'Use connection string for Prisma setup',
41
+ default: false,
42
+ },
43
+ 'endpoint-type': {
44
+ type: 'string',
45
+ choices: Object.values(EndpointType),
46
+ describe: 'Endpoint type',
47
+ },
48
+ extended: {
49
+ type: 'boolean',
50
+ describe: 'Show extended information',
51
+ },
52
+ psql: {
53
+ type: 'boolean',
54
+ describe: 'Connect to a database via psql using connection string',
55
+ default: false,
56
+ },
57
+ ssl: {
58
+ type: 'string',
59
+ choices: SSL_MODES,
60
+ default: 'require',
61
+ describe: 'SSL mode',
62
+ },
63
+ })
64
+ .middleware(fillSingleProject);
65
+ };
66
+ export const handler = async (props) => {
67
+ const projectId = props.projectId;
68
+ const parsedPIT = props.branch
69
+ ? parsePITBranch(props.branch)
70
+ : { tag: 'head', branch: '' };
71
+ if (props.branch) {
72
+ props.branch = parsedPIT.branch;
73
+ }
74
+ const branchId = await branchIdFromProps(props);
75
+ const { data: { endpoints }, } = await props.apiClient.listProjectBranchEndpoints(projectId, branchId);
76
+ const matchEndpointType = props.endpointType ?? EndpointType.ReadWrite;
77
+ let endpoint = endpoints.find((e) => e.type === matchEndpointType);
78
+ if (!endpoint && props.endpointType == null) {
79
+ endpoint = endpoints[0];
80
+ }
81
+ if (!endpoint) {
82
+ throw new Error(`No ${props.endpointType ?? ''} endpoint found for the branch: ${branchId}`);
83
+ }
84
+ const role = props.roleName ||
85
+ (await props.apiClient
86
+ .listProjectBranchRoles(projectId, branchId)
87
+ .then(({ data }) => {
88
+ if (data.roles.length === 0) {
89
+ throw new Error(`No roles found for the branch: ${branchId}`);
90
+ }
91
+ if (data.roles.length === 1) {
92
+ return data.roles[0].name;
93
+ }
94
+ throw new Error(`Multiple roles found for the branch, please provide one with the --role-name option: ${data.roles
95
+ .map((r) => r.name)
96
+ .join(', ')}`);
97
+ }));
98
+ const database = props.databaseName ||
99
+ (await props.apiClient
100
+ .listProjectBranchDatabases(projectId, branchId)
101
+ .then(({ data }) => {
102
+ if (data.databases.length === 0) {
103
+ throw new Error(`No databases found for the branch: ${branchId}`);
104
+ }
105
+ if (data.databases.length === 1) {
106
+ return data.databases[0].name;
107
+ }
108
+ throw new Error(`Multiple databases found for the branch, please provide one with the --database-name option: ${data.databases
109
+ .map((d) => d.name)
110
+ .join(', ')}`);
111
+ }));
112
+ const { data: { password }, } = await props.apiClient.getProjectBranchRolePassword(props.projectId, endpoint.branch_id, role);
113
+ let host = props.pooled
114
+ ? endpoint.host.replace(endpoint.id, `${endpoint.id}-pooler`)
115
+ : endpoint.host;
116
+ if (parsedPIT.tag !== 'head') {
117
+ host = endpoint.host.replace(endpoint.id, endpoint.branch_id);
118
+ }
119
+ const connectionString = new URL(`postgres://${host}`);
120
+ connectionString.pathname = database;
121
+ connectionString.username = role;
122
+ connectionString.password = password;
123
+ if (props.prisma) {
124
+ connectionString.searchParams.set('connect_timeout', '30');
125
+ if (props.pooled) {
126
+ connectionString.searchParams.set('pool_timeout', '30');
127
+ connectionString.searchParams.set('pgbouncer', 'true');
128
+ }
129
+ }
130
+ if (props.ssl !== 'omit') {
131
+ connectionString.searchParams.set('sslmode', props.ssl);
132
+ }
133
+ if (parsedPIT.tag === 'lsn') {
134
+ connectionString.searchParams.set('options', `neon_lsn:${parsedPIT.lsn}`);
135
+ }
136
+ else if (parsedPIT.tag === 'timestamp') {
137
+ connectionString.searchParams.set('options', `neon_timestamp:${parsedPIT.timestamp}`);
138
+ }
139
+ if (props.psql) {
140
+ const psqlArgs = props['--'];
141
+ await psql(connectionString.toString(), psqlArgs);
142
+ }
143
+ else if (props.extended) {
144
+ writer(props).end({
145
+ connection_string: connectionString.toString(),
146
+ host,
147
+ role,
148
+ password,
149
+ database,
150
+ options: connectionString.searchParams.toString(),
151
+ }, { fields: ['host', 'role', 'password', 'database'] });
152
+ }
153
+ else {
154
+ process.stdout.write(connectionString.toString() + '\n');
155
+ }
156
+ };
@@ -0,0 +1,236 @@
1
+ import { describe } from '@jest/globals';
2
+ import { testCliCommand } from '../test_utils/test_cli_command';
3
+ describe('connection_string', () => {
4
+ testCliCommand({
5
+ name: 'connection_string',
6
+ args: [
7
+ 'connection-string',
8
+ 'test_branch',
9
+ '--project-id',
10
+ 'test',
11
+ '--database-name',
12
+ 'test_db',
13
+ '--role-name',
14
+ 'test_role',
15
+ ],
16
+ expected: {
17
+ snapshot: true,
18
+ },
19
+ });
20
+ testCliCommand({
21
+ name: 'connection_string branch id',
22
+ args: [
23
+ 'connection-string',
24
+ 'br-sunny-branch-123456',
25
+ '--project-id',
26
+ 'test',
27
+ '--database-name',
28
+ 'test_db',
29
+ '--role-name',
30
+ 'test_role',
31
+ ],
32
+ expected: {
33
+ snapshot: true,
34
+ },
35
+ });
36
+ testCliCommand({
37
+ name: 'connection_string branch id 8 digits',
38
+ args: [
39
+ 'connection-string',
40
+ 'br-cloudy-branch-12345678',
41
+ '--project-id',
42
+ 'test',
43
+ '--database-name',
44
+ 'test_db',
45
+ '--role-name',
46
+ 'test_role',
47
+ ],
48
+ expected: {
49
+ snapshot: true,
50
+ },
51
+ });
52
+ testCliCommand({
53
+ name: 'connection_string pooled',
54
+ args: [
55
+ 'connection-string',
56
+ 'test_branch',
57
+ '--project-id',
58
+ 'test',
59
+ '--database-name',
60
+ 'test_db',
61
+ '--role-name',
62
+ 'test_role',
63
+ '--pooled',
64
+ ],
65
+ expected: {
66
+ snapshot: true,
67
+ },
68
+ });
69
+ testCliCommand({
70
+ name: 'connection_string prisma',
71
+ args: [
72
+ 'connection-string',
73
+ 'test_branch',
74
+ '--project-id',
75
+ 'test',
76
+ '--database-name',
77
+ 'test_db',
78
+ '--role-name',
79
+ 'test_role',
80
+ '--prisma',
81
+ ],
82
+ expected: {
83
+ snapshot: true,
84
+ },
85
+ });
86
+ testCliCommand({
87
+ name: 'connection_string prisma pooled',
88
+ args: [
89
+ 'connection-string',
90
+ 'test_branch',
91
+ '--project-id',
92
+ 'test',
93
+ '--database-name',
94
+ 'test_db',
95
+ '--role-name',
96
+ 'test_role',
97
+ '--prisma',
98
+ '--pooled',
99
+ ],
100
+ expected: {
101
+ snapshot: true,
102
+ },
103
+ });
104
+ testCliCommand({
105
+ name: 'connection_string prisma pooled extended',
106
+ args: [
107
+ 'connection-string',
108
+ 'test_branch',
109
+ '--project-id',
110
+ 'test',
111
+ '--database-name',
112
+ 'test_db',
113
+ '--role-name',
114
+ 'test_role',
115
+ '--prisma',
116
+ '--pooled',
117
+ '--extended',
118
+ ],
119
+ expected: {
120
+ snapshot: true,
121
+ },
122
+ });
123
+ testCliCommand({
124
+ name: 'connection_string without any args should pass',
125
+ args: ['connection-string'],
126
+ mockDir: 'single_project',
127
+ expected: {
128
+ snapshot: true,
129
+ },
130
+ });
131
+ testCliCommand({
132
+ name: 'connection_string with psql',
133
+ args: [
134
+ 'connection-string',
135
+ 'test_branch',
136
+ '--project-id',
137
+ 'test',
138
+ '--database-name',
139
+ 'test_db',
140
+ '--role-name',
141
+ 'test_role',
142
+ '--psql',
143
+ ],
144
+ expected: {
145
+ snapshot: true,
146
+ },
147
+ });
148
+ testCliCommand({
149
+ name: 'connection_string with psql and psql args',
150
+ args: [
151
+ 'connection-string',
152
+ 'test_branch',
153
+ '--project-id',
154
+ 'test',
155
+ '--database-name',
156
+ 'test_db',
157
+ '--role-name',
158
+ 'test_role',
159
+ '--psql',
160
+ '--',
161
+ '-c',
162
+ 'SELECT 1',
163
+ ],
164
+ expected: {
165
+ snapshot: true,
166
+ },
167
+ });
168
+ testCliCommand({
169
+ name: 'connection_string without ssl',
170
+ args: [
171
+ 'connection-string',
172
+ 'test_branch',
173
+ '--project-id',
174
+ 'test',
175
+ '--database-name',
176
+ 'test_db',
177
+ '--role-name',
178
+ 'test_role',
179
+ '--ssl',
180
+ 'omit',
181
+ ],
182
+ expected: {
183
+ snapshot: true,
184
+ },
185
+ });
186
+ testCliCommand({
187
+ name: 'connection_string with ssl verify full',
188
+ args: [
189
+ 'connection-string',
190
+ 'test_branch',
191
+ '--project-id',
192
+ 'test',
193
+ '--database-name',
194
+ 'test_db',
195
+ '--role-name',
196
+ 'test_role',
197
+ '--ssl',
198
+ 'verify-full',
199
+ ],
200
+ expected: {
201
+ snapshot: true,
202
+ },
203
+ });
204
+ testCliCommand({
205
+ name: 'connection_string with lsn',
206
+ args: [
207
+ 'connection-string',
208
+ 'test_branch@0/123456',
209
+ '--project-id',
210
+ 'test',
211
+ '--database-name',
212
+ 'test_db',
213
+ '--role-name',
214
+ 'test_role',
215
+ ],
216
+ expected: {
217
+ snapshot: true,
218
+ },
219
+ });
220
+ testCliCommand({
221
+ name: 'connection_string with timestamp',
222
+ args: [
223
+ 'connection-string',
224
+ 'test_branch@2021-01-01T00:00:00Z',
225
+ '--project-id',
226
+ 'test',
227
+ '--database-name',
228
+ 'test_db',
229
+ '--role-name',
230
+ 'test_role',
231
+ ],
232
+ expected: {
233
+ snapshot: true,
234
+ },
235
+ });
236
+ });