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

DRAFT: [Tables] API Review 1.0.0-preview.1 #1

Draft
wants to merge 1 commit into
base: tables-review-pr
Choose a base branch
from

Conversation

mahdiva
Copy link
Owner

@mahdiva mahdiva commented Jul 28, 2020

No description provided.


// @public
export type CreateEntityResponse = TableInsertEntityHeaders & {
[propertyName: string]: any;

Choose a reason for hiding this comment

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

WIP: CreateEntityResponse will use generic types

export type CreateEntityResponse<T> = TableInsertEntityHeaders & T & {
   // ...
}


// @public
export interface DeleteEntityOptions extends coreHttp.OperationOptions {
queryOptions?: GeneratedQueryOptions;

Choose a reason for hiding this comment

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

We'll need to rename GeneratedQueryOptions

}

// @public
export type Entity<T> = T & {

Choose a reason for hiding this comment

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

Other languages seem to be going with TableEntity. Is TableEntity what we want to use across languages?

Copy link

@joheredi joheredi Jul 29, 2020

Choose a reason for hiding this comment

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

Entity should also include etag and timestamp

};

// @public
export interface GeneratedQueryOptions {

Choose a reason for hiding this comment

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

We may want to rename GeneratedQueryOptions

export type ListEntitiesIterator<T extends object> = PagedAsyncIterableIterator<
T,
ListEntitiesPageResult<T>,
{}

Choose a reason for hiding this comment

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

WIP: We are working on refining the iterator. {} will be replaced by PageSettings or removed.

For context this is the interface of PageSettings

/**
 * @interface
 * An interface that tracks the settings for paged iteration
 */
export interface PageSettings {
  /**
   * @member {string} [continuationToken] The token that keeps track of where to continue the iterator
   */
  continuationToken?: string;
  /**
   * @member {number} [pageSize] The size of the page during paged iteration
   */
  maxPageSize?: number;
}

date?: Date;
requestId?: string;
version?: string;
xMsContinuationNextTableName?: string;

Choose a reason for hiding this comment

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

xMsContinuationNextTableName should probably be renamed to nextTableName


// @public
export class TableServiceClient {
constructor(url: string, options?: TableServiceClientOptions);

Choose a reason for hiding this comment

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

WIP: constructor override which accepts SharedKeyCredential

query?: QueryOptions,
options?: ListEntitiesOptions
): Promise<ListEntitiesResponse<T>>;
listTables(query?: QueryOptions, options?: ListTablesOptions): Promise<ListTablesResponse>;

Choose a reason for hiding this comment

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

WIP: listTables will support PagedAsyncIterableIterator

queryOptions?: GeneratedQueryOptions;
requestId?: string;
tableEntityProperties?: {
[propertyName: string]: any;

Choose a reason for hiding this comment

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

If possible we should override uses of [propertyName: string]: any] with generic types

tableName: string,
entity: Entity<T>,
mode?: UpdateMode,
eTag?: string,

Choose a reason for hiding this comment

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

If we are already passing the entity, do we need to also pass the eTag? Or can we just extract it from the entity we were passed?

Choose a reason for hiding this comment

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

Do we want to default eTag to "*" or do we make it required and don't assume "*" on undefined?

"*" will force unconditional update

Choose a reason for hiding this comment

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

From the arch board review, we'd like to have etag as optional and default to "*"

// @public
export interface GeneratedQueryOptions {
filter?: string;
format?: OdataMetadataFormat;

Choose a reason for hiding this comment

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

So looking at this the actual values the user would pass here are things like this:
"application/json;odata=nometadata"

Is the user expected to modify these strings at all (ie, pass something other applictio/json, like octet-stream, etc..)?

If not is it worth simplifying them? Perhaps:
"none" | "minimal" | "full"

and then translating this in your convenience layer?

}

// @public
export function odata(strings: TemplateStringsArray, ...values: unknown[]): string;
Copy link

@richardpark-msft richardpark-msft Jul 28, 2020

Choose a reason for hiding this comment

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

It seems somewhat rare to have an exported function without some associated class. How would the user use this - just curious how it ties in.

Copy link
Owner Author

Choose a reason for hiding this comment

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

This helper function will be used as a tagged template literal for escaping any single quotes inside a filter parameter when querying.

Choose a reason for hiding this comment

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

That is pretty neat!

| "application/json;odata=fullmetadata";

// @public
export interface QueryOptions extends Omit<GeneratedQueryOptions, "select"> {

Choose a reason for hiding this comment

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

I love Omit<> but be aware that it does ugly thing in our doc tool currently.

// @public
export interface TableSetAccessPolicyOptionalParams extends coreHttp.OperationOptions {
requestId?: string;
tableAcl?: SignedIdentifier[];

Choose a reason for hiding this comment

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

Not familiar with tables but is this always one way (ie only acts as an allowed list, never acts as a deny list?).

export interface TableSetAccessPolicyOptionalParams extends coreHttp.OperationOptions {
requestId?: string;
tableAcl?: SignedIdentifier[];
timeout?: number;

Choose a reason for hiding this comment

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

I believe we have a rule about this - it has to be timeoutInMs (ie, mention the unit and add 'In').

Also, is this timeout separate from the normal corehttp timeouts? Does it function independently of our normal retries, etc.?


// @public
export interface TableSetAccessPolicyOptionalParams extends coreHttp.OperationOptions {
requestId?: string;

Choose a reason for hiding this comment

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

I'm curious what this is - I feel like generically we have fields with 'request' in the name all over the place (ie, for http, etc..). Is this something specific o tables (and if so - could it have a more Tables specific name?)

};

// @public
export enum UpdateMode {

Choose a reason for hiding this comment

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

In Service Bus we've been eschewing enums in favor of just using string unions - no sure if that's an option you'd like to try here or if the 0/1 is better for clients.

So:

export type UpdateMode = "merge" | "replace";

tableName: string,
partitionKey: string,
rowKey: string,
ifMatch: string,

Choose a reason for hiding this comment

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

Is ifMatch really not optional? Or is this not the etag ifMatch?

}

// @public
export class EdmInt64 {

Choose a reason for hiding this comment

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

This is interesting! We use a long package in Service Bus and I seem to recall Brian pushing hard to see if we could just use number, etc...

Do you know if we have an "approved" way of representing longer number at this point?

Copy link

@joheredi joheredi Jul 28, 2020

Choose a reason for hiding this comment

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

@richardpark-msft, your bring up a good point. We're currently having this conversation with @bterlson, @xirzec and @ellismg

It seems like we'll land on not having these classes and instead representing these "special" types with a JSON object and give the users freedom to choose the big integer library of they liking.

{
  id: {value: "60c1ebb2-875e-4988-8610-efe28a600c08", type: "Guid"},
  viewCount: {value: "55999333", type: "Int64"},
  name: "Some entity",
  price: 123.50,
  isActive: true,
  inStockUntil: new Date("11/05/2020");
}

So for example if the user has BigInt they can do:

c = obj.viewCount.type === 'Int64' ? BigInt(obj.viewCount.value) : obj.viewCount

Note that these Edm objects will only be needed when users need to explicitly set Edm.Guid and Edm.Int64 in the Service all the other supported types will be handled by the SDK and represented as native types.

Choose a reason for hiding this comment

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

Are you taking community feedback on the EdmGuid and EdmInt64 class types? I've been watching this closely and really like the class representation versus the object representation. The object representation could also be used, as the classes could have the proposed properties in the object which would allow the same check of the "type" property.

}

async function listTables() {
const tables = await serviceClient.listTables({

Choose a reason for hiding this comment

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

(sometimes it's interesting to "document" the defaults in the sample.

So for instance, is there a default sort order, that kind of thing and just place the field with it's default value, indicating it's the default. I think this is just for your review, so no big deal, but something to consider.

}

async function deleteEntity() {
await serviceClient.deleteEntity("Samples", "Part1", "Row4", "*");

Choose a reason for hiding this comment

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

Jeffrey Ritcher's comment: Do we want to hide entity operations from ServiceClient and only expose from the TableClient?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants