create-platformatic 1.17.0 → 1.19.0
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.
- package/create-platformatic.mjs +1 -6
- package/package.json +6 -5
- package/src/ghaction.mjs +1 -0
- package/src/utils.mjs +2 -130
- package/src/ask-dir.mjs +0 -37
- package/src/cli-options.mjs +0 -34
- package/src/colors.mjs +0 -4
- package/src/composer/README.md +0 -30
- package/src/composer/create-composer-cli.mjs +0 -143
- package/src/composer/create-composer.mjs +0 -146
- package/src/create-git-repository.mjs +0 -105
- package/src/create-gitignore.mjs +0 -42
- package/src/create-package-json.mjs +0 -58
- package/src/create-plugins.mjs +0 -220
- package/src/create-readme.mjs +0 -12
- package/src/db/README.md +0 -38
- package/src/db/create-db-cli.mjs +0 -263
- package/src/db/create-db.mjs +0 -449
- package/src/get-tsconfig.mjs +0 -22
- package/src/index.mjs +0 -112
- package/src/runtime/README.md +0 -32
- package/src/runtime/create-runtime-cli.mjs +0 -199
- package/src/runtime/create-runtime.mjs +0 -128
- package/src/say.mjs +0 -20
- package/src/service/README.md +0 -31
- package/src/service/create-service-cli.mjs +0 -127
- package/src/service/create-service.mjs +0 -132
package/src/db/create-db-cli.mjs
DELETED
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { getVersion, getDependencyVersion, safeMkdir } from '../utils.mjs'
|
|
2
|
-
import { createPackageJson } from '../create-package-json.mjs'
|
|
3
|
-
import { createGitignore } from '../create-gitignore.mjs'
|
|
4
|
-
import { getPkgManager } from '@platformatic/utils'
|
|
5
|
-
import parseArgs from 'minimist'
|
|
6
|
-
import inquirer from 'inquirer'
|
|
7
|
-
import which from 'which'
|
|
8
|
-
import pino from 'pino'
|
|
9
|
-
import pretty from 'pino-pretty'
|
|
10
|
-
import { execa } from 'execa'
|
|
11
|
-
import ora from 'ora'
|
|
12
|
-
import { getConnectionString, createDB } from './create-db.mjs'
|
|
13
|
-
import askDir from '../ask-dir.mjs'
|
|
14
|
-
import { getUseTypescript, getPort, getInitGitRepository } from '../cli-options.mjs'
|
|
15
|
-
import { createReadme } from '../create-readme.mjs'
|
|
16
|
-
import { join } from 'node:path'
|
|
17
|
-
|
|
18
|
-
const databases = [{
|
|
19
|
-
value: 'sqlite',
|
|
20
|
-
name: 'SQLite'
|
|
21
|
-
}, {
|
|
22
|
-
value: 'postgres',
|
|
23
|
-
name: 'PostgreSQL'
|
|
24
|
-
}, {
|
|
25
|
-
value: 'mysql',
|
|
26
|
-
name: 'MySQL'
|
|
27
|
-
}, {
|
|
28
|
-
value: 'mariadb',
|
|
29
|
-
name: 'MariaDB'
|
|
30
|
-
}]
|
|
31
|
-
|
|
32
|
-
export function parseDBArgs (_args) {
|
|
33
|
-
return parseArgs(_args, {
|
|
34
|
-
default: {
|
|
35
|
-
hostname: '127.0.0.1',
|
|
36
|
-
database: 'sqlite',
|
|
37
|
-
migrations: 'migrations',
|
|
38
|
-
install: true
|
|
39
|
-
},
|
|
40
|
-
alias: {
|
|
41
|
-
h: 'hostname',
|
|
42
|
-
p: 'port',
|
|
43
|
-
pl: 'plugin',
|
|
44
|
-
db: 'database',
|
|
45
|
-
m: 'migrations',
|
|
46
|
-
t: 'types',
|
|
47
|
-
ts: 'typescript'
|
|
48
|
-
},
|
|
49
|
-
boolean: ['plugin', 'types', 'typescript', 'install']
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const createPlatformaticDB = async (_args, opts) => {
|
|
54
|
-
const logger = opts.logger || pino(pretty({
|
|
55
|
-
translateTime: 'SYS:HH:MM:ss',
|
|
56
|
-
ignore: 'hostname,pid'
|
|
57
|
-
}))
|
|
58
|
-
|
|
59
|
-
const args = parseDBArgs(_args)
|
|
60
|
-
const version = await getVersion()
|
|
61
|
-
const pkgManager = getPkgManager()
|
|
62
|
-
const projectDir = opts.dir || await askDir(logger, join('.', 'platformatic-db'))
|
|
63
|
-
|
|
64
|
-
const isRuntimeContext = opts.isRuntimeContext || false
|
|
65
|
-
const toAsk = []
|
|
66
|
-
|
|
67
|
-
// Ask for port if not in runtime context
|
|
68
|
-
const portQuestion = getPort(args.port)
|
|
69
|
-
portQuestion.when = !isRuntimeContext
|
|
70
|
-
toAsk.push(portQuestion)
|
|
71
|
-
|
|
72
|
-
const { database } = await inquirer.prompt({
|
|
73
|
-
type: 'list',
|
|
74
|
-
name: 'database',
|
|
75
|
-
message: 'What database do you want to use?',
|
|
76
|
-
default: args.database,
|
|
77
|
-
choices: databases
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
let connectionString = getConnectionString(database)
|
|
81
|
-
|
|
82
|
-
while (true) {
|
|
83
|
-
const pickConnectionString = await inquirer.prompt({
|
|
84
|
-
type: 'expand',
|
|
85
|
-
name: 'edit',
|
|
86
|
-
message: `Do you want to use the connection string "${connectionString}"?`,
|
|
87
|
-
choices: [
|
|
88
|
-
{
|
|
89
|
-
key: 'y',
|
|
90
|
-
name: 'Confirm',
|
|
91
|
-
value: false
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
key: 'e',
|
|
95
|
-
name: 'Edit',
|
|
96
|
-
value: true
|
|
97
|
-
}
|
|
98
|
-
]
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
if (pickConnectionString.edit) {
|
|
102
|
-
const answers = await inquirer.prompt({
|
|
103
|
-
type: 'editor',
|
|
104
|
-
name: 'connectionString',
|
|
105
|
-
message: 'Edit the connection string',
|
|
106
|
-
default: connectionString
|
|
107
|
-
})
|
|
108
|
-
connectionString = answers.connectionString.trim()
|
|
109
|
-
} else {
|
|
110
|
-
break
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
toAsk.push({
|
|
115
|
-
type: 'list',
|
|
116
|
-
name: 'defaultMigrations',
|
|
117
|
-
message: 'Do you want to create default migrations?',
|
|
118
|
-
default: true,
|
|
119
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
120
|
-
})
|
|
121
|
-
toAsk.push({
|
|
122
|
-
type: 'list',
|
|
123
|
-
name: 'applyMigrations',
|
|
124
|
-
message: 'Do you want to apply migrations?',
|
|
125
|
-
default: true,
|
|
126
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }],
|
|
127
|
-
when: (answers) => {
|
|
128
|
-
return answers.defaultMigrations
|
|
129
|
-
}
|
|
130
|
-
})
|
|
131
|
-
|
|
132
|
-
if (args.plugin === false) {
|
|
133
|
-
toAsk.push({
|
|
134
|
-
type: 'list',
|
|
135
|
-
name: 'generatePlugin',
|
|
136
|
-
message: 'Do you want to create a plugin?',
|
|
137
|
-
default: true,
|
|
138
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
toAsk.push(getUseTypescript(args.typescript))
|
|
143
|
-
|
|
144
|
-
toAsk.push({
|
|
145
|
-
type: 'list',
|
|
146
|
-
name: 'staticWorkspaceGitHubAction',
|
|
147
|
-
message: 'Do you want to create the github action to deploy this application to Platformatic Cloud?',
|
|
148
|
-
default: true,
|
|
149
|
-
when: !opts.skipGitHubActions,
|
|
150
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: 'list',
|
|
154
|
-
name: 'dynamicWorkspaceGitHubAction',
|
|
155
|
-
message: 'Do you want to enable PR Previews in your application?',
|
|
156
|
-
default: true,
|
|
157
|
-
when: !opts.skipGitHubActions,
|
|
158
|
-
choices: [{ name: 'yes', value: true }, { name: 'no', value: false }]
|
|
159
|
-
})
|
|
160
|
-
if (!opts.skipGitRepository) {
|
|
161
|
-
toAsk.push(getInitGitRepository())
|
|
162
|
-
}
|
|
163
|
-
// Prompt for questions
|
|
164
|
-
const wizardOptions = await inquirer.prompt(toAsk)
|
|
165
|
-
|
|
166
|
-
await safeMkdir(projectDir)
|
|
167
|
-
|
|
168
|
-
const generatePlugin = args.plugin || wizardOptions.generatePlugin
|
|
169
|
-
const useTypescript = args.typescript || wizardOptions.useTypescript
|
|
170
|
-
const useTypes = args.types || generatePlugin // we set this always to true if we want to generate a plugin
|
|
171
|
-
|
|
172
|
-
const params = {
|
|
173
|
-
isRuntimeContext,
|
|
174
|
-
hostname: args.hostname,
|
|
175
|
-
port: wizardOptions.port,
|
|
176
|
-
database,
|
|
177
|
-
connectionString,
|
|
178
|
-
migrations: wizardOptions.defaultMigrations ? args.migrations : '',
|
|
179
|
-
plugin: generatePlugin,
|
|
180
|
-
types: useTypes,
|
|
181
|
-
typescript: useTypescript,
|
|
182
|
-
staticWorkspaceGitHubAction: wizardOptions.staticWorkspaceGitHubAction,
|
|
183
|
-
dynamicWorkspaceGitHubAction: wizardOptions.dynamicWorkspaceGitHubAction,
|
|
184
|
-
runtimeContext: opts.runtimeContext,
|
|
185
|
-
initGitRepository: wizardOptions.initGitRepository
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
await createDB(params, logger, projectDir, version)
|
|
189
|
-
|
|
190
|
-
const fastifyVersion = await getDependencyVersion('fastify')
|
|
191
|
-
|
|
192
|
-
const scripts = {
|
|
193
|
-
migrate: 'platformatic db migrations apply',
|
|
194
|
-
test: useTypescript ? 'tsc && node --test dist/test/*/*.test.js' : 'node --test test/*/*.test.js'
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const dependencies = {
|
|
198
|
-
'@platformatic/db': `^${version}`
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Create the package.json, .gitignore, readme
|
|
202
|
-
await createPackageJson(version, fastifyVersion, logger, projectDir, useTypescript, scripts, dependencies)
|
|
203
|
-
await createGitignore(logger, projectDir)
|
|
204
|
-
await createReadme(logger, projectDir, 'db')
|
|
205
|
-
|
|
206
|
-
let hasPlatformaticInstalled = false
|
|
207
|
-
if (args.install && !opts.skipPackageJson) {
|
|
208
|
-
const spinner = ora('Installing dependencies...').start()
|
|
209
|
-
await execa(pkgManager, ['install'], { cwd: projectDir })
|
|
210
|
-
spinner.succeed()
|
|
211
|
-
hasPlatformaticInstalled = true
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (!hasPlatformaticInstalled) {
|
|
215
|
-
try {
|
|
216
|
-
const npmLs = JSON.parse(await execa('npm', ['ls', '--json']).toString())
|
|
217
|
-
hasPlatformaticInstalled = !!npmLs.dependencies.platformatic
|
|
218
|
-
} catch {
|
|
219
|
-
// Ignore all errors, this can fail
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (!hasPlatformaticInstalled) {
|
|
224
|
-
const exe = await which('platformatic', { nothrow: true })
|
|
225
|
-
hasPlatformaticInstalled = !!exe
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (hasPlatformaticInstalled) {
|
|
229
|
-
// We applied package manager install, so we can:
|
|
230
|
-
// - run the migrations
|
|
231
|
-
// - generate types
|
|
232
|
-
// if we don't generate migrations, we don't ask to apply them (the folder might not exist)
|
|
233
|
-
let migrationApplied = false
|
|
234
|
-
if (wizardOptions.defaultMigrations && wizardOptions.applyMigrations) {
|
|
235
|
-
const spinner = ora('Applying migrations...').start()
|
|
236
|
-
// We need to apply migrations using the platformatic installed in the project
|
|
237
|
-
try {
|
|
238
|
-
await execa(pkgManager, ['exec', 'platformatic', 'db', 'migrations', 'apply'], { cwd: projectDir })
|
|
239
|
-
spinner.succeed()
|
|
240
|
-
migrationApplied = true
|
|
241
|
-
} catch (err) {
|
|
242
|
-
logger.trace({ err })
|
|
243
|
-
spinner.fail('Failed applying migrations! Try again by running "platformatic db migrations apply"')
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
if (generatePlugin && migrationApplied) {
|
|
247
|
-
const spinner = ora('Generating types...').start()
|
|
248
|
-
try {
|
|
249
|
-
await execa(pkgManager, ['exec', 'platformatic', 'db', 'types'], { cwd: projectDir })
|
|
250
|
-
spinner.succeed()
|
|
251
|
-
} catch (err) {
|
|
252
|
-
logger.trace({ err })
|
|
253
|
-
spinner.fail('Failed to generate Types. Try again by running "platformatic service types"')
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// returns metadata that can be used to make some further actions
|
|
258
|
-
return {
|
|
259
|
-
typescript: useTypescript
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
export default createPlatformaticDB
|
package/src/db/create-db.mjs
DELETED
|
@@ -1,449 +0,0 @@
|
|
|
1
|
-
import { writeFile, appendFile } from 'fs/promises'
|
|
2
|
-
import { join } from 'path'
|
|
3
|
-
import { addPrefixToEnv, safeMkdir } from '../utils.mjs'
|
|
4
|
-
import { getTsConfig } from '../get-tsconfig.mjs'
|
|
5
|
-
import { generatePlugins } from '../create-plugins.mjs'
|
|
6
|
-
import { createDynamicWorkspaceGHAction, createStaticWorkspaceGHAction } from '../ghaction.mjs'
|
|
7
|
-
import { createGitRepository } from '../create-git-repository.mjs'
|
|
8
|
-
|
|
9
|
-
const connectionStrings = {
|
|
10
|
-
postgres: 'postgres://postgres:postgres@127.0.0.1:5432/postgres',
|
|
11
|
-
sqlite: 'sqlite://./db.sqlite',
|
|
12
|
-
mysql: 'mysql://root@127.0.0.1:3306/platformatic',
|
|
13
|
-
mariadb: 'mysql://root@127.0.0.1:3306/platformatic'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const moviesMigrationDo = (database) => {
|
|
17
|
-
const key = {
|
|
18
|
-
postgres: 'SERIAL',
|
|
19
|
-
sqlite: 'INTEGER',
|
|
20
|
-
mysql: 'INTEGER UNSIGNED AUTO_INCREMENT',
|
|
21
|
-
mariadb: 'INTEGER UNSIGNED AUTO_INCREMENT'
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
return `
|
|
25
|
-
-- Add SQL in this file to create the database tables for your API
|
|
26
|
-
CREATE TABLE IF NOT EXISTS movies (
|
|
27
|
-
id ${key[database]} PRIMARY KEY,
|
|
28
|
-
title TEXT NOT NULL
|
|
29
|
-
);
|
|
30
|
-
`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const moviesMigrationUndo = `
|
|
34
|
-
-- Add SQL in this file to drop the database tables
|
|
35
|
-
DROP TABLE movies;
|
|
36
|
-
`
|
|
37
|
-
|
|
38
|
-
const TS_OUT_DIR = 'dist'
|
|
39
|
-
|
|
40
|
-
const jsHelperSqlite = {
|
|
41
|
-
requires: `
|
|
42
|
-
const os = require('node:os')
|
|
43
|
-
const path = require('node:path')
|
|
44
|
-
const fs = require('node:fs/promises')
|
|
45
|
-
|
|
46
|
-
let counter = 0
|
|
47
|
-
`,
|
|
48
|
-
pre: `
|
|
49
|
-
const dbPath = join(os.tmpdir(), 'db-' + process.pid + '-' + counter++ + '.sqlite')
|
|
50
|
-
const connectionString = 'sqlite://' + dbPath
|
|
51
|
-
`,
|
|
52
|
-
config: `
|
|
53
|
-
config.migrations.autoApply = true
|
|
54
|
-
config.types.autogenerate = false
|
|
55
|
-
config.db.connectionString = connectionString
|
|
56
|
-
`,
|
|
57
|
-
post: `
|
|
58
|
-
t.after(async () => {
|
|
59
|
-
await fs.unlink(dbPath)
|
|
60
|
-
})
|
|
61
|
-
`
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function jsHelperPostgres (connectionString) {
|
|
65
|
-
return {
|
|
66
|
-
// TODO(mcollina): replace sql-mapper
|
|
67
|
-
requires: `
|
|
68
|
-
const { createConnectionPool } = require('@platformatic/sql-mapper')
|
|
69
|
-
const connectionString = '${connectionString}'
|
|
70
|
-
let counter = 0
|
|
71
|
-
`,
|
|
72
|
-
pre: `
|
|
73
|
-
const { db, sql } = await createConnectionPool({
|
|
74
|
-
log: {
|
|
75
|
-
debug: () => {},
|
|
76
|
-
info: () => {},
|
|
77
|
-
trace: () => {}
|
|
78
|
-
},
|
|
79
|
-
connectionString,
|
|
80
|
-
poolSize: 1
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const newDB = \`t-\${process.pid}-\${counter++}\`
|
|
84
|
-
t.diagnostic('Creating database ' + newDB)
|
|
85
|
-
|
|
86
|
-
await db.query(sql\`
|
|
87
|
-
CREATE DATABASE \${sql.ident(newDB)}
|
|
88
|
-
\`)
|
|
89
|
-
`,
|
|
90
|
-
config: `
|
|
91
|
-
config.migrations.autoApply = true
|
|
92
|
-
config.types.autogenerate = false
|
|
93
|
-
config.db.connectionString = connectionString.replace(/\\/[a-zA-Z0-9\\-_]+$/, '/' + newDB)
|
|
94
|
-
config.db.schemalock = false
|
|
95
|
-
`,
|
|
96
|
-
post: `
|
|
97
|
-
t.after(async () => {
|
|
98
|
-
t.diagnostic('Disposing test database ' + newDB)
|
|
99
|
-
await db.query(sql\`
|
|
100
|
-
DROP DATABASE \${sql.ident(newDB)}
|
|
101
|
-
\`)
|
|
102
|
-
await db.dispose()
|
|
103
|
-
})
|
|
104
|
-
`
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function jsHelperMySQL (connectionString) {
|
|
109
|
-
return {
|
|
110
|
-
// TODO(mcollina): replace sql-mapper
|
|
111
|
-
requires: `
|
|
112
|
-
const { createConnectionPool } = require('@platformatic/sql-mapper')
|
|
113
|
-
const connectionString = '${connectionString}'
|
|
114
|
-
let counter = 0
|
|
115
|
-
`,
|
|
116
|
-
pre: `
|
|
117
|
-
const { db, sql } = await createConnectionPool({
|
|
118
|
-
log: {
|
|
119
|
-
debug: () => {},
|
|
120
|
-
info: () => {},
|
|
121
|
-
trace: () => {}
|
|
122
|
-
},
|
|
123
|
-
connectionString,
|
|
124
|
-
poolSize: 1
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
const newDB = \`t-\${process.pid}-\${counter++}\`
|
|
128
|
-
t.diagnostic('Creating database ' + newDB)
|
|
129
|
-
|
|
130
|
-
await db.query(sql\`
|
|
131
|
-
CREATE DATABASE \${sql.ident(newDB)}
|
|
132
|
-
\`)
|
|
133
|
-
`,
|
|
134
|
-
config: `
|
|
135
|
-
config.migrations.autoApply = true
|
|
136
|
-
config.types.autogenerate = false
|
|
137
|
-
config.db.connectionString = connectionString.replace(/\\/[a-zA-Z0-9\\-_]+$/, '/' + newDB)
|
|
138
|
-
config.db.schemalock = false
|
|
139
|
-
`,
|
|
140
|
-
post: `
|
|
141
|
-
t.after(async () => {
|
|
142
|
-
t.diagnostic('Disposing test database ' + newDB)
|
|
143
|
-
await db.query(sql\`
|
|
144
|
-
DROP DATABASE \${sql.ident(newDB)}
|
|
145
|
-
\`)
|
|
146
|
-
await db.dispose()
|
|
147
|
-
})
|
|
148
|
-
`
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
const moviesTestJS = `\
|
|
153
|
-
'use strict'
|
|
154
|
-
|
|
155
|
-
const test = require('node:test')
|
|
156
|
-
const assert = require('node:assert')
|
|
157
|
-
const { getServer } = require('../helper')
|
|
158
|
-
|
|
159
|
-
test('movies', async (t) => {
|
|
160
|
-
const server = await getServer(t)
|
|
161
|
-
|
|
162
|
-
{
|
|
163
|
-
const res = await server.inject({
|
|
164
|
-
method: 'GET',
|
|
165
|
-
url: '/movies'
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
assert.strictEqual(res.statusCode, 200)
|
|
169
|
-
assert.deepStrictEqual(res.json(), [])
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
let id
|
|
173
|
-
{
|
|
174
|
-
const res = await server.inject({
|
|
175
|
-
method: 'POST',
|
|
176
|
-
url: '/movies',
|
|
177
|
-
body: {
|
|
178
|
-
title: 'The Matrix'
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
|
|
182
|
-
assert.strictEqual(res.statusCode, 200)
|
|
183
|
-
const body = res.json()
|
|
184
|
-
assert.strictEqual(body.title, 'The Matrix')
|
|
185
|
-
assert.strictEqual(body.id !== undefined, true)
|
|
186
|
-
id = body.id
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
{
|
|
190
|
-
const res = await server.inject({
|
|
191
|
-
method: 'GET',
|
|
192
|
-
url: '/movies'
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
assert.strictEqual(res.statusCode, 200)
|
|
196
|
-
assert.deepStrictEqual(res.json(), [{
|
|
197
|
-
id,
|
|
198
|
-
title: 'The Matrix'
|
|
199
|
-
}])
|
|
200
|
-
}
|
|
201
|
-
})
|
|
202
|
-
`
|
|
203
|
-
|
|
204
|
-
const moviesTestTS = `\
|
|
205
|
-
import test from 'node:test'
|
|
206
|
-
import assert from 'node:assert'
|
|
207
|
-
import { getServer } from '../helper'
|
|
208
|
-
|
|
209
|
-
test('movies', async (t) => {
|
|
210
|
-
const server = await getServer(t)
|
|
211
|
-
|
|
212
|
-
{
|
|
213
|
-
const res = await server.inject({
|
|
214
|
-
method: 'GET',
|
|
215
|
-
url: '/movies'
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
assert.strictEqual(res.statusCode, 200)
|
|
219
|
-
assert.deepStrictEqual(res.json(), [])
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
let id : Number
|
|
223
|
-
{
|
|
224
|
-
const res = await server.inject({
|
|
225
|
-
method: 'POST',
|
|
226
|
-
url: '/movies',
|
|
227
|
-
body: {
|
|
228
|
-
title: 'The Matrix'
|
|
229
|
-
}
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
assert.strictEqual(res.statusCode, 200)
|
|
233
|
-
const body = res.json()
|
|
234
|
-
assert.strictEqual(body.title, 'The Matrix')
|
|
235
|
-
assert.strictEqual(body.id !== undefined, true)
|
|
236
|
-
id = body.id as Number
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
{
|
|
240
|
-
const res = await server.inject({
|
|
241
|
-
method: 'GET',
|
|
242
|
-
url: '/movies'
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
assert.strictEqual(res.statusCode, 200)
|
|
246
|
-
assert.deepStrictEqual(res.json(), [{
|
|
247
|
-
id,
|
|
248
|
-
title: 'The Matrix'
|
|
249
|
-
}])
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
`
|
|
253
|
-
|
|
254
|
-
function generateConfig (isRuntimeContext, migrations, plugin, types, typescript, version, envPrefix) {
|
|
255
|
-
const connectionStringValue = envPrefix ? `PLT_${envPrefix}DATABASE_URL` : 'DATABASE_URL'
|
|
256
|
-
const config = {
|
|
257
|
-
$schema: `https://platformatic.dev/schemas/v${version}/db`,
|
|
258
|
-
db: {
|
|
259
|
-
connectionString: `{${connectionStringValue}}`,
|
|
260
|
-
graphql: true,
|
|
261
|
-
openapi: true,
|
|
262
|
-
schemalock: true
|
|
263
|
-
},
|
|
264
|
-
watch: {
|
|
265
|
-
ignore: ['*.sqlite', '*.sqlite-journal']
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
if (!isRuntimeContext) {
|
|
270
|
-
config.server = {
|
|
271
|
-
hostname: '{PLT_SERVER_HOSTNAME}',
|
|
272
|
-
port: '{PORT}',
|
|
273
|
-
logger: {
|
|
274
|
-
level: '{PLT_SERVER_LOGGER_LEVEL}'
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (migrations) {
|
|
280
|
-
config.migrations = {
|
|
281
|
-
dir: migrations
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (plugin === true) {
|
|
286
|
-
config.plugins = {
|
|
287
|
-
paths: [{
|
|
288
|
-
path: './plugins',
|
|
289
|
-
encapsulate: false
|
|
290
|
-
}, {
|
|
291
|
-
path: './routes'
|
|
292
|
-
}]
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (types === true) {
|
|
297
|
-
config.types = {
|
|
298
|
-
autogenerate: true
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (typescript === true && config.plugins) {
|
|
303
|
-
config.plugins.typescript = `{PLT_${envPrefix}TYPESCRIPT}`
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
return config
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function generateEnv (isRuntimeContext, hostname, port, connectionString, typescript, envPrefix) {
|
|
310
|
-
let env = ''
|
|
311
|
-
if (envPrefix) {
|
|
312
|
-
env += `PLT_${envPrefix}`
|
|
313
|
-
}
|
|
314
|
-
env += `DATABASE_URL=${connectionString}\n`
|
|
315
|
-
|
|
316
|
-
if (!isRuntimeContext) {
|
|
317
|
-
env += `\
|
|
318
|
-
PLT_SERVER_HOSTNAME=${hostname}
|
|
319
|
-
PORT=${port}
|
|
320
|
-
PLT_SERVER_LOGGER_LEVEL=info
|
|
321
|
-
|
|
322
|
-
`
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (typescript === true) {
|
|
326
|
-
env += `\
|
|
327
|
-
# Set to false to disable automatic typescript compilation.
|
|
328
|
-
# Changing this setting is needed for production
|
|
329
|
-
PLT_${envPrefix}TYPESCRIPT=true
|
|
330
|
-
`
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return env
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export function getConnectionString (database) {
|
|
337
|
-
return connectionStrings[database]
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
export async function createDB (params, logger, currentDir, version) {
|
|
341
|
-
let {
|
|
342
|
-
isRuntimeContext,
|
|
343
|
-
hostname,
|
|
344
|
-
port,
|
|
345
|
-
database = 'sqlite',
|
|
346
|
-
migrations = 'migrations',
|
|
347
|
-
plugin = true,
|
|
348
|
-
types = true,
|
|
349
|
-
typescript = false,
|
|
350
|
-
connectionString,
|
|
351
|
-
staticWorkspaceGitHubAction,
|
|
352
|
-
dynamicWorkspaceGitHubAction,
|
|
353
|
-
runtimeContext,
|
|
354
|
-
initGitRepository
|
|
355
|
-
} = params
|
|
356
|
-
|
|
357
|
-
const dbEnv = {
|
|
358
|
-
DATABASE_URL: connectionString,
|
|
359
|
-
PLT_SERVER_LOGGER_LEVEL: 'info',
|
|
360
|
-
PORT: port,
|
|
361
|
-
PLT_SERVER_HOSTNAME: hostname
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
if (typescript) {
|
|
365
|
-
dbEnv.PLT_TYPESCRIPT = true
|
|
366
|
-
}
|
|
367
|
-
connectionString = connectionString || getConnectionString(database)
|
|
368
|
-
const createMigrations = !!migrations // If we don't define a migrations folder, we don't create it
|
|
369
|
-
const envPrefix = runtimeContext !== undefined ? `${runtimeContext.envPrefix}_` : ''
|
|
370
|
-
|
|
371
|
-
const config = generateConfig(isRuntimeContext, migrations, plugin, types, typescript, version, envPrefix)
|
|
372
|
-
await writeFile(join(currentDir, 'platformatic.db.json'), JSON.stringify(config, null, 2))
|
|
373
|
-
logger.info('Configuration file platformatic.db.json successfully created.')
|
|
374
|
-
|
|
375
|
-
const env = generateEnv(isRuntimeContext, hostname, port, connectionString, typescript, envPrefix)
|
|
376
|
-
const envSample = generateEnv(isRuntimeContext, hostname, port, getConnectionString(database), typescript, envPrefix)
|
|
377
|
-
await appendFile(join(currentDir, '.env'), env)
|
|
378
|
-
await writeFile(join(currentDir, '.env.sample'), envSample)
|
|
379
|
-
|
|
380
|
-
const migrationsFolderName = migrations
|
|
381
|
-
if (createMigrations) {
|
|
382
|
-
await safeMkdir(join(currentDir, migrationsFolderName))
|
|
383
|
-
logger.info(`Migrations folder ${migrationsFolderName} successfully created.`)
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
const migrationFileNameDo = '001.do.sql'
|
|
387
|
-
const migrationFileNameUndo = '001.undo.sql'
|
|
388
|
-
const migrationFilePathDo = join(currentDir, migrationsFolderName, migrationFileNameDo)
|
|
389
|
-
const migrationFilePathUndo = join(currentDir, migrationsFolderName, migrationFileNameUndo)
|
|
390
|
-
if (createMigrations) {
|
|
391
|
-
await writeFile(migrationFilePathDo, moviesMigrationDo(database))
|
|
392
|
-
logger.info(`Migration file ${migrationFileNameDo} successfully created.`)
|
|
393
|
-
await writeFile(migrationFilePathUndo, moviesMigrationUndo)
|
|
394
|
-
logger.info(`Migration file ${migrationFileNameUndo} successfully created.`)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
if (typescript === true) {
|
|
398
|
-
const tsConfigFileName = join(currentDir, 'tsconfig.json')
|
|
399
|
-
const tsConfig = getTsConfig(TS_OUT_DIR)
|
|
400
|
-
await writeFile(tsConfigFileName, JSON.stringify(tsConfig, null, 2))
|
|
401
|
-
logger.info(`Typescript configuration file ${tsConfigFileName} successfully created.`)
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (plugin) {
|
|
405
|
-
let jsHelper = { pre: '', config: '', post: '' }
|
|
406
|
-
switch (database) {
|
|
407
|
-
case 'sqlite':
|
|
408
|
-
jsHelper = jsHelperSqlite
|
|
409
|
-
break
|
|
410
|
-
case 'mysql':
|
|
411
|
-
jsHelper = jsHelperMySQL(connectionString)
|
|
412
|
-
break
|
|
413
|
-
case 'postgres':
|
|
414
|
-
jsHelper = jsHelperPostgres(connectionString)
|
|
415
|
-
break
|
|
416
|
-
case 'mariadb':
|
|
417
|
-
jsHelper = jsHelperMySQL(connectionString)
|
|
418
|
-
break
|
|
419
|
-
}
|
|
420
|
-
await generatePlugins(logger, currentDir, typescript, 'db', jsHelper)
|
|
421
|
-
|
|
422
|
-
if (createMigrations) {
|
|
423
|
-
if (typescript) {
|
|
424
|
-
await writeFile(join(currentDir, 'test', 'routes', 'movies.test.ts'), moviesTestTS)
|
|
425
|
-
} else {
|
|
426
|
-
await writeFile(join(currentDir, 'test', 'routes', 'movies.test.js'), moviesTestJS)
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (staticWorkspaceGitHubAction) {
|
|
432
|
-
await createStaticWorkspaceGHAction(logger, dbEnv, './platformatic.db.json', currentDir, typescript)
|
|
433
|
-
}
|
|
434
|
-
if (dynamicWorkspaceGitHubAction) {
|
|
435
|
-
await createDynamicWorkspaceGHAction(logger, dbEnv, './platformatic.db.json', currentDir, typescript)
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if (initGitRepository) {
|
|
439
|
-
await createGitRepository(logger, currentDir)
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
if (isRuntimeContext) {
|
|
443
|
-
return addPrefixToEnv(isRuntimeContext)
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return dbEnv
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
export default createDB
|