Google Cloud Platform
npm i @pi-r/gcp
Tip
The alias gcloud can be used in place of “gcp” for the service property.
Storage
Note
npm i firebase && npm i firebase-admin (optional)
Interface
import type { StorageOptions } from "@google-cloud/storage";
import type { FirebaseOptions } from "@firebase/app";
import type { ServiceAccount } from "firebase-admin/app";
interface GCPStorage extends CloudStorage {
service: "gcp" | "gcloud";
credential: string | GCPStorageCredential;
bucket: string;
}
interface GCPStorageCredential extends StorageOptions, FirebaseOptions {
product?: "firebase";
admin?: boolean | string | ServiceAccount;
}
API
type Document = Record<string, any>;
type Metadata = Record<string, any>;
Authentication
GOOGLE_APPLICATION_CREDENTIALS = "";
{
"dataSource": {
"credential": "main", // squared.cloud.json
/* OR */
"credential": {
"keyFilename": "./gcp.json", // Path to JSON credentials
"projectId": "nodejs"
},
/* OR */
"credential": {
"projectId": "nodejs",
"credentials": {
"client_email": "**********",
"private_key": "**********",
"type": "service_account", // Optional
"project_id": "nodejs"
}
},
/* OR */
"credential": {
"projectId": "nodejs", // When using GOOGLE_APPLICATION_CREDENTIALS
"scopes": "https://www.googleapis.com/auth/cloud-platform" // Optional
},
/* OR */
"credential": {
"projectId": "nodejs",
"apiKey": "**********",
"authDomain": "<project-id>.firebaseapp.com",
/* OR */
"product": "firebase" // When using GOOGLE_APPLICATION_CREDENTIALS
}
}
}
Example usage
{
"selector": "html", // Any resource
"cloudStorage": [{
"service": "gcp",
"bucket": "nodejs-001",
"credential": {/* Authentication */},
"admin": {
"publicRead": true, // New buckets only
/* OR */
"acl": "private", // See "policy"
"emptyBucket": { // gcp.(deleteFiles | getFiles){GetFilesOptions}
"recursive": true // Optional
},
"configBucket": {
"policy": { // MakeBucketPrivateOptions
"acl": "private", // makePrivate + includeFiles + projectPrivate
"acl": "projectPrivate", // makePrivate + allUsers (delete) + allAuthenticatedUsers (delete)
"acl": "authenticatedRead", // projectPrivate + allAuthenticatedUsers:READER
"acl": "publicRead", // makePublic + includeFiles
"acl": "publicReadWrite", // publicRead + allUsers:WRITER
"acl": [{ "entity": "allUsers", "role": "READER" } /* add */, { "entity": "allAuthenticatedUsers" } /* delete */], // Custom
/* Unofficial aliases - gcp.setMetadata{iamConfiguration} */
"acl": "bucketAccessUniform", // Enable uniform bucket-level access
"acl": "bucketAccessACL" // Revert uniform bucket-level access (within 90 days)
},
"tags": { // gcp.setMetadata{labels}
"key_1": "value",
"key_2": "value"
},
"tags": {}, // gcp.setMetadata{labels=null}
"website": { // gcp.setMetadata{website}
"indexPage": "index.html", // mainPageSuffix
"errorPage": "404.html" // notFoundPage
},
/* During call to "upload" */
"create": { // gcp.createBucket{CreateBucketRequest}
"location": "ASIA",
"storageClass": "STANDARD" // "NEARLINE" | "COLDLINE" | "ARCHIVE"
},
"lifecycle": [/* LifecycleRule */], // gcp.addLifecycleRule
"lifecycle": [/* LifecycleRule */, false], // options.append = false
"lifecycle": [], // Delete all rules
"cors": [/* Cors */], // gcp.setCorsConfiguration
"cors": [], // Delete all rules
"retentionPolicy": 0, // gcp.removeRetentionPeriod
"retentionPolicy": 86400 // gcp.setRetentionPeriod (seconds)
}
},
"upload": {
"publicRead": true, // Will not clobber existing ACLs
"publicRead": 0, // Remove ACL without affecting other ACLs
/* OR */
"acl": "authenticatedRead", // "bucketOwnerFullControl" | "bucketOwnerRead" | "private" | "projectPrivate" | "publicRead"
/* gcp.save */
"options": { // UploadOptions
"contentType": "text/html",
"predefinedAcl": "publicRead", // Supplementary are public
"metadata": {/* Metadata */} // All objects except when "metadata" is defined
},
/* gcp.uploadFileInChunks{chunkSizeBytes} */
"chunkSize": "8mb", // Aligned to 1mb
"chunkLimit": 5, // Same as "concurrencyLimit"
"options": {
"contentType": "image/png",
"metadata": {/* Metadata */},
/* UploadFileInChunksOptions - shared */
"headers": {
"Authorization": "",
"x-goog-user-project": ""
},
"maxQueueSize": 5,
"concurrencyLimit": 5
},
/* firebase.uploadBytes */
"options": { // UploadMetadata
"contentType": "text/html",
"customMetadata": {/* Metadata */} // All objects except when "metadata" is defined
},
/* Primary object only */
"metadata": {
"key": "value",
"key_delete": null
}
},
"download": {
/* gcp.createReadStream */
"chunkSize": "", // Empty
"chunkLimit": 1, // Will only stream when value is 1
/* gcp.downloadFileInChunks{chunkSizeBytes} */
"chunkSize": "32mb", // Aligned to 1mb
"chunkLimit": 5, // Same as "concurrencyLimit"
"options": {
"concurrencyLimit": 5
}
/* Same as interface - gcp.download + firebase.getDownloadURL */
}
}]
}
Attention
Firebase does not support any bucket operations except emptyBucket and metadata.
Database
Interface
import type { AggregateSpec, FieldPath } from "@google-cloud/firestore";
import type { PathType } from "@google-cloud/datastore";
import type { entity } from "@google-cloud/datastore/build/src/entity";
import type { GoogleAuthOptions } from "google-auth-library";
import type { FirebaseOptions } from "@firebase/app";
interface GCPDatabaseQuery extends CloudDatabase {
source: "cloud";
service: "gcp" | "gcloud";
credential: string | GCPDatabaseCredential;
product?: "firestore" | "bigquery" | "bigtable" | "datastore" | "spanner" | "firebase";
id?: string | string[] | number | boolean;
params?: string | unknown[] | Document;
database?: string;
updateType?: 0 | 1 | 2 | 3;
columns?: string[];
keys?: DatastoreKey | DatastoreKey[];
kind?: string | string[];
orderBy?: (string | FieldPath | unknown[])[] | string | FieldPath;
aggregateSpec?: AggregateSpec;
pipeline?: boolean;
flags?: number;
}
interface GCPDatabaseCredential extends GoogleAuthOptions, FirebaseOptions {
product?: "firebase";
admin?: boolean | string | ServiceAccount;
}
type DatastoreKey = string | PathType[] | entity.KeyOptions;
type Document = Record<string, any>;
Authentication
{
"dataSource": {
"credential": "main", // squared.cloud.json
/* OR */
"credential": {/* Same as Storage */},
/* OR */
"credential": {
"projectId": "nodejs",
"apiKey": "**********",
"authDomain": "<project-id>.firebaseapp.com",
"databaseURL": "https://<database-name>.firebaseio.com" // Required
}
}
}
Example usage
Firestore
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "firestore",
"credential": {/* Authentication */},
"table": "demo",
/* a = fs.collection(table) | b = fs.collectionGroup(table){flags & 1} */
"id": "8Qnt83DSNW0eNykpuzcQ", // a.doc
/* OR */
"id": ["8Qnt83DSNW0eNykpuzcQ", "aahiEBE4qHM73JE7jom3"], // fs.getAll (table/id)
"options": {/* ReadOptions */},
/* OR */
"params": ["column", "column.sub"], // a.findNearest
"query": [1, 2],
"options": {
"limit": 1000, // Optional
"distanceMeasure": "EUCLIDEAN"
},
/* OR */
"options": { // a.findNearest{VectorQueryOptions} (not cached)
"vectorField": "column",
"queryVector": [1, 2],
"limit": 1000, // Optional
"distanceMeasure": "EUCLIDEAN"
},
/* OR */
"aggregateSpec": {/* AggregateSpec */}, // (a | b).aggregate (not cached)
"updateType": 0, // 0 - update{exists} | 1 - create | 2 - set | 3 - set{merge}
"update": {/* Document */}, // fs.update
"update": {
"key1": "__delete__", // FieldValue.delete()
"key2": "__increment__", // FieldValue.increment(1)
"key2": "__increment<number>__", // FieldValue.increment(number)
"key3": "__serverTimestamp__", // FieldValue.serverTimestamp()
"key4": "__vector<1, 2, 3>__", // FieldValue.vector([1, 2, 3])
"key4": "__arrayUnion<a, b, c>__", // FieldValue.arrayUnion("a", "b", "c")
"key4": "__arrayRemove<1, [2\\, 3\\, 4], 5>__" // FieldValue.arrayRemove(1, [2, 3, 4], 5)
},
"id": "8Qnt83DSNW0eNykpuzcQ" // Same as item being retrieved
}
}
Query
{
"dataSource": {
"query": [
["where", "group", "==", "Firestore"],
["where", "id", "==", "8Qnt83DSNW0eNykpuzcQ"],
["findNearest", "column", [1, 2], { "limit": 1000, "distanceMeasure": "EUCLIDEAN" }],
["limitToLast", 2],
["orderBy", "title", "asc"]
],
"query": [
["whereAnd",
["group", "==", "Firestore"],
["id", "==", "8Qnt83DSNW0eNykpuzcQ"]
],
["limitToLast", 2]
],
"query": [
["whereOr",
["id", "==", "8Qnt83DSNW0eNykpuzcQ"],
["id", "==", "aahiEBE4qHM73JE7jom3"]
],
["orderBy", "title", "asc"]
],
"orderBy": [
["title", "asc"]
],
"id": 1 // b.getPartitions(id){number} // Group only (optional)
}
}
|
|
|
|
Pipeline
These methods query parameters are interpreted when every item is an Array:
|
|
|
|
{
"dataSource": {
"query": [
["aggregate", ["rating", "average", "averageRating"]], // field("rating").average().as("averageRating")
["aggregate", ["countAll", "totalBooks"]], // countAll().as("totalBooks")
["aggregate", ["name", ["startsWith", "Mr."], "countIf"]] // countIf(field("name").startsWith("Mr."))
],
"query": [
["select", ["firstName", ["field", "lastName"], ["address", "toUpper", ["as", "upperAddress"]]]] // "firstName", field("lastName"), field("address").toUpper().as("upperAddress")
["distinct", [["author", "authorName"], "publishedAt"]] // field("author").as("authorName"), "publishedAt"
],
"query": [
["sort", ["rating", ["title", true]]] // field("rating").ascending(), field("title").descending()
],
"query": [
["unnest", ["tagIndex", ["tags", "tag", /* indexField? */]]] // "tagIndex", field("tags").as("tag")
],
"query": [
["where", [
["rating", "lessThanOrEqual", 3.15], // field("rating").lessThanOrEqual(3.15)
["genre", ["toLower", ["equal", "Fun Facts"]]] // field("genre").toLower().equal("fun facts")
]]
],
"query": [
["whereAnd", [
["rating", "lessThanOrEqual", 3.15], // and(field("rating").lessThanOrEqual(3.15), field("genre").toLower().equal("fun facts"))
["genre", ["toLower", ["equal", "Fun Facts"]]]
]],
["whereOr", [
["rating", "lessThanOrEqual", 3.15], // or(field("rating").lessThanOrEqual(3.15), field("genre").toLower().equal("fun facts"))
["genre", ["toLower", ["equal", "Fun Facts"]]]
]]
],
"options": {/* PipelineExecuteOptions */}
}
}
These methods query parameters are passed in directly without modification:
|
|
|
|
{
"dataSource": {
"query": [
["limit", 50], // limit(50)
["limit", { "limit": 75 }] // limit({ limit: 75 })
]
}
}
BigQuery
Note
npm i @google-cloud/bigquery
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "bigquery",
"credential": {/* Authentication */},
"database": "nodejs", // Dataset (optional)
"table": "demo", // Destination table (optional)
"query": "SELECT name, count FROM `demo.names_2014` WHERE gender = 'M' ORDER BY count DESC LIMIT 10", // bq.getQueryResults
"params": { "name": "value" },
"params": ["arg0" /* ? */, "arg1" /* ? */],
"options": {/* IQuery */},
"update": "SELECT name, state FROM `bigquery-public-data.usa_names.usa_1910_current` LIMIT 10" // "database" | "database" + "table" (bq.setMetadata)
}
}
Datastore
Note
npm i @google-cloud/datastore
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "datastore",
"credential": {/* Authentication */},
"keys": "task", // ds.get
"keys": ["task", "sampletask1"], // PathType[]
"keys": { // KeyOptions
"namespace": "nodejs",
"path": ["task", "sampletask3"]
},
"keys": ["task", ["task", "sampletask2"]],
/* OR */
"name": "<namespace>", // With "kind" (optional)
"kind": "Task", // ds.runQuery (at least one parameter)
"kind": ["Task1", "Task2"],
"query": [
["filter", "done", "=", false],
["filter", "priority", ">=", 4],
["order", "priority", { "descending": true }]
],
"options": {/* RunQueryOptions */},
"update": {/* Document */}, // ds.save
"keys": "task", // Same as item being retrieved
/* OR */
"kind": "Task",
"query": [/* Same */]
}
}
|
|
|
|
Bigtable
Note
npm i @google-cloud/bigtable
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "bigtable",
"credential": {/* Authentication */},
"name": "nodejs", // Instance
"table": "demo",
"id": "rowKey1", // bt.get
"columns": ["column1", "column2"],
/* OR */
"id": "<empty>", // bt.createReadStream
"query": {/* Filter */}, // Overrides "filter" in GetRowOptions
"options": {/* GetRowOptions */},
"update": {/* Document */}, // bt.save
"id": "rowKey1" // Same as item being retrieved
}
}
Spanner
Note
npm i @google-cloud/spanner
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "spanner",
"credential": {/* Authentication */},
"name": "nodejs", // Instance
"database": "sample", // Required
"options": {
"databasePool": {/* session-pool.SessionPoolOptions */},
"databaseQuery": {/* protos.IQueryOptions */}
},
"table": "demo", // sp.table.read
"columns": ["col1", "col2"], // Overrides "columns" in ReadRequest
"query": { // ReadRequest
"columns": [],
"keys": []
},
"options": {
"tableRead": {/* TimestampBounds */}
},
/* OR */
"table": "<empty>", // sp.run
"flags": 2, // sp.runStream
"query": "SELECT 1", // DML
"query": { // ExecuteSqlRequest
"sql": "SELECT 1",
"params": { "p1": 0, "p2": 1 },
"types": {
"p1": "numeric" // date | float | float32 | int | protoEnum | protoMessage | struct | pgJsonb | pgNumeric | timestamp
}
},
"table": "demo", // sp.table.update
"update": {/* Document */},
"updateType": 0, // 0 - update | 1 - insert | 2 - replace
"options": {
"tableUpdate": {/* UpdateRowsOptions */}
},
/* OR */
"table": "<empty>", // sp.runUpdate
"update": "SELECT 1",
"update": { "sql": "SELECT 1", "params": { "p1": 0, "p2": 1 } }
}
}
Realtime Database
Note
npm i firebase && npm i firebase-admin (optional)
{
"selector": "h1",
"type": "text",
"dataSource": {
"source": "cloud",
"service": "gcp",
"product": "firebase",
"credential": {/* Authentication */},
"query": "path/to/ref", // rd.child
/* OR */
"query": "path/to/ref", // rd.query
"orderBy": [
["orderByChild", "path/to/child"],
["startAfter", 5, "name"],
["limitToFirst", 1]
],
"update": {/* Document */}, // rd.update
"query": "path/to/ref" // Same as item being retrieved (rd.child)
}
}
|
|
|
|
@pi-r/gcp
Added in version 0.12.0:
Firestore pipeline (beta) queries are supported.
Changed in version 0.12.0:
BREAKINGThere is no special handling when uploading the file extension “.map”. CloudStorageUpload property descendantsGroup as [“.map”] can be used to restore the old behavior.
Added in version 0.11.0:
GCPStorage properties upload | download extended CopyObjectAction as copyObject | copyObject[].
Added in version 0.10.1:
Spanner method runStream for SQL requests was implemented.
Changed in version 0.10.0:
GCPStorage property admin.configBucket.retentionPolicy as 0 calls the method removeRetentionPeriod.
Firebase (admin) authentication using a JSON file or an object with a service account key is supported.
Firestore aggregate and collection group partition queries are supported.
Firestore method findNearest for vector queries as VectorQueryOptions was implemented.
Added in version 0.9.0:
GCPStorage property emptyBucket for directory listing as GetListOptions was implemented.
Added in version 0.8.0:
GCPStorage action download using createReadStream with chunkLimit was implemented.
Firestore method findNearest as a VectorQuery and Query is supported.
Firestore property update supports using FieldValue<”vector” | “arrayUnion” | “arrayRemove”> methods.
Added in version 0.7.1:
Firestore methods where | orderBy | select supports using FieldPath params.
Added in version 0.7.0:
CLOUD_UPLOAD_STREAM attribute in ICloudServiceClient was enabled.
CLOUD_UPLOAD_CHUNK attribute in ICloudServiceClient was enabled.
CLOUD_DOWNLOAD_CHUNK attribute in ICloudServiceClient was enabled.
chunkSize | chunkLimit in CloudStorageUpload were implemented.
chunkSize | chunkLimit in CloudStorageDownload were implemented.
GCPStorage configBucket.tags using Metadata was implemented.
GCPStorage configBucket.cors using Cors was implemented.
GCPStorage configBucket.lifecycle using LifecycleRule was implemented.
Firestore property update supports using FieldValue<”delete” | “increment” | “serverTimestamp”> methods.
Firestore property update supports using property updateType enum values.
Removed in version 0.7.0:
GCPStorageCredential no longer extends CreateBucketRequest.
Added in version 0.6.3:
Firestore property id supports multiple document references.
Firestore property query supports using Filter<”and” | “or”> conditional groups.
Added in version 0.6.2:
GoogleAuthOptions properties authClient and credentials were not detected during credential validation.
Datastore method createQuery with namespace and kind parameter is supported.