Add system generated keys for permissions and items (#83)

* Add system generated keys for permissions and items

* Add ItemDefinition (#84)
This commit is contained in:
Steve Faulkner 2018-07-31 00:51:25 +00:00 коммит произвёл GitHub
Родитель d44294d40d
Коммит 85d02c6760
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 100 добавлений и 40 удалений

Просмотреть файл

@ -2,6 +2,8 @@ import { UriFactory } from "../../common";
import { CosmosClient } from "../../CosmosClient";
import { RequestOptions, Response } from "../../request";
import { Container } from "../Container";
import { ItemBody } from "./ItemBody";
import { ItemDefinition } from "./ItemDefinition";
import { ItemResponse } from "./ItemResponse";
/**
@ -36,7 +38,7 @@ export class Item {
* @param options Additional options for the request, such as the partition key.
* Note, if you provide a partition key on the options object, it will override the primary key on `this.primaryKey`.
*/
public read(options?: RequestOptions): Promise<ItemResponse<any>>;
public read(options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Read the item's definition.
*
@ -62,15 +64,15 @@ export class Item {
* ({body: item} = await item.read<TodoItem>());
* ```
*/
public read<T>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async read<T>(options?: RequestOptions): Promise<ItemResponse<T>> {
public read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) {
options.partitionKey = this.primaryKey;
}
const response = await (this.client.documentClient.readDocument(this.url, options) as Promise<Response<T>>);
const response = await this.client.documentClient.readDocument(this.url, options);
return {
body: response.result,
body: response.result as T & ItemBody,
headers: response.headers,
ref: this,
item: this
@ -85,7 +87,7 @@ export class Item {
* @param body The definition to replace the existing {@link Item}'s defintion with.
* @param options Additional options for the request, such as the partition key.
*/
public replace(body: any, options?: RequestOptions): Promise<ItemResponse<any>>;
public replace(body: ItemDefinition, options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Replace the item's definition.
*
@ -97,15 +99,13 @@ export class Item {
* @param body The definition to replace the existing {@link Item}'s defintion with.
* @param options Additional options for the request, such as the partition key.
*/
public replace<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async replace<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
public replace<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async replace<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) {
options.partitionKey = this.primaryKey;
}
const response = await (this.client.documentClient.replaceDocument(this.url, body, options) as Promise<
Response<T>
>);
const response = await this.client.documentClient.replaceDocument(this.url, body, options);
return {
body: response.result,
headers: response.headers,
@ -118,7 +118,7 @@ export class Item {
* Delete the item.
* @param options Additional options for the request, such as the partition key.
*/
public delete(options?: RequestOptions): Promise<ItemResponse<any>>;
public delete(options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Delete the item.
*
@ -127,13 +127,13 @@ export class Item {
*
* @param options Additional options for the request, such as the partition key.
*/
public delete<T>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async delete<T>(options?: RequestOptions): Promise<ItemResponse<T>> {
public delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) {
options.partitionKey = this.primaryKey;
}
const response = await (this.client.documentClient.deleteDocument(this.url, options) as Promise<Response<T>>);
const response = await this.client.documentClient.deleteDocument(this.url, options);
return {
body: response.result,
headers: response.headers,

Просмотреть файл

@ -0,0 +1,14 @@
export interface ItemBody {
/** Required. User settable property. Unique name that identifies the item, that is, no two items share the same ID within a database. The id must not exceed 255 characters. */
id: string;
/** System generated property. The resource ID (_rid) is a unique identifier that is also hierarchical per the resource stack on the resource model. It is used internally for placement and navigation of the item resource. */
_rid: string;
/** System generated property. Specifies the last updated timestamp of the resource. The value is a timestamp. */
_ts: string;
/** System generated property. The unique addressable URI for the resource. */
_self: string;
/** System generated property. Represents the resource etag required for optimistic concurrency control. */
_etag: string;
/** System generated property. Specifies the addressable path for the attachments resource. */
_attachments: string;
}

Просмотреть файл

@ -0,0 +1,11 @@
/**
* Items in Cosmos DB are simply JSON objects.
* Most of the Item operations allow for your to provide your own type
* that extends the very simple ItemDefintion.
*
* You cannot use any reserved keys. You can see the reserved key list
* in {@link ItemBody}
*/
export interface ItemDefinition {
[key: string]: any;
}

Просмотреть файл

@ -1,7 +1,9 @@
import { CosmosResponse } from "../../request/CosmosResponse";
import { Item } from "./Item";
import { ItemBody } from "./ItemBody";
import { ItemDefinition } from "./ItemDefinition";
export interface ItemResponse<T> extends CosmosResponse<T, Item> {
export interface ItemResponse<T extends ItemDefinition> extends CosmosResponse<T & ItemBody, Item> {
/** Reference to the {@link Item} the response corresponds to. */
item: Item;
}

Просмотреть файл

@ -4,6 +4,8 @@ import { QueryIterator } from "../../queryIterator";
import { FeedOptions, RequestOptions, Response } from "../../request";
import { Container } from "../Container";
import { Item } from "./Item";
import { ItemBody } from "./ItemBody";
import { ItemDefinition } from "./ItemDefinition";
import { ItemResponse } from "./ItemResponse";
/**
@ -37,7 +39,7 @@ export class Items {
* const {body: containerList} = await items.query.toArray();
* ```
*/
public query(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<any>;
public query(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<ItemDefinition>;
/**
* Queries all items.
* @param query Query configuration for the operation. See {@link SqlQuerySpec} for more info on how to configure a query.
@ -53,8 +55,8 @@ export class Items {
* const {body: containerList} = await items.query.toArray();
* ```
*/
public query<T>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T>;
public query<T>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T> {
public query<T extends ItemDefinition>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T>;
public query<T extends ItemDefinition>(query: string | SqlQuerySpec, options?: FeedOptions): QueryIterator<T> {
return this.client.queryDocuments(this.container.url, query, options) as QueryIterator<T>;
}
@ -69,7 +71,7 @@ export class Items {
* const {body: containerList} = await items.readAll().toArray();
* ```
*/
public readAll(options?: FeedOptions): QueryIterator<any>;
public readAll(options?: FeedOptions): QueryIterator<ItemDefinition>;
/**
* Read all items.
*
@ -84,8 +86,8 @@ export class Items {
* const {body: containerList} = await items.readAll().toArray();
* ```
*/
public readAll<T>(options?: FeedOptions): QueryIterator<T>;
public readAll<T>(options?: FeedOptions): QueryIterator<T> {
public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T>;
public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T> {
return this.client.readDocuments(this.container.url, options) as QueryIterator<T>;
}
@ -97,7 +99,7 @@ export class Items {
* @param body Represents the body of the item. Can contain any number of user defined properties.
* @param options Used for modifying the request (for instance, specifying the partition key).
*/
public async create(body: any, options?: RequestOptions): Promise<ItemResponse<any>>;
public async create(body: any, options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Create a item.
*
@ -109,12 +111,12 @@ export class Items {
* @param body Represents the body of the item. Can contain any number of user defined properties.
* @param options Used for modifying the request (for instance, specifying the partition key).
*/
public async create<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async create<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
const response = await (this.client.createDocument(this.container.url, body, options) as Promise<Response<T>>);
public async create<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async create<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
const response = await this.client.createDocument(this.container.url, body, options);
const ref = new Item(this.container, (response.result as any).id, (options && options.partitionKey) as string);
return {
body: response.result,
body: response.result as T & ItemBody,
headers: response.headers,
ref,
item: ref
@ -129,7 +131,7 @@ export class Items {
* @param body Represents the body of the item. Can contain any number of user defined properties.
* @param options Used for modifying the request (for instance, specifying the partition key).
*/
public async upsert(body: any, options?: RequestOptions): Promise<ItemResponse<any>>;
public async upsert(body: any, options?: RequestOptions): Promise<ItemResponse<ItemDefinition>>;
/**
* Upsert an item.
*
@ -141,8 +143,8 @@ export class Items {
* @param body Represents the body of the item. Can contain any number of user defined properties.
* @param options Used for modifying the request (for instance, specifying the partition key).
*/
public async upsert<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async upsert<T>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
public async upsert<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async upsert<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
const response = await this.client.upsertDocument(this.container.url, body, options);
const ref = new Item(this.container, (response.result as any).id, (options && options.partitionKey) as string);
return {

Просмотреть файл

@ -1,3 +1,4 @@
export { Item } from "./Item";
export { Items } from "./Items";
export { ItemResponse } from "./ItemResponse";
export { ItemDefinition } from "./ItemDefinition";

Просмотреть файл

@ -0,0 +1,15 @@
import { PermissionMode } from "../../documents";
import { PermissionDefinition } from "./PermissionDefinition";
export interface PermissionBody extends PermissionDefinition {
/** System generated property. The resource ID (_rid) is a unique identifier that is also hierarchical per the resource stack on the resource model. It is used internally for placement and navigation of the permission resource. */
_rid: string;
/** System generated property. Specifies the last updated timestamp of the resource. The value is a timestamp. */
_ts: string;
/** System generated property. The unique addressable URI for the resource. */
_self: string;
/** System generated property. Represents the resource etag required for optimistic concurrency control. */
_etag: string;
/** System generated resource token for the particular resource and user */
_token: string;
}

Просмотреть файл

@ -2,7 +2,7 @@ import { PermissionMode } from "../../documents";
export interface PermissionDefinition {
/** The id of the permission */
id?: string;
id: string;
/** The mode of the permission, must be a value of {@link PermissionMode} */
permissionMode: PermissionMode;
/** The link of the resource that the permission will be applied to. */

Просмотреть файл

@ -1,8 +1,8 @@
import { CosmosResponse } from "../../request";
import { Permission } from "./Permission";
import { PermissionDefinition } from "./PermissionDefinition";
import { PermissionBody } from "./PermissionBody";
export interface PermissionResponse extends CosmosResponse<PermissionDefinition, Permission> {
export interface PermissionResponse extends CosmosResponse<PermissionBody, Permission> {
/** A reference to the {@link Permission} corresponding to the returned {@link PermissionDefinition}. */
permission: Permission;
}

Просмотреть файл

@ -2,14 +2,14 @@ import * as assert from "assert";
import { Container, CosmosClient, Database, DatabaseDefinition, Item, RequestOptions, Response } from "../../";
import {
ContainerDefinition,
ItemDefinition,
ItemResponse,
PermissionDefinition,
PermissionResponse,
TriggerResponse,
User,
UserDefinedFunctionResponse,
UserDefinition
UserDefinedFunctionResponse
} from "../../client";
import { ItemBody } from "../../client/Item/ItemBody";
import { StoredProcedureResponse } from "../../client/StoredProcedure/StoredProcedureResponse";
import { UserResponse } from "../../client/User/UserResponse";
import { endpoint, masterKey } from "./../common/_testConfig";
@ -67,7 +67,10 @@ export async function getTestContainer(
return db.container(id);
}
export async function bulkInsertItems(container: Container, documents: any[]) {
export async function bulkInsertItems(
container: Container,
documents: any[]
): Promise<Array<ItemDefinition & ItemBody>> {
const returnedDocuments = [];
for (const doc of documents) {
try {

Просмотреть файл

@ -12,6 +12,18 @@ import {
replaceOrUpsertItem
} from "./../common/TestHelpers";
/**
* @ignore
* @hidden
*/
interface TestItem {
id?: string;
name?: string;
foo?: string;
key?: string;
replace?: string;
}
describe("NodeJS CRUD Tests", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 10000);
beforeEach(async function() {
@ -32,7 +44,7 @@ describe("NodeJS CRUD Tests", function() {
// create an item
const beforeCreateDocumentsCount = items.length;
const itemDefinition = {
const itemDefinition: TestItem = {
name: "sample document",
foo: "bar",
key: "value",
@ -73,8 +85,8 @@ describe("NodeJS CRUD Tests", function() {
assert.equal(replacedDocument.foo, "not bar", "property should have changed");
assert.equal(document.id, replacedDocument.id, "document id should stay the same");
// read document
const { body: document2 } = await container.item(replacedDocument.id).read();
assert.equal(replacedDocument.id, document.id);
const { body: document2 } = await container.item(replacedDocument.id).read<TestItem>();
assert.equal(replacedDocument.id, document2.id);
// delete document
const { body: res } = await container.item(replacedDocument.id).delete();