Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: remove resolvers, remove promise in withBeginTransaction, simplify code calling withBeginTransaction #1212

Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
941810e
Change resolvers
danieljbruce Nov 29, 2023
4c8a4c5
Add a wrapWithBeginTransaction function for get
danieljbruce Nov 29, 2023
1f533d4
Use wrapWithBeginTransaction in more places
danieljbruce Nov 29, 2023
9ff6166
Add callbackWithError function
danieljbruce Nov 29, 2023
7f9147f
Add return type to callbackWithError
danieljbruce Nov 29, 2023
423b530
Delete code that is not used
danieljbruce Nov 29, 2023
dfc5998
There is no need to define a separate type
danieljbruce Nov 29, 2023
267205c
TODO no longer applies
danieljbruce Nov 29, 2023
ddbd200
Remove TODO
danieljbruce Nov 29, 2023
712d3e8
Inline the error type
danieljbruce Nov 30, 2023
015c3d4
Add a comment for callbackWithError
danieljbruce Nov 30, 2023
d598ec6
Added comments to document sendUserCallbackData
danieljbruce Nov 30, 2023
8312310
Move function
danieljbruce Nov 30, 2023
665192e
Do not define a commit type only used once
danieljbruce Nov 30, 2023
19b7d5e
Replace the type in the comment with Function
danieljbruce Nov 30, 2023
3c69ffa
Just use function type for the callback
danieljbruce Nov 30, 2023
08bf1f3
Remove withBeginTransaction
danieljbruce Dec 7, 2023
2714f7c
Simplify code usage of withBeginTransaction
danieljbruce Dec 7, 2023
908995b
function should not have any arguments
danieljbruce Dec 7, 2023
039394e
Remove generic Args parameter
danieljbruce Dec 7, 2023
34c92b9
Remove TODOs that are not relevant anymore.
danieljbruce Dec 7, 2023
fde0db4
Rename to withBeginTransaction
danieljbruce Dec 11, 2023
7047a32
Update comments for withBeginTransaction
danieljbruce Dec 11, 2023
d48633c
Simplify diff
danieljbruce Dec 11, 2023
b32ec8d
Remove error as null
danieljbruce Dec 11, 2023
edc9df2
withBeginTransaction
danieljbruce Dec 11, 2023
d45838e
Add a comment to indicate error
danieljbruce Jan 2, 2024
111a236
Rename method to beginTxAsync
danieljbruce Jan 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 59 additions & 89 deletions src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,6 @@ import {
} from './request';
import {AggregateQuery} from './aggregate';
import {Mutex} from 'async-mutex';
import MutexInterface from 'async-mutex/lib/MutexInterface';

type RunQueryResponseOptional = [
Entity[] | undefined,
RunQueryInfo | undefined,
];

/**
* This type matches data typically passed into a callback the user supplies.
Expand Down Expand Up @@ -200,52 +194,15 @@ class Transaction extends DatastoreRequest {
: () => {};
const gaxOptions =
typeof gaxOptionsOrCallback === 'object' ? gaxOptionsOrCallback : {};
const resolver: Resolver<google.datastore.v1.ICommitResponse> = resolve => {
this.#runCommit(
gaxOptions,
(err?: Error | null, resp?: google.datastore.v1.ICommitResponse) => {
resolve({err, resp});
}
);
};
this.#withBeginTransaction(gaxOptions, resolver).then(
(response: UserCallbackData<google.datastore.v1.ICommitResponse>) => {
callback(response.err, response.resp);
}
this.#withBeginTransaction(
gaxOptions,
() => {
this.#runCommit(gaxOptions, callback);
},
callback
);
}

/**
* If the transaction has not begun yet then this function ensures the transaction
* has started before running the resolver provided. The resolver is a function with one
* argument. This argument is a function that is used to pass errors and
* response data back to the caller of the withBeginTransaction function.
*
* @param {CallOptions | undefined} [gaxOptions]
* @param {Resolver<T>} [resolver]
* @returns {Promise<UserCallbackData<T>>} Returns a promise that will run
* this code and resolve to an error or resolve with the data from the resolver.
* @private
*/
async #withBeginTransaction<T>(
gaxOptions: CallOptions | undefined,
resolver: Resolver<T>
): Promise<UserCallbackData<T>> {
if (this.#state === TransactionState.NOT_STARTED) {
try {
await this.#mutex.runExclusive(async () => {
if (this.#state === TransactionState.NOT_STARTED) {
const runResults = await this.#runAsync({gaxOptions});
this.#parseRunSuccess(runResults);
}
});
} catch (err: any) {
return {err};
}
}
return await new Promise(resolver);
}

/**
* Create a query for the specified kind. See {module:datastore/query} for all
* of the available methods.
Expand Down Expand Up @@ -413,15 +370,12 @@ class Transaction extends DatastoreRequest {
: {};
const callback =
typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
const resolver: Resolver<GetResponse> = resolve => {
super.get(keys, options, (err?: Error | null, resp?: GetResponse) => {
resolve({err, resp});
});
};
this.#withBeginTransaction(options.gaxOptions, resolver).then(
(response: UserCallbackData<GetResponse>) => {
callback(response.err, response.resp);
}
this.#withBeginTransaction(
options.gaxOptions,
() => {
super.get(keys, options, callback);
},
callback
);
}

Expand Down Expand Up @@ -829,20 +783,12 @@ class Transaction extends DatastoreRequest {
: {};
const callback =
typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
const resolver: Resolver<any> = resolve => {
super.runAggregationQuery(
query,
options,
(err?: Error | null, resp?: any) => {
resolve({err, resp});
}
);
};
this.#withBeginTransaction(options.gaxOptions, resolver).then(
(response: UserCallbackData<UserCallbackData<any>>) => {
const error = response.err ? response.err : null;
callback(error, response.resp);
}
this.#withBeginTransaction(
options.gaxOptions,
() => {
super.runAggregationQuery(query, options, callback);
},
callback
);
}

Expand Down Expand Up @@ -875,22 +821,12 @@ class Transaction extends DatastoreRequest {
: {};
const callback =
typeof optionsOrCallback === 'function' ? optionsOrCallback : cb!;
const resolver: Resolver<RunQueryResponseOptional> = resolve => {
super.runQuery(
query,
options,
(err: Error | null, entities?: Entity[], info?: RunQueryInfo) => {
resolve({err, resp: [entities, info]});
}
);
};
this.#withBeginTransaction(options.gaxOptions, resolver).then(
(response: UserCallbackData<RunQueryResponseOptional>) => {
const error = response.err ? response.err : null;
const entities = response.resp ? response.resp[0] : undefined;
const info = response.resp ? response.resp[1] : undefined;
callback(error, entities, info);
}
this.#withBeginTransaction(
options.gaxOptions,
() => {
super.runQuery(query, options, callback);
},
callback
);
}

Expand Down Expand Up @@ -1084,6 +1020,41 @@ class Transaction extends DatastoreRequest {

this.save(entities);
}

/**
* If the transaction has not begun yet then this function ensures the transaction
* has started before running the function provided as a parameter.
*
* @param {CallOptions | undefined} [gaxOptions] Gax options provided by the
* user that are used for the beginTransaction grpc call.
* @param {function} [fn] A function which is run after ensuring a
* beginTransaction call is made.
* @param {function} [callback] A callback provided by the user that expects
* an error in the first argument and a custom data type for the rest of the
* arguments.
* @private
*/
#withBeginTransaction<T extends any[]>(
gaxOptions: CallOptions | undefined,
fn: () => void,
callback: (...args: [Error | null, ...T] | [Error | null]) => void
): void {
(async () => {
if (this.#state === TransactionState.NOT_STARTED) {
try {
await this.#mutex.runExclusive(async () => {
if (this.#state === TransactionState.NOT_STARTED) {
const runResults = await this.#runAsync({gaxOptions});
Copy link

@daniel-sanche daniel-sanche Dec 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it looks like runAsync's primary purpose is to call beginTransaction. Maybe name it something like beginTransactionAsync?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, changed to beginTransactionAsync. Since this is in the transaction class run typically means run the transaction, but maybe beginTransactionAsync is more descriptive. Either way, this method is private so the name can be modified later if need be.

this.#parseRunSuccess(runResults);
}
});
} catch (err: any) {
return callback(err);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of errors might you encounter here? A comment would be useful

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

}
}
return fn();
})();
}
}

export type ModifiedEntities = Array<{
Expand Down Expand Up @@ -1127,7 +1098,6 @@ promisifyAll(Transaction, {
'save',
'update',
'upsert',
'#withBeginTransaction',
],
});

Expand Down
1 change: 0 additions & 1 deletion test/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ const fakePfy = Object.assign({}, pfy, {
'save',
'update',
'upsert',
'#withBeginTransaction',
]);
},
});
Expand Down
Loading