typescript
The Project
This guide explains how to create a simple command line application that utilizes the Squid Client SDK with a Squid backend. The application will read input from the command line and perform basic database operations based on user input.
Reading command line input
To begin customizing the client, we first need to read input from the command line. Create a readInput()
function, which will have the squid
object we initialized in the previous step as a parameter. We will use the readline module in order to read user input. The readInput()
function will recursively call itself and read input until the user chooses to exit
the program. We will execute the main()
function at the bottom of the file:
import { Squid } from '@squidcloud/client';
import * as readline from 'readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function main() {
const squid = new Squid({
appId: 'YOUR_APP_ID',
region: 'YOUR_REGION', // example: 'us-east-1.aws'
environmentId: 'dev | prod', // choose one of 'dev' or 'prod'
squidDeveloperId: 'YOUR_SQUID_DEVELOPER_ID',
});
readInput(squid);
}
function readInput(squid: Squid) {
rl.question('Usage [exit / insert / read / update / delete]: ', (input) => {
if (input.toLowerCase() === 'exit') {
rl.close();
process.exit(0);
} else if (input.toLowerCase() === 'insert') {
console.log('Insert placeholder');
readInput(squid);
} else {
console.log('Please select a recognized command');
readInput(squid);
}
});
}
main();
Insert
Squid organizes data into collections and documents. Documents are individual records in the database (such as rows in a table), while collections are groups of documents (like tables themselves, but unstructured). To access a Squid collection, use the collection()
method with the collection name as the first parameter.
To create a new document in Typescript, use the insert()
method on a document reference. Document references can be initialized with a document ID, which you can learn more about in our documentation. Create a new insertUser()
function:
import * as crypto from 'crypto';
...
function insertUser(name: string, squid: Squid) {
type User = { id: string; name: string; age: number };
const userId = crypto.randomUUID();
squid
.collection<User>('users') // users collection
.doc(userId) // docId = userId
.insert({
id: userId,
name,
age: Math.ceil(Math.random() * 100),
})
.then(() => console.log("New user created"))
.catch((err) => console.error("Error creating user: ", err));
}
Read
Squid provides a robust and powerful query system. To simply get a reference to the collection of users from Squid, there are multiple different options which suit different use cases, such as subscribing to changes in the collection or accessing it a single time. In our case, we will use the dereference()
method to receive the document data directly. Create a readUsers()
function:
function readUsers(squid: Squid) {
type User = { id: string; name: string; age: number };
squid
.collection<User>('users')
.query()
.dereference()
.snapshot()
.then((user) => {
console.log(user);
});
}
Now that we have the ability to insert into and read the collection, we can begin to test our application. Here is the code example in index.ts
up to this point. Note that we will wrap the body of the readInput()
function in a timeout so that output is printed in the correct order:
import { Squid } from '@squidcloud/client';
import * as readline from 'readline';
import * as crypto from 'crypto';
const rl = ...
function main() {
const squid = ...
readInput(squid);
}
function readInput(squid: Squid) {
setTimeout(() => {
rl.question('Usage [exit / insert / read / update / delete]: ', (input) => {
if (input.toLowerCase() === 'exit') {
rl.close();
process.exit(0);
} else if (input.toLowerCase() === 'insert') {
rl.question('Name: ', (name) => {
insertUser(name, squid);
readInput(squid);
})
} else if (input.toLowerCase() === 'read') {
readUsers(squid);
readInput(squid);
} else {
console.log("Please select a recognized command");
readInput(squid);
}
})
}, 1500)
}
function insertUser(name: string, squid: Squid) {
...
}
function readUsers(squid: Squid) {
...
}
And here is example usage of the app:
Update
To update a document in the collection, we call the update()
method on a DocumentReference
and pass in an object that contains the partial update data as an argument. To do so, we will create an updateUser()
function which will update a user's name and/or age:
function updateUser(squid: Squid, id: string, name?: string, age?: number) {
type User = { id: string; name: string; age: number };
let updateObj;
// updateObj should be partial or complete
if (name && age) {
updateObj = { name, age };
} else if (name) {
updateObj = { name };
} else if (age) {
updateObj = { age };
} else {
console.log('Please update either a name or age');
return;
}
squid
.collection<User>('users')
.doc(id)
.update(updateObj)
.then(() => console.log(`User ${id} updated`))
.catch((err) => console.error(`Error updating user ${id}: `, err));
}
Next, we can update readInput()
to execute the update function. To use the update function, you can copy a user's id after executing the read
command:
function readInput(squid: Squid) {
setTimeout(() => {
rl.question('Usage [exit / insert / read / update / delete]: ', (input) => {
if (input.toLowerCase() === 'exit') {
...
} else if (input.toLowerCase() === 'insert') {
...
} else if (input.toLowerCase() === 'read') {
...
} else if (input.toLowerCase() === 'update') {
rl.question('Id: ', (id) => {
rl.question('Name: ', (name) => {
rl.question('Age: ', (age) => {
updateUser(squid, id, name, parseInt(age));
readInput(squid);
})
})
})
} else {
...
}
})
}, 1500)
}
Delete
To delete a document, you can call the delete()
method on a DocumentReference
. Create a deleteUser()
function, which takes in an id as the second parameter:
function deleteUser(squid: Squid, id: string) {
type User = { id: string; name: string; age: number };
squid
.collection<User>('users')
.doc(id)
.delete()
.then(() => console.log(`User ${id} deleted`))
.catch((err) => console.error(`Error deleting user ${id}: `, err));
}
Next, update readInput()
to execute the delete function:
function readInput(squid: Squid) {
setTimeout(() => {
rl.question('Usage [exit / insert / read / update / delete]: ', (input) => {
if (input.toLowerCase() === 'exit') {
...
} else if (input.toLowerCase() === 'insert') {
...
} else if (input.toLowerCase() === 'read') {
...
} else if (input.toLowerCase() === 'update') {
...
} else if (input.toLowerCase() === 'delete') {
rl.question('Id: ', (id) => {
deleteUser(squid, id);
readInput(squid);
})
} else {
...
}
})
}, 1500)
}
After completing delete, we are now able to use Squid’s built in database service to accomplish all the major functionality that is required in a database. Here is the final index.ts
file:
import { Squid } from '@squidcloud/client';
import * as readline from 'readline';
import * as crypto from 'crypto';
const rl = ...
function main() {
const squid = ...
readInput(squid);
}
function readInput(squid: Squid) {
setTimeout(() => {
rl.question('Usage [exit / insert / read / update / delete]: ', (input) => {
if (input.toLowerCase() === 'exit') {
rl.close();
process.exit(0);
} else if (input.toLowerCase() === 'insert') {
rl.question('Name: ', (name) => {
insertUser(name, squid);
readInput(squid);
})
} else if (input.toLowerCase() === 'read') {
readUsers(squid);
readInput(squid);
} else if (input.toLowerCase() === 'update') {
rl.question('Id: ', (id) => {
rl.question('Name: ', (name) => {
rl.question('Age: ', (age) => {
updateUser(squid, id, name, parseInt(age));
readInput(squid);
})
})
})
} else if (input.toLowerCase() === 'delete') {
rl.question('Id: ', (id) => {
deleteUser(squid, id);
readInput(squid);
})
} else {
console.log("Please select a recognized command");
readInput(squid);
}
})
}, 1500)
}
function insertUser(name: string, squid: Squid) {
...
}
function readUsers(squid: Squid) {
...
}
function updateUser(squid: Squid, id: string, name?: string, age?: number) {
...
}
function deleteUser(squid: Squid, id: string) {
...
}
main();
Next steps
Congratulations on completing the tutorial! To learn about key features of the Squid backend including security functionality, view the Backend SDK documentation. To learn about the functionality of the Squid Client SDK including more complex data queries, managing secrets, and interacting with your storage buckets, view the Client SDK documentation.