directus 9.4.3 → 9.5.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.
Files changed (108) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/auth.d.ts +2 -1
  3. package/dist/auth/drivers/oauth2.js +10 -20
  4. package/dist/auth/drivers/openid.js +12 -2
  5. package/dist/cli/commands/init/questions.d.ts +3 -0
  6. package/dist/cli/commands/init/questions.js +2 -0
  7. package/dist/cli/utils/create-db-connection.d.ts +1 -1
  8. package/dist/cli/utils/create-db-connection.js +11 -1
  9. package/dist/cli/utils/drivers.d.ts +1 -0
  10. package/dist/cli/utils/drivers.js +2 -1
  11. package/dist/controllers/files.js +1 -1
  12. package/dist/controllers/utils.js +2 -0
  13. package/dist/database/helpers/date/index.d.ts +1 -0
  14. package/dist/database/helpers/date/index.js +3 -1
  15. package/dist/database/helpers/geometry/index.d.ts +1 -0
  16. package/dist/database/helpers/geometry/index.js +3 -1
  17. package/dist/database/helpers/index.d.ts +2 -0
  18. package/dist/database/helpers/index.js +2 -0
  19. package/dist/database/helpers/schema/dialects/cockroachdb.d.ts +16 -0
  20. package/dist/database/helpers/schema/dialects/cockroachdb.js +16 -0
  21. package/dist/database/helpers/schema/dialects/default.d.ts +3 -0
  22. package/dist/database/helpers/schema/dialects/default.js +7 -0
  23. package/dist/database/helpers/schema/dialects/oracle.d.ts +12 -0
  24. package/dist/database/helpers/schema/dialects/oracle.js +13 -0
  25. package/dist/database/helpers/schema/index.d.ts +7 -0
  26. package/dist/database/helpers/schema/index.js +17 -0
  27. package/dist/database/helpers/schema/types.d.ts +25 -0
  28. package/dist/database/helpers/schema/types.js +89 -0
  29. package/dist/database/index.d.ts +1 -1
  30. package/dist/database/index.js +33 -16
  31. package/dist/database/migrations/20201105B-change-webhook-url-type.js +6 -25
  32. package/dist/database/migrations/20210312A-webhooks-collections-text.js +6 -25
  33. package/dist/database/migrations/20210415A-make-filesize-nullable.js +9 -4
  34. package/dist/database/migrations/20210506A-rename-interfaces.js +1 -1
  35. package/dist/database/migrations/20210510A-restructure-relations.js +12 -4
  36. package/dist/database/migrations/20210525A-add-insights.js +2 -2
  37. package/dist/database/migrations/20210626A-change-filesize-bigint.js +5 -7
  38. package/dist/database/migrations/20210903A-add-auth-provider.js +11 -2
  39. package/dist/database/migrations/20210907A-webhooks-collections-not-null.js +6 -20
  40. package/dist/database/migrations/20210920A-webhooks-url-not-null.js +10 -14
  41. package/dist/database/migrations/20211211A-add-shares.js +2 -2
  42. package/dist/database/run-ast.d.ts +1 -1
  43. package/dist/database/seeds/01-collections.yaml +1 -0
  44. package/dist/database/seeds/02-roles.yaml +1 -0
  45. package/dist/database/seeds/03-users.yaml +1 -0
  46. package/dist/database/system-data/relations/index.d.ts +1 -1
  47. package/dist/emitter.d.ts +3 -4
  48. package/dist/emitter.js +2 -8
  49. package/dist/exceptions/database/translate.js +1 -0
  50. package/dist/exceptions/index.d.ts +1 -0
  51. package/dist/exceptions/index.js +1 -0
  52. package/dist/exceptions/unsupported-media-type.d.ts +4 -0
  53. package/dist/exceptions/unsupported-media-type.js +10 -0
  54. package/dist/extensions.d.ts +6 -5
  55. package/dist/extensions.js +56 -42
  56. package/dist/logger.js +22 -1
  57. package/dist/services/authentication.d.ts +2 -2
  58. package/dist/services/authentication.js +3 -1
  59. package/dist/services/authorization.d.ts +2 -3
  60. package/dist/services/collections.d.ts +2 -2
  61. package/dist/services/collections.js +10 -6
  62. package/dist/services/fields.d.ts +2 -3
  63. package/dist/services/fields.js +8 -4
  64. package/dist/services/graphql.d.ts +2 -1
  65. package/dist/services/import.d.ts +2 -2
  66. package/dist/services/import.js +2 -1
  67. package/dist/services/items.d.ts +2 -2
  68. package/dist/services/items.js +22 -18
  69. package/dist/services/mail/index.d.ts +2 -2
  70. package/dist/services/meta.d.ts +2 -2
  71. package/dist/services/payload.d.ts +2 -2
  72. package/dist/services/relations.d.ts +2 -2
  73. package/dist/services/server.d.ts +2 -2
  74. package/dist/services/specifications.d.ts +2 -2
  75. package/dist/services/users.d.ts +2 -3
  76. package/dist/services/utils.d.ts +2 -2
  77. package/dist/types/ast.d.ts +1 -2
  78. package/dist/types/auth.d.ts +1 -3
  79. package/dist/types/index.d.ts +0 -3
  80. package/dist/types/index.js +0 -3
  81. package/dist/types/services.d.ts +1 -3
  82. package/dist/types/snapshot.d.ts +1 -2
  83. package/dist/utils/apply-query.d.ts +1 -2
  84. package/dist/utils/apply-query.js +1 -1
  85. package/dist/utils/apply-snapshot.d.ts +2 -1
  86. package/dist/utils/get-ast-from-query.d.ts +2 -3
  87. package/dist/utils/get-permissions.d.ts +1 -2
  88. package/dist/utils/get-relation-type.d.ts +1 -1
  89. package/dist/utils/get-schema.d.ts +1 -2
  90. package/dist/utils/get-snapshot.d.ts +2 -1
  91. package/dist/utils/merge-permissions-for-share.d.ts +1 -2
  92. package/dist/utils/reduce-schema.d.ts +1 -2
  93. package/example.env +8 -0
  94. package/package.json +15 -14
  95. package/dist/cli/index.test.d.ts +0 -1
  96. package/dist/cli/index.test.js +0 -58
  97. package/dist/middleware/cache.test.d.ts +0 -1
  98. package/dist/middleware/cache.test.js +0 -62
  99. package/dist/tests/database/migrations/run.test.d.ts +0 -1
  100. package/dist/tests/database/migrations/run.test.js +0 -29
  101. package/dist/types/extensions.d.ts +0 -43
  102. package/dist/types/extensions.js +0 -2
  103. package/dist/types/relation.d.ts +0 -21
  104. package/dist/types/relation.js +0 -2
  105. package/dist/types/schema.d.ts +0 -32
  106. package/dist/types/schema.js +0 -2
  107. package/dist/utils/get-cache-key.test.d.ts +0 -1
  108. package/dist/utils/get-cache-key.test.js +0 -53
package/README.md CHANGED
@@ -33,7 +33,7 @@ Learn more at...
33
33
 
34
34
  ## Installing
35
35
 
36
- Directus requires NodeJS 10+. Create a new project with our simple CLI tool:
36
+ Directus requires NodeJS 10+. Create a new project with our simple CLI tool:
37
37
 
38
38
  ```
39
39
  npm init directus-project my-project
@@ -1,5 +1,6 @@
1
+ import { SchemaOverview } from '@directus/shared/types';
1
2
  import { Knex } from 'knex';
2
- import { AuthDriverOptions, SchemaOverview, User } from '../types';
3
+ import { AuthDriverOptions, User } from '../types';
3
4
  export declare abstract class AuthDriver {
4
5
  knex: Knex;
5
6
  schema: SchemaOverview;
@@ -22,7 +22,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
22
22
  constructor(options, config) {
23
23
  super(options, config);
24
24
  const { authorizeUrl, accessUrl, profileUrl, clientId, clientSecret, ...additionalConfig } = config;
25
- if (!authorizeUrl || !accessUrl || !clientId || !clientSecret || !additionalConfig.provider) {
25
+ if (!authorizeUrl || !accessUrl || !profileUrl || !clientId || !clientSecret || !additionalConfig.provider) {
26
26
  throw new exceptions_1.InvalidConfigException('Invalid provider config', { provider: additionalConfig.provider });
27
27
  }
28
28
  const redirectUrl = new url_1.Url(env_1.default.PUBLIC_URL).addPath('auth', 'login', additionalConfig.provider, 'callback');
@@ -33,8 +33,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
33
33
  authorization_endpoint: authorizeUrl,
34
34
  token_endpoint: accessUrl,
35
35
  userinfo_endpoint: profileUrl,
36
- // Required for openid providers (openid flow should be preferred!)
37
- issuer: additionalConfig.issuerUrl,
36
+ issuer: additionalConfig.provider,
38
37
  });
39
38
  this.client = new issuer.Client({
40
39
  client_id: clientId,
@@ -84,16 +83,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
84
83
  let userInfo;
85
84
  try {
86
85
  tokenSet = await this.client.oauthCallback(this.redirectUrl, { code: payload.code, state: payload.state }, { code_verifier: payload.codeVerifier, state: openid_client_1.generators.codeChallenge(payload.codeVerifier) });
87
- const issuer = this.client.issuer;
88
- if (issuer.metadata.userinfo_endpoint) {
89
- userInfo = await this.client.userinfo(tokenSet.access_token);
90
- }
91
- else if (tokenSet.id_token) {
92
- userInfo = tokenSet.claims();
93
- }
94
- else {
95
- throw new exceptions_1.InvalidConfigException('OAuth profile URL not defined', { provider: this.config.provider });
96
- }
86
+ userInfo = await this.client.userinfo(tokenSet.access_token);
97
87
  }
98
88
  catch (e) {
99
89
  throw handleError(e);
@@ -103,7 +93,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
103
93
  // Fallback to email if explicit identifier not found
104
94
  const identifier = (_a = userInfo[identifierKey]) !== null && _a !== void 0 ? _a : email;
105
95
  if (!identifier) {
106
- logger_1.default.warn(`Failed to find user identifier for provider "${this.config.provider}"`);
96
+ logger_1.default.warn(`[OAuth2] Failed to find user identifier for provider "${this.config.provider}"`);
107
97
  throw new exceptions_1.InvalidCredentialsException();
108
98
  }
109
99
  const userId = await this.fetchUserId(identifier);
@@ -140,7 +130,7 @@ class OAuth2AuthDriver extends local_1.LocalAuthDriver {
140
130
  authData = JSON.parse(authData);
141
131
  }
142
132
  catch {
143
- logger_1.default.warn(`Session data isn't valid JSON: ${authData}`);
133
+ logger_1.default.warn(`[OAuth2] Session data isn't valid JSON: ${authData}`);
144
134
  }
145
135
  }
146
136
  if (authData === null || authData === void 0 ? void 0 : authData.refreshToken) {
@@ -163,12 +153,12 @@ exports.OAuth2AuthDriver = OAuth2AuthDriver;
163
153
  const handleError = (e) => {
164
154
  if (e instanceof openid_client_1.errors.OPError) {
165
155
  if (e.error === 'invalid_grant') {
166
- logger_1.default.trace(e, `[OAuth2] Invalid grant.`);
167
156
  // Invalid token
157
+ logger_1.default.trace(e, `[OAuth2] Invalid grant`);
168
158
  return new exceptions_1.InvalidTokenException();
169
159
  }
170
- logger_1.default.trace(e, `[OAuth2] Unknown OP error.`);
171
160
  // Server response error
161
+ logger_1.default.trace(e, `[OAuth2] Unknown OP error`);
172
162
  return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
173
163
  service: 'oauth2',
174
164
  message: e.error_description,
@@ -176,10 +166,10 @@ const handleError = (e) => {
176
166
  }
177
167
  else if (e instanceof openid_client_1.errors.RPError) {
178
168
  // Internal client error
179
- logger_1.default.trace(e, `[OAuth2] Unknown RP error.`);
169
+ logger_1.default.trace(e, `[OAuth2] Unknown RP error`);
180
170
  return new exceptions_1.InvalidCredentialsException();
181
171
  }
182
- logger_1.default.trace(e, `[OAuth2] Unknown error.`);
172
+ logger_1.default.trace(e, `[OAuth2] Unknown error`);
183
173
  return e;
184
174
  };
185
175
  function createOAuth2AuthRouter(providerName) {
@@ -221,7 +211,7 @@ function createOAuth2AuthRouter(providerName) {
221
211
  try {
222
212
  res.clearCookie(`oauth2.${providerName}`);
223
213
  if (!req.query.code || !req.query.state) {
224
- logger_1.default.warn(`[OAuth2]Couldn't extract OAuth2 code or state from query: ${JSON.stringify(req.query)}`);
214
+ logger_1.default.warn(`[OAuth2] Couldn't extract OAuth2 code or state from query: ${JSON.stringify(req.query)}`);
225
215
  }
226
216
  authResponse = await authenticationService.login(providerName, {
227
217
  code: req.query.code,
@@ -83,6 +83,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
83
83
  async getUserID(payload) {
84
84
  var _a;
85
85
  if (!payload.code || !payload.codeVerifier) {
86
+ logger_1.default.trace('[OpenID] No code or codeVerifier in payload');
86
87
  throw new exceptions_1.InvalidCredentialsException();
87
88
  }
88
89
  let tokenSet;
@@ -106,7 +107,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
106
107
  // Fallback to email if explicit identifier not found
107
108
  const identifier = (_a = userInfo[identifierKey !== null && identifierKey !== void 0 ? identifierKey : 'sub']) !== null && _a !== void 0 ? _a : email;
108
109
  if (!identifier) {
109
- logger_1.default.warn(`Failed to find user identifier for provider "${this.config.provider}"`);
110
+ logger_1.default.warn(`[OpenID] Failed to find user identifier for provider "${this.config.provider}"`);
110
111
  throw new exceptions_1.InvalidCredentialsException();
111
112
  }
112
113
  const userId = await this.fetchUserId(identifier);
@@ -122,6 +123,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
122
123
  const isEmailVerified = !requireVerifiedEmail || userInfo.email_verified;
123
124
  // Is public registration allowed?
124
125
  if (!allowPublicRegistration || !isEmailVerified) {
126
+ logger_1.default.trace(`[OpenID] User doesn't exist, and public registration not allowed for provider "${this.config.provider}"`);
125
127
  throw new exceptions_1.InvalidCredentialsException();
126
128
  }
127
129
  await this.usersService.createOne({
@@ -145,7 +147,7 @@ class OpenIDAuthDriver extends local_1.LocalAuthDriver {
145
147
  authData = JSON.parse(authData);
146
148
  }
147
149
  catch {
148
- logger_1.default.warn(`Session data isn't valid JSON: ${authData}`);
150
+ logger_1.default.warn(`[OpenID] Session data isn't valid JSON: ${authData}`);
149
151
  }
150
152
  }
151
153
  if (authData === null || authData === void 0 ? void 0 : authData.refreshToken) {
@@ -170,9 +172,11 @@ const handleError = (e) => {
170
172
  if (e instanceof openid_client_1.errors.OPError) {
171
173
  if (e.error === 'invalid_grant') {
172
174
  // Invalid token
175
+ logger_1.default.trace(e, `[OpenID] Invalid grant`);
173
176
  return new exceptions_1.InvalidTokenException();
174
177
  }
175
178
  // Server response error
179
+ logger_1.default.trace(e, `[OpenID] Unknown OP error`);
176
180
  return new exceptions_1.ServiceUnavailableException('Service returned unexpected response', {
177
181
  service: 'openid',
178
182
  message: e.error_description,
@@ -180,8 +184,10 @@ const handleError = (e) => {
180
184
  }
181
185
  else if (e instanceof openid_client_1.errors.RPError) {
182
186
  // Internal client error
187
+ logger_1.default.trace(e, `[OpenID] Unknown RP error`);
183
188
  return new exceptions_1.InvalidCredentialsException();
184
189
  }
190
+ logger_1.default.trace(e, `[OpenID] Unknown error`);
185
191
  return e;
186
192
  };
187
193
  function createOpenIDAuthRouter(providerName) {
@@ -248,8 +254,12 @@ function createOpenIDAuthRouter(providerName) {
248
254
  else if (error instanceof exceptions_1.InvalidTokenException) {
249
255
  reason = 'INVALID_TOKEN';
250
256
  }
257
+ else {
258
+ logger_1.default.warn(error, `[OpenID] Unexpected error during OpenID login`);
259
+ }
251
260
  return res.redirect(`${redirect.split('?')[0]}?reason=${reason}`);
252
261
  }
262
+ logger_1.default.warn(error, `[OpenID] Unexpected error during OpenID login`);
253
263
  throw error;
254
264
  }
255
265
  const { accessToken, refreshToken, expires } = authResponse;
@@ -8,6 +8,9 @@ export declare const databaseQuestions: {
8
8
  pg: (({ client }: {
9
9
  client: string;
10
10
  }) => Record<string, any>)[];
11
+ cockroachdb: (({ client }: {
12
+ client: string;
13
+ }) => Record<string, any>)[];
11
14
  oracledb: (({ client }: {
12
15
  client: string;
13
16
  }) => Record<string, any>)[];
@@ -24,6 +24,7 @@ const port = ({ client }) => ({
24
24
  default() {
25
25
  const ports = {
26
26
  pg: 5432,
27
+ cockroachdb: 26257,
27
28
  mysql: 3306,
28
29
  oracledb: 1521,
29
30
  mssql: 1433,
@@ -64,6 +65,7 @@ exports.databaseQuestions = {
64
65
  sqlite3: [filename],
65
66
  mysql: [host, port, database, user, password],
66
67
  pg: [host, port, database, user, password, ssl],
68
+ cockroachdb: [host, port, database, user, password, ssl],
67
69
  oracledb: [host, port, database, user, password],
68
70
  mssql: [host, port, database, user, password, encrypt],
69
71
  };
@@ -9,4 +9,4 @@ export declare type Credentials = {
9
9
  ssl?: boolean;
10
10
  options__encrypt?: boolean;
11
11
  };
12
- export default function createDBConnection(client: 'sqlite3' | 'mysql' | 'pg' | 'oracledb' | 'mssql', credentials: Credentials): Knex<any, unknown[]>;
12
+ export default function createDBConnection(client: 'sqlite3' | 'mysql' | 'pg' | 'oracledb' | 'mssql' | 'cockroachdb', credentials: Credentials): Knex<any, unknown[]>;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const knex_1 = require("knex");
7
7
  const path_1 = __importDefault(require("path"));
8
+ const util_1 = require("util");
8
9
  function createDBConnection(client, credentials) {
9
10
  let connection = {};
10
11
  if (client === 'sqlite3') {
@@ -22,7 +23,7 @@ function createDBConnection(client, credentials) {
22
23
  user: user,
23
24
  password: password,
24
25
  };
25
- if (client === 'pg') {
26
+ if (client === 'pg' || client === 'cockroachdb') {
26
27
  const { ssl } = credentials;
27
28
  connection['ssl'] = ssl;
28
29
  }
@@ -40,10 +41,19 @@ function createDBConnection(client, credentials) {
40
41
  extension: 'js',
41
42
  directory: path_1.default.resolve(__dirname, '../../database/seeds/'),
42
43
  },
44
+ pool: {},
43
45
  };
44
46
  if (client === 'sqlite3') {
45
47
  knexConfig.useNullAsDefault = true;
46
48
  }
49
+ if (client === 'cockroachdb') {
50
+ knexConfig.pool.afterCreate = async (conn, callback) => {
51
+ const run = (0, util_1.promisify)(conn.query.bind(conn));
52
+ await run('SET serial_normalization = "sql_sequence"');
53
+ await run('SET default_int_size = 4');
54
+ callback(null, conn);
55
+ };
56
+ }
47
57
  const db = (0, knex_1.knex)(knexConfig);
48
58
  return db;
49
59
  }
@@ -1,5 +1,6 @@
1
1
  export declare const drivers: {
2
2
  pg: string;
3
+ cockroachdb: string;
3
4
  mysql: string;
4
5
  sqlite3: string;
5
6
  mssql: string;
@@ -3,10 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDriverForClient = exports.drivers = void 0;
4
4
  exports.drivers = {
5
5
  pg: 'PostgreSQL / Redshift',
6
+ cockroachdb: 'CockroachDB (Beta)',
6
7
  mysql: 'MySQL / MariaDB / Aurora',
7
8
  sqlite3: 'SQLite',
8
9
  mssql: 'Microsoft SQL Server',
9
- oracledb: 'Oracle Database (Alpha)',
10
+ oracledb: 'Oracle Database',
10
11
  };
11
12
  function getDriverForClient(client) {
12
13
  for (const [key, value] of Object.entries(exports.drivers)) {
@@ -20,7 +20,7 @@ const router = express_1.default.Router();
20
20
  router.use((0, use_collection_1.default)('directus_files'));
21
21
  const multipartHandler = (0, async_handler_1.default)(async (req, res, next) => {
22
22
  if (req.is('multipart/form-data') === false)
23
- return next();
23
+ throw new exceptions_1.UnsupportedMediaTypeException(`Unsupported Content-Type header`);
24
24
  let headers;
25
25
  if (req.headers['content-type']) {
26
26
  headers = req.headers;
@@ -66,6 +66,8 @@ router.post('/revert/:revision', (0, async_handler_1.default)(async (req, res, n
66
66
  next();
67
67
  }), respond_1.respond);
68
68
  router.post('/import/:collection', collection_exists_1.default, (0, async_handler_1.default)(async (req, res, next) => {
69
+ if (req.is('multipart/form-data') === false)
70
+ throw new exceptions_1.UnsupportedMediaTypeException(`Unsupported Content-Type header`);
69
71
  const service = new services_1.ImportService({
70
72
  accountability: req.accountability,
71
73
  schema: req.schema,
@@ -1,5 +1,6 @@
1
1
  export { DateHelperPostgres as postgres } from './dialects/postgres';
2
2
  export { DateHelperPostgres as redshift } from './dialects/postgres';
3
+ export { DateHelperPostgres as cockroachdb } from './dialects/postgres';
3
4
  export { DateHelperOracle as oracle } from './dialects/oracle';
4
5
  export { DateHelperSQLite as sqlite } from './dialects/sqlite';
5
6
  export { DateHelperMySQL as mysql } from './dialects/mysql';
@@ -1,10 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.postgres = void 0;
3
+ exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.cockroachdb = exports.redshift = exports.postgres = void 0;
4
4
  var postgres_1 = require("./dialects/postgres");
5
5
  Object.defineProperty(exports, "postgres", { enumerable: true, get: function () { return postgres_1.DateHelperPostgres; } });
6
6
  var postgres_2 = require("./dialects/postgres");
7
7
  Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return postgres_2.DateHelperPostgres; } });
8
+ var postgres_3 = require("./dialects/postgres");
9
+ Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return postgres_3.DateHelperPostgres; } });
8
10
  var oracle_1 = require("./dialects/oracle");
9
11
  Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return oracle_1.DateHelperOracle; } });
10
12
  var sqlite_1 = require("./dialects/sqlite");
@@ -1,4 +1,5 @@
1
1
  export { GeometryHelperPostgres as postgres } from './dialects/postgres';
2
+ export { GeometryHelperPostgres as cockroachdb } from './dialects/postgres';
2
3
  export { GeometryHelperRedshift as redshift } from './dialects/redshift';
3
4
  export { GeometryHelperOracle as oracle } from './dialects/oracle';
4
5
  export { GeometryHelperSQLite as sqlite } from './dialects/sqlite';
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.postgres = void 0;
3
+ exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.cockroachdb = exports.postgres = void 0;
4
4
  var postgres_1 = require("./dialects/postgres");
5
5
  Object.defineProperty(exports, "postgres", { enumerable: true, get: function () { return postgres_1.GeometryHelperPostgres; } });
6
+ var postgres_2 = require("./dialects/postgres");
7
+ Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return postgres_2.GeometryHelperPostgres; } });
6
8
  var redshift_1 = require("./dialects/redshift");
7
9
  Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return redshift_1.GeometryHelperRedshift; } });
8
10
  var oracle_1 = require("./dialects/oracle");
@@ -1,8 +1,10 @@
1
1
  import { Knex } from 'knex';
2
2
  import * as dateHelpers from './date';
3
3
  import * as geometryHelpers from './geometry';
4
+ import * as schemaHelpers from './schema';
4
5
  export declare function getHelpers(database: Knex): {
5
6
  date: dateHelpers.postgres | dateHelpers.oracle | dateHelpers.sqlite | dateHelpers.mysql | dateHelpers.mssql;
6
7
  st: geometryHelpers.postgres | geometryHelpers.redshift | geometryHelpers.oracle | geometryHelpers.sqlite | geometryHelpers.mysql | geometryHelpers.mssql;
8
+ schema: schemaHelpers.postgres | schemaHelpers.cockroachdb | schemaHelpers.oracle;
7
9
  };
8
10
  export declare type Helpers = ReturnType<typeof getHelpers>;
@@ -23,11 +23,13 @@ exports.getHelpers = void 0;
23
23
  const __1 = require("..");
24
24
  const dateHelpers = __importStar(require("./date"));
25
25
  const geometryHelpers = __importStar(require("./geometry"));
26
+ const schemaHelpers = __importStar(require("./schema"));
26
27
  function getHelpers(database) {
27
28
  const client = (0, __1.getDatabaseClient)(database);
28
29
  return {
29
30
  date: new dateHelpers[client](database),
30
31
  st: new geometryHelpers[client](database),
32
+ schema: new schemaHelpers[client](database),
31
33
  };
32
34
  }
33
35
  exports.getHelpers = getHelpers;
@@ -0,0 +1,16 @@
1
+ import { SchemaHelper } from '../types';
2
+ export declare class SchemaHelperCockroachDb extends SchemaHelper {
3
+ changeToText(table: string, column: string, options?: {
4
+ nullable?: boolean;
5
+ default?: any;
6
+ }): Promise<void>;
7
+ changeToString(table: string, column: string, options?: {
8
+ nullable?: boolean;
9
+ default?: any;
10
+ length?: number;
11
+ }): Promise<void>;
12
+ changeToInteger(table: string, column: string, options?: {
13
+ nullable?: boolean;
14
+ default?: any;
15
+ }): Promise<void>;
16
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaHelperCockroachDb = void 0;
4
+ const types_1 = require("../types");
5
+ class SchemaHelperCockroachDb extends types_1.SchemaHelper {
6
+ async changeToText(table, column, options = {}) {
7
+ await this.changeToTypeByCopy(table, column, options, (builder, column) => builder.text(column));
8
+ }
9
+ async changeToString(table, column, options = {}) {
10
+ await this.changeToTypeByCopy(table, column, options, (builder, column, options) => builder.string(column, options.length));
11
+ }
12
+ async changeToInteger(table, column, options = {}) {
13
+ await this.changeToTypeByCopy(table, column, options, (builder, column) => builder.integer(column));
14
+ }
15
+ }
16
+ exports.SchemaHelperCockroachDb = SchemaHelperCockroachDb;
@@ -0,0 +1,3 @@
1
+ import { SchemaHelper } from '../types';
2
+ export declare class SchemaHelperDefault extends SchemaHelper {
3
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaHelperDefault = void 0;
4
+ const types_1 = require("../types");
5
+ class SchemaHelperDefault extends types_1.SchemaHelper {
6
+ }
7
+ exports.SchemaHelperDefault = SchemaHelperDefault;
@@ -0,0 +1,12 @@
1
+ import { SchemaHelper } from '../types';
2
+ export declare class SchemaHelperOracle extends SchemaHelper {
3
+ changeToText(table: string, column: string, options?: {
4
+ nullable?: boolean;
5
+ default?: any;
6
+ }): Promise<void>;
7
+ changeToString(table: string, column: string, options?: {
8
+ nullable?: boolean;
9
+ default?: any;
10
+ length?: number;
11
+ }): Promise<void>;
12
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaHelperOracle = void 0;
4
+ const types_1 = require("../types");
5
+ class SchemaHelperOracle extends types_1.SchemaHelper {
6
+ async changeToText(table, column, options = {}) {
7
+ await this.changeToTypeByCopy(table, column, options, (builder, column) => builder.text(column));
8
+ }
9
+ async changeToString(table, column, options = {}) {
10
+ await this.changeToTypeByCopy(table, column, options, (builder, column, options) => builder.string(column, options.length));
11
+ }
12
+ }
13
+ exports.SchemaHelperOracle = SchemaHelperOracle;
@@ -0,0 +1,7 @@
1
+ export { SchemaHelperDefault as postgres } from './dialects/default';
2
+ export { SchemaHelperCockroachDb as cockroachdb } from './dialects/cockroachdb';
3
+ export { SchemaHelperDefault as redshift } from './dialects/default';
4
+ export { SchemaHelperOracle as oracle } from './dialects/oracle';
5
+ export { SchemaHelperDefault as sqlite } from './dialects/default';
6
+ export { SchemaHelperDefault as mysql } from './dialects/default';
7
+ export { SchemaHelperDefault as mssql } from './dialects/default';
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mssql = exports.mysql = exports.sqlite = exports.oracle = exports.redshift = exports.cockroachdb = exports.postgres = void 0;
4
+ var default_1 = require("./dialects/default");
5
+ Object.defineProperty(exports, "postgres", { enumerable: true, get: function () { return default_1.SchemaHelperDefault; } });
6
+ var cockroachdb_1 = require("./dialects/cockroachdb");
7
+ Object.defineProperty(exports, "cockroachdb", { enumerable: true, get: function () { return cockroachdb_1.SchemaHelperCockroachDb; } });
8
+ var default_2 = require("./dialects/default");
9
+ Object.defineProperty(exports, "redshift", { enumerable: true, get: function () { return default_2.SchemaHelperDefault; } });
10
+ var oracle_1 = require("./dialects/oracle");
11
+ Object.defineProperty(exports, "oracle", { enumerable: true, get: function () { return oracle_1.SchemaHelperOracle; } });
12
+ var default_3 = require("./dialects/default");
13
+ Object.defineProperty(exports, "sqlite", { enumerable: true, get: function () { return default_3.SchemaHelperDefault; } });
14
+ var default_4 = require("./dialects/default");
15
+ Object.defineProperty(exports, "mysql", { enumerable: true, get: function () { return default_4.SchemaHelperDefault; } });
16
+ var default_5 = require("./dialects/default");
17
+ Object.defineProperty(exports, "mssql", { enumerable: true, get: function () { return default_5.SchemaHelperDefault; } });
@@ -0,0 +1,25 @@
1
+ import { DatabaseHelper } from '../types';
2
+ import { Knex } from 'knex';
3
+ declare type Clients = 'mysql' | 'postgres' | 'cockroachdb' | 'sqlite' | 'oracle' | 'mssql' | 'redshift';
4
+ export declare abstract class SchemaHelper extends DatabaseHelper {
5
+ isOneOfClients(clients: Clients[]): boolean;
6
+ changeNullable(table: string, column: string, nullable: boolean): Promise<void>;
7
+ changeToText(table: string, column: string, options?: {
8
+ nullable?: boolean;
9
+ default?: any;
10
+ }): Promise<void>;
11
+ changeToInteger(table: string, column: string, options?: {
12
+ nullable?: boolean;
13
+ default?: any;
14
+ }): Promise<void>;
15
+ changeToString(table: string, column: string, options?: {
16
+ nullable?: boolean;
17
+ default?: any;
18
+ length?: number;
19
+ }): Promise<void>;
20
+ protected changeToTypeByCopy<Options extends {
21
+ nullable?: boolean;
22
+ default?: any;
23
+ }>(table: string, column: string, options: Options, cb: (builder: Knex.CreateTableBuilder, column: string, options: Options) => Knex.ColumnBuilder): Promise<void>;
24
+ }
25
+ export {};
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SchemaHelper = void 0;
4
+ const index_1 = require("../../index");
5
+ const types_1 = require("../types");
6
+ class SchemaHelper extends types_1.DatabaseHelper {
7
+ isOneOfClients(clients) {
8
+ return clients.includes((0, index_1.getDatabaseClient)(this.knex));
9
+ }
10
+ async changeNullable(table, column, nullable) {
11
+ await this.knex.schema.alterTable(table, (builder) => {
12
+ if (nullable) {
13
+ builder.setNullable(column);
14
+ }
15
+ else {
16
+ builder.dropNullable(column);
17
+ }
18
+ });
19
+ }
20
+ async changeToText(table, column, options = {}) {
21
+ await this.knex.schema.alterTable(table, (builder) => {
22
+ const b = builder.string(column);
23
+ if (options.nullable === true) {
24
+ b.nullable();
25
+ }
26
+ if (options.nullable === false) {
27
+ b.notNullable();
28
+ }
29
+ if (options.default !== undefined) {
30
+ b.defaultTo(options.default);
31
+ }
32
+ b.alter();
33
+ });
34
+ }
35
+ async changeToInteger(table, column, options = {}) {
36
+ await this.knex.schema.alterTable(table, (builder) => {
37
+ const b = builder.integer(column);
38
+ if (options.nullable === true) {
39
+ b.nullable();
40
+ }
41
+ if (options.nullable === false) {
42
+ b.notNullable();
43
+ }
44
+ if (options.default !== undefined) {
45
+ b.defaultTo(options.default);
46
+ }
47
+ b.alter();
48
+ });
49
+ }
50
+ async changeToString(table, column, options = {}) {
51
+ await this.knex.schema.alterTable(table, (builder) => {
52
+ const b = builder.string(column, options.length);
53
+ if (options.nullable === true) {
54
+ b.nullable();
55
+ }
56
+ if (options.nullable === false) {
57
+ b.notNullable();
58
+ }
59
+ if (options.default !== undefined) {
60
+ b.defaultTo(options.default);
61
+ }
62
+ b.alter();
63
+ });
64
+ }
65
+ async changeToTypeByCopy(table, column, options, cb) {
66
+ await this.knex.schema.alterTable(table, (builder) => {
67
+ const col = cb(builder, `${column}__temp`, options);
68
+ if (options.default !== undefined) {
69
+ col.defaultTo(options.default);
70
+ }
71
+ // Force new temporary column to be nullable (required, as there will already be rows in
72
+ // the table)
73
+ col.nullable();
74
+ });
75
+ await this.knex(table).update(`${column}__temp`, this.knex.ref(column));
76
+ await this.knex.schema.alterTable(table, (builder) => {
77
+ builder.dropColumn(column);
78
+ });
79
+ await this.knex.schema.alterTable(table, (builder) => {
80
+ builder.renameColumn(`${column}__temp`, column);
81
+ });
82
+ // We're altering the temporary column here. That starts nullable, so we only want to set it
83
+ // to NOT NULL when applicable
84
+ if (options.nullable === false) {
85
+ await this.changeNullable(table, column, options.nullable);
86
+ }
87
+ }
88
+ }
89
+ exports.SchemaHelper = SchemaHelper;
@@ -4,7 +4,7 @@ export default function getDatabase(): Knex;
4
4
  export declare function getSchemaInspector(): ReturnType<typeof SchemaInspector>;
5
5
  export declare function hasDatabaseConnection(database?: Knex): Promise<boolean>;
6
6
  export declare function validateDatabaseConnection(database?: Knex): Promise<void>;
7
- export declare function getDatabaseClient(database?: Knex): 'mysql' | 'postgres' | 'sqlite' | 'oracle' | 'mssql' | 'redshift';
7
+ export declare function getDatabaseClient(database?: Knex): 'mysql' | 'postgres' | 'cockroachdb' | 'sqlite' | 'oracle' | 'mssql' | 'redshift';
8
8
  export declare function isInstalled(): Promise<boolean>;
9
9
  export declare function validateMigrations(): Promise<boolean>;
10
10
  /**