@stacksjs/database 0.70.188 → 0.70.190

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/dist/seeder.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import type { Attribute, Model } from '@stacksjs/types';
2
+ /** Test whether a model holds accounts rather than fixtures. */
3
+ export declare function isAccountModel(name: string): boolean;
2
4
  /**
3
5
  * Test whether a model name is on the protected list.
4
6
  * Exported for downstream tooling (CI lint rules, custom seeders) so the
@@ -63,6 +65,23 @@ export declare function listSeedableModels(): Promise<Array<{ name: string, tabl
63
65
  * issuance / validation / refresh belongs here.
64
66
  */
65
67
  export declare const PROTECTED_MODELS: readonly string[];
68
+ /**
69
+ * Models whose rows are people, not fixtures.
70
+ *
71
+ * A seeded row is allowed to attach itself to a parent that already exists —
72
+ * that is how a seeded flight finds a seeded field. It is not allowed to
73
+ * attach itself to an *account*. These tables hold real sign-ins on any
74
+ * database that is not a scratch copy, and pointing invented rows at them
75
+ * hands one customer another customer's fabricated data: a farmer signs in
76
+ * and finds fields they have never seen, on a holding they do not own.
77
+ *
78
+ * Foreign keys to these models are left null. Which account owns a seeded
79
+ * row is a decision for the app that seeded it (a `demo:account` command, a
80
+ * fixture, a migration), not something a factory should guess.
81
+ *
82
+ * `allowProtected: true` (`./buddy seed --allow-protected`) opts back in.
83
+ */
84
+ export declare const ACCOUNT_MODELS: readonly string[];
66
85
  /**
67
86
  * Seeder configuration options
68
87
  */
@@ -75,6 +94,7 @@ export declare interface SeederConfig {
75
94
  except?: string[]
76
95
  includeDefaults?: boolean
77
96
  allowProtected?: boolean
97
+ append?: boolean
78
98
  }
79
99
  /**
80
100
  * Result of a single model seeding operation
package/dist/seeder.js CHANGED
@@ -12,7 +12,14 @@ export const PROTECTED_MODELS = Object.freeze([
12
12
  "OauthAccessToken",
13
13
  "OauthRefreshToken",
14
14
  "PersonalAccessToken"
15
+ ]), ACCOUNT_MODELS = Object.freeze([
16
+ "User",
17
+ "Team",
18
+ "Customer"
15
19
  ]);
20
+ export function isAccountModel(name) {
21
+ return ACCOUNT_MODELS.includes(name);
22
+ }
16
23
  export function isProtectedModel(name) {
17
24
  return PROTECTED_MODELS.includes(name);
18
25
  }
@@ -146,7 +153,7 @@ async function existingRows(table) {
146
153
  return [];
147
154
  }
148
155
  }
149
- async function relationColumns(model) {
156
+ async function relationColumns(model, options = {}) {
150
157
  const parents = parentModels(model);
151
158
  if (parents.length === 0)
152
159
  return [];
@@ -155,6 +162,8 @@ async function relationColumns(model) {
155
162
  const column = `${snakeCase(parent)}_id`;
156
163
  if (model.attributes[column] || model.attributes[parent])
157
164
  continue;
165
+ if (isAccountModel(parent) && !options.allowProtected)
166
+ continue;
158
167
  const rows = await existingRows(`${snakeCase(parent)}s`);
159
168
  if (rows.length > 0)
160
169
  pools.push({ column, rows });
@@ -182,8 +191,8 @@ export function chooseRelations(pools, count) {
182
191
  return row;
183
192
  });
184
193
  }
185
- async function generateRecords(model) {
186
- const records = [], relations = await relationColumns(model);
194
+ async function generateRecords(model, options = {}) {
195
+ const records = [], relations = await relationColumns(model, options);
187
196
  for (let i = 0;i < model.count; i++) {
188
197
  const record = await generateRecord(model.attributes, model.name, i === 0), fixture = model.fixtures[i], withRelations = { ...record, ...relations[i] ?? {} };
189
198
  records.push(fixture ? { ...withRelations, ...fixtureToColumns(fixture) } : withRelations);
@@ -209,10 +218,10 @@ async function seedModel(model, options) {
209
218
  }
210
219
  throw tableErr;
211
220
  }
212
- if (!options.fresh) {
221
+ if (!options.fresh && !options.append) {
213
222
  if (await db.selectFrom(model.table).selectAll().limit(1).executeTakeFirst()) {
214
223
  if (options.verbose)
215
- log.info(` ${model.name}: table already has rows \u2014 skipping (use --fresh to replace)`);
224
+ log.info(` ${model.name}: table already has rows \u2014 skipping (--append to add more, --fresh to replace)`);
216
225
  return {
217
226
  model: model.name,
218
227
  table: model.table,
@@ -222,7 +231,7 @@ async function seedModel(model, options) {
222
231
  };
223
232
  }
224
233
  }
225
- const records = await generateRecords(model);
234
+ const records = await generateRecords(model, options);
226
235
  if (records.length === 0)
227
236
  return {
228
237
  model: model.name,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/database",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.188",
5
+ "version": "0.70.190",
6
6
  "description": "The Stacks database integration.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -60,15 +60,15 @@
60
60
  "dynamodb-tooling": "^0.3.2"
61
61
  },
62
62
  "devDependencies": {
63
- "@stacksjs/cli": "0.70.188",
64
- "@stacksjs/config": "0.70.188",
65
- "@stacksjs/logging": "0.70.188",
66
- "@stacksjs/router": "0.70.188",
63
+ "@stacksjs/cli": "0.70.190",
64
+ "@stacksjs/config": "0.70.190",
65
+ "@stacksjs/logging": "0.70.190",
66
+ "@stacksjs/router": "0.70.190",
67
67
  "better-dx": "^0.2.17",
68
- "@stacksjs/path": "0.70.188",
69
- "@stacksjs/query-builder": "0.70.188",
70
- "@stacksjs/storage": "0.70.188",
71
- "@stacksjs/strings": "0.70.188",
72
- "@stacksjs/utils": "0.70.188"
68
+ "@stacksjs/path": "0.70.190",
69
+ "@stacksjs/query-builder": "0.70.190",
70
+ "@stacksjs/storage": "0.70.190",
71
+ "@stacksjs/strings": "0.70.190",
72
+ "@stacksjs/utils": "0.70.190"
73
73
  }
74
74
  }