Skip to content

Commit ee5360e

Browse files
committed
fix: Cut table TS errors in half
1 parent caebdc4 commit ee5360e

File tree

2 files changed

+37
-42
lines changed

2 files changed

+37
-42
lines changed

resources/ResourceInterface.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,11 +214,15 @@ export interface SubSelect {
214214
}
215215
export type Select = (string | SubSelect)[];
216216

217-
export interface SubscriptionRequest extends RequestTarget {
218-
/** The starting time of events to return (defaults to now) */
217+
export interface SubscriptionRequest extends Partial<RequestTarget> {
218+
/** The starting time of events to return (now is the default) */
219219
startTime?: number;
220220
/** The count of previously recorded events to return */
221221
previousCount?: number;
222+
/** Indicates that all threads are (presumably) making this subscription and we do not need to propagate events across threads (more efficient) */
223+
crossThreads?: boolean;
224+
/** Indicates that we want, if possible, immediate notification of writes within the process (not supported yet) */
225+
inTransactionUpdates?: boolean;
222226
/** If the current record state should be omitted as the first event */
223227
omitCurrent?: boolean;
224228
onlyChildren?: boolean;

resources/Table.ts

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ export function makeTable(options): TableStaticInterface {
126126
const updateRecord = recordUpdater(primaryStore, tableId, auditStore);
127127
let sourceLoad: any; // if a source has a load function (replicator), record it here
128128
let hasSourceGet: any;
129-
let primaryKeyAttribute: Attribute = {};
129+
let primaryKeyAttribute: Attribute | null = null;
130130
let lastEvictionCompletion: Promise<void> = Promise.resolve();
131131
let createdTimeProperty: Attribute, updatedTimeProperty: Attribute, expiresAtProperty: Attribute;
132132
for (const attribute of attributes) {
@@ -188,6 +188,8 @@ export function makeTable(options): TableStaticInterface {
188188
}
189189
}
190190
class TableResource<Record extends object = any> extends Resource<Record> implements TableInterface<Record> {
191+
['constructor']: typeof TableResource;
192+
191193
#record: any; // the stored/frozen record from the database and stored in the cache (should not be modified directly)
192194
#changes: any; // the changes to the record that have been made (should not be modified directly)
193195
#version?: number; // version of the record
@@ -230,10 +232,7 @@ export function makeTable(options): TableStaticInterface {
230232
* @param options
231233
* @returns
232234
*/
233-
static sourcedFrom<Record extends object = any>(
234-
source: TableInterface<Record> & TableStaticInterface<Record>,
235-
options?: ExpirationOptions & IntermediateSourceOptions
236-
) {
235+
static sourcedFrom(source: typeof TableResource, options?: ExpirationOptions & IntermediateSourceOptions) {
237236
// define a source for retrieving invalidated entries for caching purposes
238237
if (options) {
239238
this.sourceOptions = options;
@@ -253,7 +252,7 @@ export function makeTable(options): TableStaticInterface {
253252
this.source = source;
254253
}
255254
hasSourceGet = hasSourceGet || (source.get && (!source.get.reliesOnPrototype || source.prototype.get));
256-
sourceLoad = sourceLoad || source.load;
255+
sourceLoad = sourceLoad || (source as any).load;
257256
const shouldRevalidateEvents = this.source?.shouldRevalidateEvents;
258257

259258
// External data source may provide a subscribe method, allowing for real-time proactive delivery
@@ -268,7 +267,7 @@ export function makeTable(options): TableStaticInterface {
268267
// perform the write of an individual write event
269268
const writeUpdate = async (event, context) => {
270269
const value = event.value;
271-
const Table = event.table ? databases[databaseName][event.table] : TableResource;
270+
const Table = (event.table ? databases[databaseName][event.table] : TableResource) as typeof TableResource;
272271
if (
273272
databaseName === SYSTEM_SCHEMA_NAME &&
274273
(event.table === SYSTEM_TABLE_NAMES.ROLE_TABLE_NAME || event.table === SYSTEM_TABLE_NAMES.USER_TABLE_NAME)
@@ -289,7 +288,7 @@ export function makeTable(options): TableStaticInterface {
289288
async: true,
290289
};
291290
const id = event.id;
292-
const resource: TableResource = await Table.getResource(id, context, options);
291+
const resource = await Table.getResource(id, context, options);
293292
if (event.finished) await event.finished;
294293
switch (event.type) {
295294
case 'put':
@@ -318,16 +317,10 @@ export function makeTable(options): TableStaticInterface {
318317
const hasSubscribe = source.subscribe;
319318
// if subscriptions come in out-of-order, we need to track deletes to ensure consistency
320319
if (hasSubscribe && trackDeletes == undefined) trackDeletes = true;
321-
const subscriptionOptions = {
322-
// this is used to indicate that all threads are (presumably) making this subscription
323-
// and we do not need to propagate events across threads (more efficient)
320+
const subscriptionOptions: SubscriptionRequest = {
324321
crossThreads: false,
325-
// this is used to indicate that we want, if possible, immediate notification of writes
326-
// within the process (not supported yet)
327322
inTransactionUpdates: true,
328-
// supports transaction operations
329323
supportsTransactions: true,
330-
// don't need the current state, should be up-to-date
331324
omitCurrent: true,
332325
};
333326
const subscribeOnThisThread = source.subscribeOnThisThread
@@ -523,11 +516,7 @@ export function makeTable(options): TableStaticInterface {
523516
}
524517
return resource;
525518
}
526-
_loadRecord<Record extends object = any>(
527-
target: RequestTarget,
528-
request: Context,
529-
resourceOptions?: any
530-
): MaybePromise<TableResource<Record>> {
519+
_loadRecord(target: RequestTarget, request: Context, resourceOptions?: any): MaybePromise<TableResource<Record>> {
531520
const id = target && typeof target === 'object' ? target.id : target;
532521
if (id == null) return this;
533522
checkValidId(id);
@@ -907,17 +896,18 @@ export function makeTable(options): TableStaticInterface {
907896
* This retrieves the data of this resource.
908897
* @param target - If included, is an identifier/query that specifies the requested target to retrieve and query
909898
*/
910-
get(target: RequestTargetOrId): Record | AsyncIterable<Record> | Promise<Record | AsyncIterable<Record>>;
899+
get(target: RequestTargetOrId): AsyncIterable<Record> | Promise<Record>;
911900
get(
912-
target?: RequestTargetOrId
901+
targetOrId?: RequestTargetOrId
913902
): TableResource<Record> | undefined | Record | AsyncIterable<Record> | Promise<Record | AsyncIterable<Record>> {
914-
const constructor: Resource = this.constructor;
915-
if (typeof target === 'string' && constructor.loadAsInstance !== false) return this.getProperty(target);
916-
if (isSearchTarget(target)) {
903+
const constructor = this.constructor;
904+
if (typeof targetOrId === 'string' && constructor.loadAsInstance !== false) return this.getProperty(targetOrId);
905+
if (isSearchTarget(targetOrId)) {
917906
// go back to the static search method so it gets a chance to override
918-
return constructor.search(target, this.getContext());
907+
return constructor.search(targetOrId, this.getContext());
919908
}
920-
if (target && target.id === undefined && !target.toString()) {
909+
const target = targetOrId as unknown as RequestTarget | undefined;
910+
if (target?.id === undefined && !target.toString()) {
921911
const description = {
922912
// basically a describe call
923913
records: './', // an href to the records themselves
@@ -1009,7 +999,7 @@ export function makeTable(options): TableStaticInterface {
1009999
/**
10101000
* Determine if the user is allowed to get/read data from the current resource
10111001
*/
1012-
allowRead(user: User, target: RequestTarget, context: Context): boolean {
1002+
allowRead(user: User, target: Pick<RequestTarget, 'select' | 'checkPermission'>, context: Context): boolean {
10131003
const tablePermission = getTablePermissions(user, target);
10141004
if (tablePermission?.read) {
10151005
if (tablePermission.isSuperUser) return true;
@@ -1300,15 +1290,13 @@ export function makeTable(options): TableStaticInterface {
13001290
const context = this.getContext();
13011291
checkValidId(id);
13021292
const transaction = txnForContext(this.getContext());
1293+
const source: any = this.constructor.source;
13031294
transaction.addWrite({
13041295
key: id,
13051296
store: primaryStore,
13061297
invalidated: true,
13071298
entry: this.#entry,
1308-
before:
1309-
this.constructor.source?.relocate && !context?.source
1310-
? this.constructor.source.relocate.bind(this.constructor.source, id, undefined, context)
1311-
: undefined,
1299+
before: source?.relocate && !context?.source ? source.relocate.bind(source, id, undefined, context) : undefined,
13121300
commit: (txnTime, existingEntry, _retry, transaction: any) => {
13131301
if (precedesExistingVersion(txnTime, existingEntry, options?.nodeId) <= 0) return;
13141302
const residency = TableResource.getResidencyRecord(options.residencyId);
@@ -1885,7 +1873,7 @@ export function makeTable(options): TableStaticInterface {
18851873
if (target) {
18861874
let allowed = true;
18871875
const context = this.getContext();
1888-
if (target.checkPermission) {
1876+
if ((target as RequestTarget).checkPermission) {
18891877
// requesting authorization verification
18901878
allowed = this.allowDelete(context.user, target, context);
18911879
}
@@ -3546,8 +3534,11 @@ export function makeTable(options): TableStaticInterface {
35463534
if (length > MAX_KEY_BYTES) throw new Error('Primary key size is too large: ' + id.length);
35473535
return true;
35483536
}
3549-
function requestTargetToId(target: RequestTargetOrId): Id {
3550-
return typeof target === 'object' && target ? target.id : (target as Id);
3537+
function requestTargetToId(target: Partial<RequestTargetOrId>): Id {
3538+
return typeof target === 'object' && target ? (target as RequestTarget).id : (target as Id);
3539+
}
3540+
function isId(target: RequestTargetOrId): target is Id {
3541+
return target !== undefined && typeof target !== 'object';
35513542
}
35523543
function isSearchTarget(target: RequestTargetOrId): target is RequestTarget {
35533544
return typeof target === 'object' && target && (target as RequestTarget).isCollection;
@@ -3688,7 +3679,7 @@ export function makeTable(options): TableStaticInterface {
36883679
}
36893680
});
36903681
}
3691-
function getTablePermissions(user: User, target?: RequestTarget) {
3682+
function getTablePermissions(user: User, target?: Pick<RequestTarget, 'checkPermission'>) {
36923683
let permission = target?.checkPermission; // first check to see the request target specifically provides the permissions to authorize
36933684
if (typeof permission !== 'object') {
36943685
if (!user?.role) return;
@@ -4165,12 +4156,12 @@ export function makeTable(options): TableStaticInterface {
41654156
* Verify that the context does not have any replication parameters that are not allowed
41664157
* @param context
41674158
*/
4168-
function checkContextPermissions(context: Context): boolean {
4159+
function checkContextPermissions(context: Context | SourceContext): boolean {
41694160
if (!context) return true;
4170-
if (context.user?.role?.permission?.super_user) return true;
4171-
if (context.replicateTo)
4161+
if ((context as Context).user?.role?.permission?.super_user) return true;
4162+
if ((context as Context).replicateTo)
41724163
throw new ClientError('Can not specify replication parameters without super user permissions', 403);
4173-
if (context.replicatedConfirmation)
4164+
if ((context as Context).replicatedConfirmation)
41744165
throw new ClientError('Can not specify replication confirmation without super user permissions', 403);
41754166
return true;
41764167
}

0 commit comments

Comments
 (0)