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 { CosmosClient } from "../../CosmosClient";
import { RequestOptions, Response } from "../../request"; import { RequestOptions, Response } from "../../request";
import { Container } from "../Container"; import { Container } from "../Container";
import { ItemBody } from "./ItemBody";
import { ItemDefinition } from "./ItemDefinition";
import { ItemResponse } from "./ItemResponse"; import { ItemResponse } from "./ItemResponse";
/** /**
@ -36,7 +38,7 @@ export class Item {
* @param options Additional options for the request, such as the partition key. * @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`. * 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. * Read the item's definition.
* *
@ -62,15 +64,15 @@ export class Item {
* ({body: item} = await item.read<TodoItem>()); * ({body: item} = await item.read<TodoItem>());
* ``` * ```
*/ */
public read<T>(options?: RequestOptions): Promise<ItemResponse<T>>; public read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async read<T>(options?: RequestOptions): Promise<ItemResponse<T>> { public async read<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {}; options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) { if ((!options || !options.partitionKey) && this.primaryKey) {
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 { return {
body: response.result, body: response.result as T & ItemBody,
headers: response.headers, headers: response.headers,
ref: this, ref: this,
item: this item: this
@ -85,7 +87,7 @@ export class Item {
* @param body The definition to replace the existing {@link Item}'s defintion with. * @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. * @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. * 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 body The definition to replace the existing {@link Item}'s defintion with.
* @param options Additional options for the request, such as the partition key. * @param options Additional options for the request, such as the partition key.
*/ */
public 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>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> { public async replace<T extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {}; options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) { if ((!options || !options.partitionKey) && this.primaryKey) {
options.partitionKey = this.primaryKey; options.partitionKey = this.primaryKey;
} }
const response = await (this.client.documentClient.replaceDocument(this.url, body, options) as Promise< const response = await this.client.documentClient.replaceDocument(this.url, body, options);
Response<T>
>);
return { return {
body: response.result, body: response.result,
headers: response.headers, headers: response.headers,
@ -118,7 +118,7 @@ export class Item {
* Delete the item. * Delete the item.
* @param options Additional options for the request, such as the partition key. * @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. * Delete the item.
* *
@ -127,13 +127,13 @@ export class Item {
* *
* @param options Additional options for the request, such as the partition key. * @param options Additional options for the request, such as the partition key.
*/ */
public delete<T>(options?: RequestOptions): Promise<ItemResponse<T>>; public delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>>;
public async delete<T>(options?: RequestOptions): Promise<ItemResponse<T>> { public async delete<T extends ItemDefinition>(options?: RequestOptions): Promise<ItemResponse<T>> {
options = options || {}; options = options || {};
if ((!options || !options.partitionKey) && this.primaryKey) { if ((!options || !options.partitionKey) && this.primaryKey) {
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 { return {
body: response.result, body: response.result,
headers: response.headers, 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 { CosmosResponse } from "../../request/CosmosResponse";
import { Item } from "./Item"; 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. */ /** Reference to the {@link Item} the response corresponds to. */
item: Item; item: Item;
} }

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

@ -4,6 +4,8 @@ import { QueryIterator } from "../../queryIterator";
import { FeedOptions, RequestOptions, Response } from "../../request"; import { FeedOptions, RequestOptions, Response } from "../../request";
import { Container } from "../Container"; import { Container } from "../Container";
import { Item } from "./Item"; import { Item } from "./Item";
import { ItemBody } from "./ItemBody";
import { ItemDefinition } from "./ItemDefinition";
import { ItemResponse } from "./ItemResponse"; import { ItemResponse } from "./ItemResponse";
/** /**
@ -37,7 +39,7 @@ export class Items {
* const {body: containerList} = await items.query.toArray(); * 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. * Queries all items.
* @param query Query configuration for the operation. See {@link SqlQuerySpec} for more info on how to configure a query. * @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(); * const {body: containerList} = await items.query.toArray();
* ``` * ```
*/ */
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>(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>; 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(); * const {body: containerList} = await items.readAll().toArray();
* ``` * ```
*/ */
public readAll(options?: FeedOptions): QueryIterator<any>; public readAll(options?: FeedOptions): QueryIterator<ItemDefinition>;
/** /**
* Read all items. * Read all items.
* *
@ -84,8 +86,8 @@ export class Items {
* const {body: containerList} = await items.readAll().toArray(); * const {body: containerList} = await items.readAll().toArray();
* ``` * ```
*/ */
public readAll<T>(options?: FeedOptions): QueryIterator<T>; public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T>;
public readAll<T>(options?: FeedOptions): QueryIterator<T> { public readAll<T extends ItemDefinition>(options?: FeedOptions): QueryIterator<T> {
return this.client.readDocuments(this.container.url, options) as 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 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). * @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. * 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 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). * @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 extends ItemDefinition>(body: T, options?: RequestOptions): Promise<ItemResponse<T>>;
public async create<T>(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) as Promise<Response<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); const ref = new Item(this.container, (response.result as any).id, (options && options.partitionKey) as string);
return { return {
body: response.result, body: response.result as T & ItemBody,
headers: response.headers, headers: response.headers,
ref, ref,
item: 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 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). * @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. * 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 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). * @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 extends ItemDefinition>(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>> {
const response = await this.client.upsertDocument(this.container.url, body, options); 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); const ref = new Item(this.container, (response.result as any).id, (options && options.partitionKey) as string);
return { return {

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

@ -1,3 +1,4 @@
export { Item } from "./Item"; export { Item } from "./Item";
export { Items } from "./Items"; export { Items } from "./Items";
export { ItemResponse } from "./ItemResponse"; 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 { export interface PermissionDefinition {
/** The id of the permission */ /** The id of the permission */
id?: string; id: string;
/** The mode of the permission, must be a value of {@link PermissionMode} */ /** The mode of the permission, must be a value of {@link PermissionMode} */
permissionMode: PermissionMode; permissionMode: PermissionMode;
/** The link of the resource that the permission will be applied to. */ /** The link of the resource that the permission will be applied to. */

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

@ -1,8 +1,8 @@
import { CosmosResponse } from "../../request"; import { CosmosResponse } from "../../request";
import { Permission } from "./Permission"; 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}. */ /** A reference to the {@link Permission} corresponding to the returned {@link PermissionDefinition}. */
permission: Permission; permission: Permission;
} }

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

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

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

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