Skip to content

Commit

Permalink
feat: pre-publish
Browse files Browse the repository at this point in the history
  • Loading branch information
Melchyore committed Mar 25, 2022
1 parent a2f0880 commit 7bb7731
Show file tree
Hide file tree
Showing 23 changed files with 1,292 additions and 669 deletions.
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,23 @@ jobs:
- 17.x
steps:
- uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}

- name: Install
run: npm install

- name: Run tests
run: npm test
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.AWS_REGION }}

- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
9 changes: 9 additions & 0 deletions .nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@istanbuljs/nyc-config-typescript",
"all": true,
"check-coverage": true,
"include": [
"src/**/*.ts",
"providers/**/*.ts"
]
}
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ RUN apk update && apk upgrade && \
WORKDIR /usr/src/app

COPY package*.json ./

RUN npm install
RUN npm install -g coveralls
RUN npm install -g nyc

# Install peer dependencies
RUN npm install @adonisjs/core

RUN mkdir p ./.nyc_output
#RUN mkdir p ./coverage

COPY . .

158 changes: 152 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,166 @@
# Adonis DynamoDB
> A DynamoDB (Dyngoose) wrapper for AdonisJs.
A DynamoDB (Dyngoose) wrapper for AdonisJs.

[![circleci-image]][circleci-url] [![npm-image]][npm-url] [![license-image]][license-url] [![typescript-image]][typescript-url]
[![gh-workflow-image]][gh-workflow-url] [![coverage-image]][coverage-url] [![npm-image]][npm-url] [![license-image]][license-url] [![typescript-image]][typescript-url]

## Dyngoose

### What is it?
Dyngoose is a DynamoDB object modeling for Typescript.

### Why Dyngoose?
Because it looks like Lucid, you will not be lost. The use of decorators makes it even more attractive to use.

### Docs
You can find all Dyngoose docs [here](https://github.com/benhutchins/dyngoose/tree/master/docs).

## Installation
> npm i adonis-dynamodb
First, install the package using npm or yarn

```sh
npm i adonis-dynamodb
# or
yarn add adonis-dynamodb
```

Next, configure the package by running the following command
```sh
node ace configure adonis-dynamodb
```

Then, add the following namespace to `.adonisrc.json` file
```json
"namespaces": {
// ...other namespaces
"dynamodbTables": "App/Tables" // You can use another namespace.
}
```

Finally, add the rules for the env variables inside `env.ts` in your application root:
```ts
export default Env.rules({
// ...other rules
AWS_REGION: Env.schema.string(),
AWS_ACCESS_KEY_ID: Env.schema.string(),
AWS_SECRET_ACCESS_KEY: Env.schema.string(),
})
```
**PS: NEVER share these environment variables.**

## Usage

[circleci-image]: https://img.shields.io/circleci/project/github/Melchyore/adonis-dynamodb/master.svg?style=for-the-badge&logo=circleci
[circleci-url]: https://circleci.com/gh/Melchyore/adonis-dynamodb "circleci"
### Create a new table model
Run the following command to create a table model **(it will only create the model file in App/Tables or the namespace of your choice)**
```sh
node ace dynamo:make Test
```

By default, the primary key name is `id`. You can use a custom name by adding a flag to the above command
```sh
node ace dynamo:make Test --pk=myPrimaryKey
```

Create the table(s) on AWS from the model(s)
```sh
node ace dynamo:create
```

This operation may take time. You can also create only one table from a given model by adding the model's name/path.
```sh
# Using model's name
node ace dynamo:create Test
```

```sh
# Using model's path (the path is resolved using the namespace defined in .adonisrc.json file as root)
node ace dynamo:create Dir/Test
```

### Delete tables from AWS
You can delete one table from AWS using as follows
```sh
# This will delete the table named "Test"
node ace dynamo:drop Test
```

You can also delete all tables **(please be careful when you run this command in production as the drop action is irreversible)**
```sh
# This will delete all the tables
node ace dynamo:drop
```

Everytime you run the `dynamo:drop` command you will be asked if you want to confirm the action.

This command will not delete your models.

### Create a new record or update an existing one
Dyngoose will automatically perform an `UpdateItem` operation if it is possible, to only update the attributes you have changed; but if it is a new record it will perform a `PutItem` operation.

```ts
import Test from 'App/Tables/Test'

const test = await Test.new({
id: 1
title: 'Test'
})
await test.save()

// Or
const test = new Test()
test.id = 1
test.title = 'Test'
await test.save()
```

For more information, please, visit [Dyngoose saving docs](https://github.com/benhutchins/dyngoose/blob/master/docs/Saving.md).

### Get an existing record (querying)
```ts
// Get record by the primary key
const record = await Test.primaryKey.get({ id: 1 })

if (record) {
// You need to call toJSON() on the record to get your data serialized.
console.log(record.toJSON())
}

// Or you can use search() method with filters to get an array of records.
const records = await Test.search({ title: 'Test' }).exec()

records.forEach(record => {
console.log(record.toJSON())
})

// You can also get all records inside a table using scan() method.
const records = await Test.primaryKey.scan()

records.forEach(record => {
console.log(record.toJSON())
})
```

Read more about querying [here](https://github.com/benhutchins/dyngoose/blob/master/docs/Querying.md).

### Delete a record
```ts
// Get record by the primary key
const record = await Test.primaryKey.get({ id: 1 })

if (record) {
await record.delete()
}
```

[gh-workflow-image]: https://img.shields.io/github/workflow/status/Melchyore/adonis-dynamodb/test?style=for-the-badge
[gh-workflow-url]: https://github.com/Melchyore/adonis-dynamodb/actions/workflows/test.yml "Github action"

[coverage-image]: https://img.shields.io/coveralls/github/Melchyore/adonis-dynamodb/master?style=for-the-badge
[coverage-url]: https://coveralls.io/github/Melchyore/adonis-dynamodb "Coverage"

[npm-image]: https://img.shields.io/npm/v/adonis-dynamodb.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/adonis-dynamodb "npm"

[license-image]: https://img.shields.io/npm/l/adonis-dynamodb?color=blueviolet&style=for-the-badge
[license-image]: https://img.shields.io/npm/l/Melchyore/adonis-dynamodb?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md "license"

[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
Expand Down
6 changes: 3 additions & 3 deletions adonis-typings/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ declare module '@ioc:Adonis/Addons/DynamoDB' {

secretAccessKey: string

endpont?: string
endpoint?: string
}

export {
Expand Down Expand Up @@ -67,6 +67,6 @@ declare module '@ioc:Adonis/Addons/DynamoDB' {
}

export type DynamoDBContract = typeof Dyngoose
const DynamoDB: DynamoDBContract
export default DynamoDB

export const DynamoDB: DynamoDBContract
}
2 changes: 1 addition & 1 deletion bin/test/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export async function setup (environment: 'test' | 'web', dynamodbConfig: Dynamo
await fs.add(
'config/dynamodb.ts',
`
const dynamoConfig = ${JSON.stringify(dynamoConfig, null, 2)}
const dynamoConfig = ${JSON.stringify(dynamodbConfig, null, 2)}
export default dynamoConfig
`
)
Expand Down
6 changes: 1 addition & 5 deletions bin/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { expect } from '@japa/expect'
import { assert } from '@japa/assert'
import { specReporter } from '@japa/spec-reporter'
import { runFailedTests } from '@japa/run-failed-tests'
import { processCliArgs, configure, run, TestContext } from '@japa/runner'
import { Filesystem } from '@poppinss/dev-utils'
import { resolve } from 'path'
import { processCliArgs, configure, run } from '@japa/runner'

/*
|--------------------------------------------------------------------------
Expand All @@ -19,7 +16,6 @@ import { resolve } from 'path'
|
| Please consult japa.dev/runner-config for the config docs.
*/
const fs = new Filesystem(resolve(__dirname, '..', 'tmp'))

configure({
...processCliArgs(process.argv.slice(2)),
Expand Down
71 changes: 71 additions & 0 deletions commands/Base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { Table } from '@ioc:Adonis/Addons/DynamoDB'

import { join, extname } from 'path'
import { slash } from '@poppinss/utils'
import { resolveDir, fsReadAll, string } from '@poppinss/utils/build/helpers'
import { BaseCommand } from '@adonisjs/core/build/standalone'

export default abstract class Base extends BaseCommand {
protected async getFile (filePath: string): Promise<Promise<typeof Table>> {
return new Promise(async (resolve, reject) => {
const path = this.absoluteTablesDirectoryPath()

try {
resolve(
(await import(join(path, filePath + extname(filePath)))).default
)
} catch (error) {
reject(error)
}
})
}

protected getFiles (): Promise<Array<Promise<typeof Table>>> {
return new Promise((resolve, reject) => {
const path = this.absoluteTablesDirectoryPath()
const files = fsReadAll(path)

try {
resolve(
files.map(
async (file: string) => (await import(join(path, file))).default
)
)
} catch (error) {
reject(error)
}
})
}

protected async getTable (filePath: string): Promise<typeof Table> {
return await this.getFile(filePath)
}

protected async getTables (): Promise<Array<typeof Table>> {
return await Promise.all(await this.getFiles())
}

protected getTablesDirectory (): string {
return this.application.namespacesMap.get('dynamodbTables') || 'App/Tables'
}

protected absoluteTablesDirectoryPath (): string {
const path = this.resolvedNamespace()

return resolveDir(
this.application.appRoot,
`./${path}`
)
}

protected resolvedNamespace (): string {
return this.application.resolveNamespaceDirectory('dynamodbTables') || 'app/Tables'
}

protected normalizeName (name: string): string {
const path = slash(name).split('/')
const transformedName = string.pascalCase(path.pop()!)

return join(...[...path, transformedName])
}
}
52 changes: 52 additions & 0 deletions commands/Create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Table } from '@ioc:Adonis/Addons/DynamoDB'

import { args } from '@adonisjs/core/build/standalone'

import Base from './Base'

export default class Create extends Base {
public static commandName = 'dynamo:create'

public static description = 'Create DynamoDB tables on AWS from models'

public static settings = {
loadApp: true,
stayAlive: true
}

@args.string({
description: 'Name/path of the model class',
required: false
})
public name?: string

public async run () {
let tables: Array<typeof Table> = []

if (this.name) {
tables = [await this.getTable(this.normalizeName(this.name))]
} else {
tables = await this.getTables()
}

for (const createTable of tables.map(_table => () => this.createTable(_table))) {
await createTable()
}

await this.exit()
}

private async createTable (table: typeof Table): Promise<void> {
const spinner = this.logger.await(`Creating table ${table.name}`, undefined, undefined)

try {
await table.createTable()

this.logger.logUpdate(this.logger.colors.green(`Table ${table.name} successfully created`))
} catch (e) {
this.logger.logUpdate(this.logger.colors.red(`Cannot create table ${table.name}.\n${e}`))
}

spinner.stop()
}
}
Loading

0 comments on commit 7bb7731

Please sign in to comment.