@stacksjs/orm 0.75.37 → 0.75.40

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.
@@ -50,7 +50,7 @@ export declare function withoutValidation<T>(fn: () => T | Promise<T>): Promise<
50
50
  * decides for itself how many queries that costs; without it this falls back to
51
51
  * projecting each row, which is what a column-rearranging `shape` wants anyway.
52
52
  */
53
- export declare function projectDocumentsFromTrait(config: SearchableTraitConfig): Promise<Record<string, unknown>[]>;
53
+ export declare function projectDocumentsFromTrait(models: Record<string, unknown>[], config: SearchableTraitConfig): Promise<Record<string, unknown>[]>;
54
54
  export declare function defineModel<const TDef extends ModelDefinition>(definition: TDef): StacksModelStatic<TDef>;
55
55
  /**
56
56
  * Normalize a ModelInstance (or array of them, or already-plain row) into
@@ -211,7 +211,12 @@ declare type MutableModelDefinition = Omit<ModelDefinition, 'set'> & {
211
211
  }
212
212
  declare type BQBModelAttribute = BQBModelDefinition['attributes'][string];
213
213
  export type StacksModelAttribute = Omit<BQBModelAttribute, 'factory'> & {
214
- factory?: (faker: Faker) => unknown
214
+ /**
215
+ * Fake value for seeding. Receives the attributes this record's factories
216
+ * have already produced (those declared above it, by attribute name), so a
217
+ * value can depend on another: `(faker, { discountType }) => ...`.
218
+ */
219
+ factory?: (faker: Faker, attributes: Readonly<Record<string, unknown>>) => unknown
215
220
  }
216
221
  declare type ModelDefinition = StacksModelDefinition;
217
222
  declare type ValidationRuleOf<TAttribute> = TAttribute extends { validation: { rule: infer TRule } } ? TRule : never;
@@ -267,13 +267,17 @@ export default defineModel({
267
267
  factory: faker => faker.number.float({ min: 0.5, max: 8, fractionDigits: 1 }),
268
268
  },
269
269
 
270
+ // Integer minor units of `currency`, like every money column (1999 is
271
+ // $19.99). The columns are INTEGER; a decimal here was stored as a REAL by
272
+ // SQLite and truncated by MySQL and Postgres.
270
273
  budget: {
271
274
  required: false,
272
275
  fillable: true,
273
276
  validation: {
274
- rule: schema.number().min(0),
277
+ rule: schema.number().integer().min(0),
275
278
  },
276
- factory: faker => faker.number.float({ min: 100, max: 10000, fractionDigits: 2 }),
279
+ // $100 to $10,000.
280
+ factory: faker => faker.number.int({ min: 10000, max: 1000000 }),
277
281
  },
278
282
 
279
283
  spent: {
@@ -281,9 +285,10 @@ export default defineModel({
281
285
  fillable: true,
282
286
  default: 0,
283
287
  validation: {
284
- rule: schema.number().min(0),
288
+ rule: schema.number().integer().min(0),
285
289
  },
286
- factory: faker => faker.number.float({ min: 0, max: 5000, fractionDigits: 2 }),
290
+ // Within the budget drawn above, so a seeded campaign is never over it.
291
+ factory: (faker, { budget }) => faker.number.int({ min: 0, max: Number(budget) || 0 }),
287
292
  },
288
293
 
289
294
  currency: {
@@ -65,7 +65,8 @@ export default defineModel({
65
65
  validation: {
66
66
  rule: schema.number().min(0),
67
67
  },
68
- factory: faker => faker.number.int({ min: 0, max: 1000 }),
68
+ // Integer minor units, like every commerce amount: 1999 is $19.99.
69
+ factory: faker => faker.number.int({ min: 1000, max: 20000 }),
69
70
  },
70
71
 
71
72
  taxAmount: {
@@ -75,7 +76,7 @@ export default defineModel({
75
76
  validation: {
76
77
  rule: schema.number().min(0),
77
78
  },
78
- factory: faker => faker.number.int({ min: 0, max: 200 }),
79
+ factory: faker => faker.number.int({ min: 0, max: 1500 }),
79
80
  },
80
81
 
81
82
  discountAmount: {
@@ -85,7 +86,7 @@ export default defineModel({
85
86
  validation: {
86
87
  rule: schema.number().min(0),
87
88
  },
88
- factory: faker => faker.number.int({ min: 0, max: 100 }),
89
+ factory: faker => faker.number.int({ min: 0, max: 1000 }),
89
90
  },
90
91
 
91
92
  total: {
@@ -95,7 +96,7 @@ export default defineModel({
95
96
  validation: {
96
97
  rule: schema.number().min(0),
97
98
  },
98
- factory: faker => faker.number.int({ min: 0, max: 1200 }),
99
+ factory: faker => faker.number.int({ min: 1000, max: 21500 }),
99
100
  },
100
101
 
101
102
  expiresAt: {
@@ -52,7 +52,8 @@ export default defineModel({
52
52
  validation: {
53
53
  rule: schema.number().required().min(0),
54
54
  },
55
- factory: faker => faker.number.int({ min: 1, max: 1000 }),
55
+ // Integer minor units, in the same range as Product.price.
56
+ factory: faker => faker.number.int({ min: 100, max: 10000 }),
56
57
  },
57
58
 
58
59
  totalPrice: {
@@ -61,7 +62,7 @@ export default defineModel({
61
62
  validation: {
62
63
  rule: schema.number().required().min(0),
63
64
  },
64
- factory: faker => faker.number.int({ min: 1, max: 1000 }),
65
+ factory: faker => faker.number.int({ min: 100, max: 50000 }),
65
66
  },
66
67
 
67
68
  taxRate: {
@@ -79,7 +80,7 @@ export default defineModel({
79
80
  validation: {
80
81
  rule: schema.number().min(0),
81
82
  },
82
- factory: faker => faker.number.int({ min: 0, max: 50 }),
83
+ factory: faker => faker.number.int({ min: 0, max: 1000 }),
83
84
  },
84
85
 
85
86
  discountPercentage: {
@@ -97,7 +98,8 @@ export default defineModel({
97
98
  validation: {
98
99
  rule: schema.number().min(0),
99
100
  },
100
- factory: faker => faker.number.int({ min: 0, max: 25 }),
101
+ // At most $1.00, so it never exceeds the smallest unit price above.
102
+ factory: faker => faker.number.int({ min: 0, max: 100 }),
101
103
  },
102
104
 
103
105
  productName: {
@@ -106,7 +106,11 @@ export default defineModel({
106
106
  min: 'Discount value must be greater than 0.01',
107
107
  },
108
108
  },
109
- factory: faker => faker.number.int({ min: 5, max: 50 }),
109
+ // A percentage stays a plain number; a fixed amount is integer minor units
110
+ // ($5 to $50). discountType is declared above, so the seeder has drawn it.
111
+ factory: (faker, { discountType }) => discountType === 'fixed_amount'
112
+ ? faker.helpers.arrayElement([500, 1000, 1500, 2000, 2500, 5000])
113
+ : faker.number.int({ min: 5, max: 50 }),
110
114
  },
111
115
 
112
116
  minOrderAmount: {
@@ -118,7 +122,8 @@ export default defineModel({
118
122
  min: 'Min order amount must be greater than 0',
119
123
  },
120
124
  },
121
- factory: faker => faker.number.int({ min: 0, max: 50 }),
125
+ // Integer minor units: no minimum, or $25 to $100.
126
+ factory: faker => faker.helpers.arrayElement([0, 2500, 5000, 7500, 10000]),
122
127
  },
123
128
 
124
129
  maxDiscountAmount: {
@@ -130,7 +135,8 @@ export default defineModel({
130
135
  min: 'Max discount amount must be greater than 0',
131
136
  },
132
137
  },
133
- factory: faker => faker.number.int({ min: 5, max: 100 }),
138
+ // Integer minor units: $10 to $100.
139
+ factory: faker => faker.number.int({ min: 1000, max: 10000 }),
134
140
  },
135
141
 
136
142
  freeProductId: {
@@ -82,7 +82,8 @@ export default defineModel({
82
82
  min: 'Total spent cannot be negative',
83
83
  },
84
84
  },
85
- factory: faker => faker.number.int({ min: 0, max: 2000 }),
85
+ // Integer minor units: $0 to $5,000.
86
+ factory: faker => faker.number.int({ min: 0, max: 500000 }),
86
87
  },
87
88
 
88
89
  lastOrder: {
@@ -57,7 +57,8 @@ export default defineModel({
57
57
  validation: {
58
58
  rule: schema.number().required().min(1),
59
59
  },
60
- factory: faker => faker.number.int({ min: 100, max: 2000 }),
60
+ // Integer minor units, in the denominations cards are actually sold in: $25 to $250.
61
+ factory: faker => faker.helpers.arrayElement([2500, 5000, 10000, 15000, 20000, 25000]),
61
62
  },
62
63
 
63
64
  currentBalance: {
@@ -66,7 +67,9 @@ export default defineModel({
66
67
  validation: {
67
68
  rule: schema.number().required().min(0),
68
69
  },
69
- factory: () => 1,
70
+ // Drawn below the smallest initial balance above, so a seeded card never
71
+ // holds more than it was issued with.
72
+ factory: faker => faker.number.int({ min: 0, max: 2500 }),
70
73
  },
71
74
 
72
75
  currency: {
@@ -64,7 +64,8 @@ export default defineModel({
64
64
  validation: {
65
65
  rule: schema.number().required().min(0),
66
66
  },
67
- factory: faker => faker.number.int({ min: 100, max: 2000 }),
67
+ // Integer minor units, like every commerce amount: 1999 is $19.99.
68
+ factory: faker => faker.number.int({ min: 1000, max: 50000 }),
68
69
  },
69
70
 
70
71
  currency: {
@@ -84,7 +85,7 @@ export default defineModel({
84
85
  validation: {
85
86
  rule: schema.number().min(0),
86
87
  },
87
- factory: faker => faker.number.int({ min: 10, max: 200 }),
88
+ factory: faker => faker.number.int({ min: 0, max: 4000 }),
88
89
  },
89
90
 
90
91
  discountAmount: {
@@ -94,7 +95,7 @@ export default defineModel({
94
95
  validation: {
95
96
  rule: schema.number().min(0),
96
97
  },
97
- factory: faker => faker.number.int({ min: 0, max: 150 }),
98
+ factory: faker => faker.number.int({ min: 0, max: 2000 }),
98
99
  },
99
100
 
100
101
  deliveryFee: {
@@ -104,7 +105,7 @@ export default defineModel({
104
105
  validation: {
105
106
  rule: schema.number().min(0),
106
107
  },
107
- factory: faker => faker.number.int({ min: 0, max: 100 }),
108
+ factory: faker => faker.helpers.arrayElement([0, 299, 499, 799]),
108
109
  },
109
110
 
110
111
  tipAmount: {
@@ -114,7 +115,7 @@ export default defineModel({
114
115
  validation: {
115
116
  rule: schema.number().min(0),
116
117
  },
117
- factory: faker => faker.number.int({ min: 0, max: 200 }),
118
+ factory: faker => faker.number.int({ min: 0, max: 1500 }),
118
119
  },
119
120
 
120
121
  orderType: {
@@ -36,7 +36,8 @@ export default defineModel({
36
36
  min: 'Price cannot be negative',
37
37
  },
38
38
  },
39
- factory: faker => faker.number.int({ min: 5, max: 50 }),
39
+ // Integer minor units, in the same range as Product.price.
40
+ factory: faker => faker.number.int({ min: 100, max: 10000 }),
40
41
  },
41
42
 
42
43
  special_instructions: {
@@ -13,14 +13,22 @@ export default defineModel({
13
13
  // tell "considered" from "nobody thought about it" (stacksjs/stacks#2375).
14
14
  ownership: false,
15
15
 
16
+ // A SKU identifies a variant within its product. Unique per product rather
17
+ // than globally, because two imported stores (or two products of one) can
18
+ // legitimately reuse a code. NULLs never collide, so variants without a SKU
19
+ // are unconstrained on every dialect.
20
+ indexes: [
21
+ { name: 'product_variants_product_sku_unique', columns: ['product_id', 'sku'], unique: true },
22
+ ],
23
+
16
24
  traits: {
17
25
  useUuid: true,
18
26
  useTimestamps: true,
19
27
  useSearch: {
20
- displayable: ['id', 'productId', 'variant', 'type', 'description', 'options', 'status'],
21
- searchable: ['variant', 'type', 'description', 'options'],
22
- sortable: ['createdAt', 'updatedAt', 'variant', 'type', 'status'],
23
- filterable: ['productId', 'type', 'status'],
28
+ displayable: ['id', 'productId', 'variant', 'type', 'sku', 'price', 'compareAtPrice', 'inventoryCount', 'description', 'options', 'status'],
29
+ searchable: ['variant', 'type', 'sku', 'description', 'options'],
30
+ sortable: ['createdAt', 'updatedAt', 'variant', 'type', 'status', 'price', 'inventoryCount'],
31
+ filterable: ['productId', 'type', 'status', 'sku'],
24
32
  },
25
33
 
26
34
  useSeeder: {
@@ -109,6 +117,65 @@ export default defineModel({
109
117
  },
110
118
  factory: faker => faker.helpers.arrayElement(['active', 'inactive', 'draft']),
111
119
  },
120
+
121
+ sku: {
122
+ order: 8,
123
+ fillable: true,
124
+ nullable: true,
125
+ validation: {
126
+ rule: schema.string().max(100),
127
+ message: {
128
+ max: 'SKU must have a maximum of 100 characters',
129
+ },
130
+ },
131
+ factory: faker => faker.string.alphanumeric(10).toUpperCase(),
132
+ },
133
+
134
+ // Money is integer minor units (cents), never a float. NULL means the
135
+ // variant has no price of its own and inherits `products.price`.
136
+ price: {
137
+ order: 9,
138
+ fillable: true,
139
+ nullable: true,
140
+ validation: {
141
+ rule: schema.number().integer().min(0),
142
+ message: {
143
+ min: 'Price must be at least 0',
144
+ },
145
+ },
146
+ factory: faker => faker.number.int({ min: 100, max: 10000 }),
147
+ },
148
+
149
+ // The "was" price shown struck through, in minor units. NULL when the
150
+ // variant is not on sale.
151
+ compareAtPrice: {
152
+ order: 10,
153
+ fillable: true,
154
+ nullable: true,
155
+ validation: {
156
+ rule: schema.number().integer().min(0),
157
+ message: {
158
+ min: 'Compare-at price must be at least 0',
159
+ },
160
+ },
161
+ // Above the factory's highest `price`, so a seeded sale is always a discount.
162
+ factory: faker => faker.datatype.boolean() ? faker.number.int({ min: 10001, max: 20000 }) : null,
163
+ },
164
+
165
+ // Units in stock. NULL means stock is not tracked for this variant,
166
+ // which is different from 0 (tracked and sold out).
167
+ inventoryCount: {
168
+ order: 11,
169
+ fillable: true,
170
+ nullable: true,
171
+ validation: {
172
+ rule: schema.number().integer().min(0),
173
+ message: {
174
+ min: 'Inventory count must be at least 0',
175
+ },
176
+ },
177
+ factory: faker => faker.number.int({ min: 0, max: 100 }),
178
+ },
112
179
  },
113
180
 
114
181
  dashboard: {
@@ -41,9 +41,10 @@ export default defineModel({
41
41
  order: 2,
42
42
  fillable: true,
43
43
  validation: {
44
- rule: schema.number().required().min(0.01),
44
+ // Integer minor units: the smallest amount is one cent, not 0.01 of one.
45
+ rule: schema.number().integer().required().min(1),
45
46
  },
46
- factory: faker => faker.number.int({ min: 5, max: 500 }),
47
+ factory: faker => faker.number.int({ min: 500, max: 50000 }),
47
48
  },
48
49
 
49
50
  status: {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/orm",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.37",
5
+ "version": "0.75.40",
6
6
  "description": "The Stacks ORM integration",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -63,31 +63,31 @@
63
63
  "prepublishOnly": "bun run build"
64
64
  },
65
65
  "dependencies": {
66
- "@stacksjs/cache": "0.75.37",
67
- "@stacksjs/cli": "0.75.37",
68
- "@stacksjs/config": "0.75.37",
69
- "@stacksjs/database": "0.75.37",
70
- "@stacksjs/env": "0.75.37",
71
- "@stacksjs/error-handling": "0.75.37",
72
- "@stacksjs/events": "0.75.37",
73
- "@stacksjs/logging": "0.75.37",
74
- "@stacksjs/model-meta": "0.75.37",
75
- "@stacksjs/pagination": "0.75.37",
76
- "@stacksjs/path": "0.75.37",
77
- "@stacksjs/query-builder": "0.75.37",
78
- "@stacksjs/realtime": "0.75.37",
79
- "@stacksjs/router": "0.75.37",
80
- "@stacksjs/storage": "0.75.37",
81
- "@stacksjs/strings": "0.75.37",
66
+ "@stacksjs/cache": "0.75.40",
67
+ "@stacksjs/cli": "0.75.40",
68
+ "@stacksjs/config": "0.75.40",
69
+ "@stacksjs/database": "0.75.40",
70
+ "@stacksjs/env": "0.75.40",
71
+ "@stacksjs/error-handling": "0.75.40",
72
+ "@stacksjs/events": "0.75.40",
73
+ "@stacksjs/logging": "0.75.40",
74
+ "@stacksjs/model-meta": "0.75.40",
75
+ "@stacksjs/pagination": "0.75.40",
76
+ "@stacksjs/path": "0.75.40",
77
+ "@stacksjs/query-builder": "0.75.40",
78
+ "@stacksjs/realtime": "0.75.40",
79
+ "@stacksjs/router": "0.75.40",
80
+ "@stacksjs/storage": "0.75.40",
81
+ "@stacksjs/strings": "0.75.40",
82
82
  "@stacksjs/ts-validation": "^0.5.6",
83
- "@stacksjs/validation": "0.75.37",
84
- "bun-query-builder": "^0.3.0"
83
+ "@stacksjs/validation": "0.75.40",
84
+ "bun-query-builder": "^0.3.4"
85
85
  },
86
86
  "peerDependencies": {
87
- "@stacksjs/auth": "0.75.37",
88
- "@stacksjs/payments": "0.75.37",
89
- "@stacksjs/queue": "0.75.37",
90
- "@stacksjs/search-engine": "0.75.37",
87
+ "@stacksjs/auth": "0.75.40",
88
+ "@stacksjs/payments": "0.75.40",
89
+ "@stacksjs/queue": "0.75.40",
90
+ "@stacksjs/search-engine": "0.75.40",
91
91
  "stripe": "22.3.2"
92
92
  },
93
93
  "peerDependenciesMeta": {
@@ -108,7 +108,7 @@
108
108
  }
109
109
  },
110
110
  "devDependencies": {
111
- "@stacksjs/types": "0.75.37",
111
+ "@stacksjs/types": "0.75.40",
112
112
  "better-dx": "^0.2.24",
113
113
  "stripe": "22.3.2"
114
114
  }