@stacksjs/orm 0.72.6 → 0.72.8

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.
@@ -188,11 +188,36 @@ declare type InferenceHint<TAttribute> = TAttribute extends { type: unknown } |
188
188
  ? object
189
189
  : { type: DefaultTypeToken<TAttribute> }
190
190
  : { type: ValidationInferenceRule<ValidationRuleOf<TAttribute>> }
191
+ /**
192
+ * `required: false` is what makes the emitted column nullable, so it has to
193
+ * imply `nullable: true` for the inferred value type as well.
194
+ *
195
+ * Without this the two halves of a definition disagree. Value types come from
196
+ * the seed factory's return type, and a factory exists to produce a *useful*
197
+ * sample row, so optional columns are routinely written as
198
+ * `factory: () => new Date().toISOString()`. That inferred a bare `string`,
199
+ * which made `update({ nextPollAt: null })` a type error against a column the
200
+ * migration had already created as nullable. An explicit `nullable` on the
201
+ * attribute still wins, since it is the more specific declaration.
202
+ */
203
+ declare type IsOptionalAttribute<TAttribute> = TAttribute extends { required: false } ? true : false;
204
+ /** Covers attributes with no factory, where the validation rule drives the type. */
205
+ declare type NullabilityOf<TAttribute> = TAttribute extends { nullable: unknown }
206
+ ? object
207
+ : IsOptionalAttribute<TAttribute> extends true ? { nullable: true } : object;
208
+ /**
209
+ * Covers attributes that do have a factory, whose return type takes precedence
210
+ * over `nullable` when the value type is inferred.
211
+ */
212
+ declare type FactoryValueOf<TAttribute> = IsOptionalAttribute<TAttribute> extends true
213
+ ? FactoryReturnOf<TAttribute> | null
214
+ : FactoryReturnOf<TAttribute>;
191
215
  declare type QueryAttribute<TAttribute> = Omit<TAttribute, 'factory'>
192
216
  & InferenceHint<TAttribute>
217
+ & NullabilityOf<TAttribute>
193
218
  & ([FactoryReturnOf<TAttribute>] extends [never]
194
219
  ? object
195
- : { factory: (faker: BQBFaker) => FactoryReturnOf<TAttribute> });
220
+ : { factory: (faker: BQBFaker) => FactoryValueOf<TAttribute> });
196
221
  declare type QueryTraits<TDef extends ModelDefinition> = TDef extends { traits: infer TTraits }
197
222
  ? { traits: TTraits & NonNullable<BQBModelDefinition['traits']> }
198
223
  : { traits?: BQBModelDefinition['traits'] }
package/dist/index.d.ts CHANGED
@@ -140,6 +140,22 @@ export declare const Transaction: ReturnType<typeof lazyModel<typeof import('../
140
140
  export declare const WaitlistProduct: ReturnType<typeof lazyModel<typeof import('../../../defaults/app/Models/commerce/WaitlistProduct').default>>;
141
141
  export declare const WaitlistRestaurant: ReturnType<typeof lazyModel<typeof import('../../../defaults/app/Models/commerce/WaitlistRestaurant').default>>;
142
142
  export declare const Websocket: ReturnType<typeof lazyModel<typeof import('../../../defaults/app/Models/realtime/Websocket').default>>;
143
+ /**
144
+ * A model record seen only through `get(column)`.
145
+ *
146
+ * Normalizers, dashboard aggregators and report builders all take rows from
147
+ * more than one model and read a handful of shared columns by name. Typing
148
+ * that parameter as the model's own record ties the helper to one model;
149
+ * typing it as `{ get: (key: string) => unknown }` is WIDER than what any real
150
+ * record offers, and contravariance then makes every real record unassignable.
151
+ *
152
+ * Four copies of this interface had grown up in the dashboard scaffold - one
153
+ * each for jobs, kanban, analytics and deployments - all with the same
154
+ * hard-won `any`. This is that type, once.
155
+ */
156
+ export declare interface ReadableRecord {
157
+ get: (key: any) => unknown
158
+ }
143
159
  /**
144
160
  * Framework-default User row shape. Matches the attributes declared on
145
161
  * `storage/framework/defaults/app/Models/User.ts` plus the system
@@ -60,8 +60,16 @@ declare type AttributeValue<TAttribute> = TAttribute extends { readonly type: in
60
60
  ? TRule extends Validator<infer TValue> ? TValue : unknown
61
61
  : TAttribute extends { readonly default: infer TDefault } ? WidenDefault<TDefault>
62
62
  : unknown;
63
+ /**
64
+ * An attribute is nullable when it says so outright, or when `required: false`
65
+ * marks it optional. The latter is what makes the generated column nullable, so
66
+ * the row type has to agree with the schema the migration emits.
67
+ */
68
+ declare type IsNullableAttribute<TAttribute> = TAttribute extends { readonly nullable: true }
69
+ ? true
70
+ : TAttribute extends { readonly required: false } ? true : false;
63
71
  declare type DeclaredAttributes<TDef> = {
64
- [TKey in AttributeKeys<TDef>]: DefinitionAttributes<TDef>[TKey] extends { readonly nullable: true }
72
+ [TKey in AttributeKeys<TDef>]: IsNullableAttribute<DefinitionAttributes<TDef>[TKey]> extends true
65
73
  ? AttributeValue<DefinitionAttributes<TDef>[TKey]> | null
66
74
  : AttributeValue<DefinitionAttributes<TDef>[TKey]>
67
75
  }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/orm",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.6",
5
+ "version": "0.72.8",
6
6
  "description": "The Stacks ORM integration",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -64,12 +64,12 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@stacksjs/ts-validation": "^0.5.4",
67
- "bun-query-builder": "^0.2.39"
67
+ "bun-query-builder": "^0.2.41"
68
68
  },
69
69
  "devDependencies": {
70
- "@stacksjs/config": "0.72.6",
70
+ "@stacksjs/config": "0.72.8",
71
71
  "better-dx": "^0.2.23",
72
- "@stacksjs/query-builder": "0.72.6",
73
- "@stacksjs/types": "0.72.6"
72
+ "@stacksjs/query-builder": "0.72.8",
73
+ "@stacksjs/types": "0.72.8"
74
74
  }
75
75
  }