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

String array untyped #2010

Closed
wants to merge 58 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d992e90
feat(spanner): emulator support for admin client apis samples
alkatrivedi Feb 13, 2024
0cda32c
fix: lint errors
alkatrivedi Feb 13, 2024
1da0d06
docs: add comment
alkatrivedi Feb 13, 2024
8a8fcfb
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 13, 2024
1836197
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 14, 2024
c0ba211
refactor: remove redundant code lines
alkatrivedi Feb 14, 2024
ae8c194
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 14, 2024
6084578
refactor: renamed the helper function for the admin client API calls
alkatrivedi Feb 14, 2024
d00e7bd
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 14, 2024
e9e72e1
refactor: remove redundant code lines
alkatrivedi Feb 14, 2024
bb79fed
refactor if condition
alkatrivedi Feb 14, 2024
88aa219
refactor comments
alkatrivedi Feb 19, 2024
b414ef1
refactor: remove added logs
alkatrivedi Feb 19, 2024
6791652
chore: update helper functions for admin clients
alkatrivedi Feb 21, 2024
070c735
refactor: remove unneeded imports
alkatrivedi Feb 21, 2024
51e3fda
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 22, 2024
cdfff7f
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 23, 2024
5e98c3f
Merge branch 'googleapis:main' into admin-emulator-support
alkatrivedi Feb 23, 2024
f3ba05a
refactor: documention of get instance/database admin client method
alkatrivedi Feb 23, 2024
70ea49f
test: add the integration test for emulator support
alkatrivedi Feb 26, 2024
bec0fce
fix: header-checks
alkatrivedi Feb 26, 2024
7b36a00
fix: error in integration test
alkatrivedi Feb 26, 2024
9160ae0
fix: lint errors
alkatrivedi Feb 26, 2024
b2d578d
fix: header-checks
alkatrivedi Feb 26, 2024
d070abb
fix: license error
alkatrivedi Feb 26, 2024
d265645
fix: header-checks
alkatrivedi Feb 26, 2024
09847ce
fix: presubmit error
alkatrivedi Feb 26, 2024
2b25618
fix: presubmit error
alkatrivedi Feb 26, 2024
3754fae
fix: presubmit error
alkatrivedi Feb 26, 2024
1d5cb85
fix: presubmit errors
alkatrivedi Feb 26, 2024
336f1c9
fix: lint error
alkatrivedi Feb 26, 2024
ceb3a9c
Documentation and method names
surbhigarg92 Feb 27, 2024
4550b07
refactor integration test
alkatrivedi Feb 27, 2024
fbba14a
fix presubmit error
alkatrivedi Feb 27, 2024
1c6104f
fix: lint error
alkatrivedi Feb 27, 2024
5d7cdd6
fix: methods documentation
alkatrivedi Feb 27, 2024
b05ec94
refactor: methods name
alkatrivedi Feb 27, 2024
e756390
fix: presubmit error
alkatrivedi Feb 27, 2024
1e6cf67
Documentation changes
surbhigarg92 Feb 27, 2024
bf1590c
Refactor system tests
surbhigarg92 Feb 27, 2024
f122cbc
refactor: integration tests
alkatrivedi Feb 27, 2024
c0f4b3a
refactor code
alkatrivedi Feb 27, 2024
f5a536f
fix: lint error
alkatrivedi Feb 27, 2024
336c78e
refactor: remove redundant file
alkatrivedi Feb 27, 2024
fe119e3
fix: presubmit error
alkatrivedi Feb 27, 2024
65c8967
fix: presubmit error
alkatrivedi Feb 27, 2024
e52d926
test: add configrations for testing in local
alkatrivedi Feb 27, 2024
828d6cc
refactor: integration test
alkatrivedi Feb 27, 2024
6b95faa
fix: presubmit error
alkatrivedi Feb 27, 2024
53d7dec
review comments
surbhigarg92 Feb 27, 2024
ac04630
review comments
surbhigarg92 Feb 27, 2024
db0c65d
Apply suggestions from code review
surbhigarg92 Feb 27, 2024
9289cda
review comments
surbhigarg92 Feb 27, 2024
4603ebe
review comments
surbhigarg92 Feb 27, 2024
cfa7196
review comments
surbhigarg92 Feb 27, 2024
cb004f2
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Feb 27, 2024
aedbb14
review comments
surbhigarg92 Feb 27, 2024
7856cde
fix: untyped param for string array
surbhigarg92 Mar 4, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ system-test/*key.json
package-lock.json
__pycache__
.idea
.vscode
9 changes: 7 additions & 2 deletions src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ interface FieldType extends Type {
* @private
*
* @param {*} value - The value.
* @param {boolean} isArrayValue - If the value is for an array type.
* @returns {object}
*
* @example
Expand All @@ -597,7 +598,7 @@ interface FieldType extends Type {
* // {type: 'float64'}
* ```
*/
function getType(value: Value): Type {
function getType(value: Value, isArrayValue = false): Type {
const isSpecialNumber =
is.infinite(value) || (is.number(value) && isNaN(value));

Expand Down Expand Up @@ -629,6 +630,10 @@ function getType(value: Value): Type {
return {type: 'bool'};
}

if (is.string(value) && isArrayValue) {
return {type: 'string'};
}

if (Buffer.isBuffer(value)) {
return {type: 'bytes'};
}
Expand Down Expand Up @@ -663,7 +668,7 @@ function getType(value: Value): Type {

return {
type: 'array',
child: getType(child),
child: getType(child, true),
};
}

Expand Down
58 changes: 57 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ import {
CreateInstanceConfigCallback,
CreateInstanceConfigResponse,
} from './instance-config';
import {grpc, GrpcClientOptions, CallOptions, GoogleError} from 'google-gax';
import {
grpc,
GrpcClientOptions,
CallOptions,
GoogleError,
ClientOptions,
} from 'google-gax';
import {google, google as instanceAdmin} from '../protos/protos';
import {
PagedOptions,
Expand Down Expand Up @@ -347,6 +353,54 @@ class Spanner extends GrpcService {
this.directedReadOptions = directedReadOptions;
}

/**
* Gets the InstanceAdminClient object.
* The returned InstanceAdminClient object is a shared, managed instance and should not be manually closed.
* @returns {v1.InstanceAdminClient} The InstanceAdminClient object
* @example
* ```
* const {Spanner} = require('@google-cloud/spanner');
* const spanner = new Spanner({
* projectId: projectId,
* });
* const instanceAdminClient = spanner.getInstanceAdminClient();
* ```
*/
getInstanceAdminClient(): v1.InstanceAdminClient {
const clientName = 'InstanceAdminClient';
if (!this.clients_.has(clientName)) {
this.clients_.set(
clientName,
new v1[clientName](this.options as ClientOptions)
);
}
return this.clients_.get(clientName)! as v1.InstanceAdminClient;
}

/**
* Gets the DatabaseAdminClient object.
* The returned DatabaseAdminClient object is a managed, shared instance and should not be manually closed.
* @returns {v1.DatabaseAdminClient} The DatabaseAdminClient object.
* @example
* ```
* const {Spanner} = require('@google-cloud/spanner');
* const spanner = new Spanner({
* projectId: projectId,
* });
* const databaseAdminClient = spanner.getDatabaseAdminClient();
* ```
*/
getDatabaseAdminClient(): v1.DatabaseAdminClient {
const clientName = 'DatabaseAdminClient';
if (!this.clients_.has(clientName)) {
this.clients_.set(
clientName,
new v1[clientName](this.options as ClientOptions)
);
}
return this.clients_.get(clientName)! as v1.DatabaseAdminClient;
}

/** Closes this Spanner client and cleans up all resources used by it. */
close(): void {
this.clients_.forEach(c => {
Expand Down Expand Up @@ -1741,6 +1795,8 @@ promisifyAll(Spanner, {
'pgJsonb',
'operation',
'timestamp',
'getInstanceAdminClient',
'getDatabaseAdminClient',
],
});

Expand Down
149 changes: 149 additions & 0 deletions system-test/spanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,115 @@ describe('Spanner', () => {
);
});

describe('Autogenerated Admin Client', async () => {
const projectId = process.env.GCLOUD_PROJECT;
const instanceId = envInstanceName
? envInstanceName
: generateName('instance');
const DATABASE = generateName('database');
const instanceAdminClient = spanner.getInstanceAdminClient();
const databaseAdminClient = spanner.getDatabaseAdminClient();

before(async () => {
assert(projectId);
if (generateInstanceForTest) {
const [operation] = await instanceAdminClient.createInstance({
parent: instanceAdminClient.projectPath(projectId),
instanceId: instanceId,
instance: {
config: instanceAdminClient.instanceConfigPath(
projectId,
'regional-us-central1'
),
nodeCount: 1,
displayName: instanceId,
labels: {
cloud_spanner_samples: 'true',
created: Math.round(Date.now() / 1000).toString(), // current time
},
},
});
const [instance] = await operation.promise();
RESOURCES_TO_CLEAN.push(instance as Instance);
} else {
console.log(
`Not creating temp instance, using + ${instanceAdminClient.instancePath(
projectId,
envInstanceName
)}...`
);
}
const [operation] = await databaseAdminClient.createDatabase({
createStatement: 'CREATE DATABASE `' + DATABASE + '`',
extraStatements: [
`CREATE TABLE ${TABLE_NAME} (
SingerId STRING(1024) NOT NULL,
Name STRING(1024),
) PRIMARY KEY(SingerId)`,
],
parent: databaseAdminClient.instancePath(projectId, instanceId),
});
await operation.promise();
});

describe('Instances', () => {
it('should have created the instance', async () => {
assert(projectId);
try {
const [metadata] = await instanceAdminClient.getInstance({
name: instanceAdminClient.instancePath(projectId, instanceId),
});
assert.strictEqual(
metadata!.name,
instanceAdminClient.instancePath(projectId, instanceId)
);
} catch (err) {
if (!err) {
assert.ifError(err);
}
}
});

it('should list the instances', async () => {
assert(projectId);
const [instances] = await instanceAdminClient.listInstances({
parent: instanceAdminClient.projectPath(projectId),
});
assert(instances!.length > 0);
});
});

describe('Databases', () => {
async function createDatabase(database, dialect) {
assert(projectId);
const [metadata] = await databaseAdminClient.getDatabase({
name: databaseAdminClient.databasePath(
projectId,
instanceId,
database
),
});
assert.strictEqual(
metadata!.name,
databaseAdminClient.databasePath(projectId, instanceId, database)
);
assert.strictEqual(metadata!.state, 'READY');
if (IS_EMULATOR_ENABLED) {
assert.strictEqual(
metadata!.databaseDialect,
'DATABASE_DIALECT_UNSPECIFIED'
);
} else {
assert.strictEqual(metadata!.databaseDialect, dialect);
}
}

it('GOOGLE_STANDARD_SQL should have created the database', async () => {
createDatabase(DATABASE, 'GOOGLE_STANDARD_SQL');
});
});
});

describe('types', () => {
const TABLE_NAME = 'TypeCheck';
const googleSqlTable = DATABASE.table(TABLE_NAME);
Expand Down Expand Up @@ -1322,6 +1431,46 @@ describe('Spanner', () => {
);
});

it('GOOGLE_STANDARD_SQL should query untyped string array values', function (done) {
if (IS_EMULATOR_ENABLED) {
this.skip();
}

const value = ['ghi', 'jkl'];
const table = googleSqlTable;

const query: ExecuteSqlRequest = {
sql:
'SELECT * FROM `' +
table.name +
'` WHERE EXISTS (SELECT 1 FROM UNNEST(StringArray) AS c WHERE c IN UNNEST(@value))',
params: {
value,
},
};

insert(
{StringArray: value},
Spanner.GOOGLE_STANDARD_SQL,
(err, row) => {
assert.ifError(err);
assert.deepStrictEqual(row.toJSON().StringArray, ['ghi', 'jkl']);

DATABASE.run(query, (err, rows) => {
if (err) {
assert.ifError(err);
done();
}
assert.deepStrictEqual(rows!.shift()!.toJSON().StringArray, [
'ghi',
'jkl',
]);
done();
});
}
);
});

it('GOOGLE_STANDARD_SQL should read untyped string values', function (done) {
if (IS_EMULATOR_ENABLED) {
this.skip();
Expand Down
2 changes: 2 additions & 0 deletions test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ const fakePfy = extend({}, pfy, {
'pgJsonb',
'operation',
'timestamp',
'getInstanceAdminClient',
'getDatabaseAdminClient',
]);
},
});
Expand Down
Loading