diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..1fbf798 --- /dev/null +++ b/.env.example @@ -0,0 +1,2 @@ +MONGO_DATABASE_URL="mongodb://root:example@localhost:27017/example?authSource=admin" +POSTGRESQL_DATABASE_URL="postgresql://root:example@localhost:5438/example?schema=public" diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index 7f90ce9..1070da4 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -22,13 +22,13 @@ jobs: if: steps.yarn-cache.outputs.cache-hit != 'true' run: yarn install - test: - name: Test + test-postgres: + name: Tests with postgres runs-on: ubuntu-latest needs: setup env: NODE_ENV: test - DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/prisma_example_test?schema=public" + POSTGRESQL_DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/prisma_example_test?schema=public" services: postgres: image: postgres:10.8 @@ -59,14 +59,52 @@ jobs: run: yarn install - name: Lint run: yarn lint - - name: Migrate - run: npx prisma migrate dev + - name: Setup prisma for tests + run: yarn test:setup:postgresql - name: Test run: yarn test - + + test-mongo: + name: Tests with mongo + runs-on: ubuntu-latest + needs: setup + env: + NODE_ENV: test + MONGO_DATABASE_URL: "mongodb://root:example@localhost:27017/example?authSource=admin" + services: + mongo: + image: prismagraphql/mongo-single-replica:4.4.3-bionic + env: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: example + MONGO_INITDB_DATABASE: example + ports: + - 27017:27017 + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup + uses: actions/setup-node@v2 + with: + node-version: '14' + - uses: actions/cache@v1 + id: yarn-cache + with: + path: node_modules + key: ${{ runner.os }}-node_modules-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-node_modules- + - name: Install + if: steps.yarn-cache.outputs.cache-hit != 'true' + run: yarn install + - name: Setup prisma for tests + run: yarn test:setup:mongo + - name: Test + run: yarn test + publish: name: Publish - needs: test + needs: [test-mongo, test-postgres] runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.gitignore b/.gitignore index 0e6bf3e..fcb2012 100644 --- a/.gitignore +++ b/.gitignore @@ -160,4 +160,4 @@ types build lib .adminjs -/spec/prisma/migrations +/spec/prisma diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..c02eacf --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,24 @@ +version: '3.8' + +name: adminjs-prisma + +services: + postgres: + image: postgres:latest + restart: always + environment: + POSTGRES_DB: example + POSTGRES_USER: root + POSTGRES_PASSWORD: example + ports: + - '5438:5432' + + mongo: # This image automatically creates a replica set required for transactions + image: prismagraphql/mongo-single-replica:4.4.3-bionic + restart: always + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: example + MONGO_INITDB_DATABASE: example + ports: + - '27017:27017' diff --git a/package.json b/package.json index beb7fc1..0e202a4 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,12 @@ "ts-node": "ts-node", "lint": "eslint './src/**/*.{ts,js}' './spec/**/*.{ts,js}' './example-app/**/*.{ts,js}' --ignore-pattern 'build' --ignore-pattern 'yarn.lock'", "check:all": "yarn lint && yarn test && yarn build", - "release": "semantic-release" + "release": "semantic-release", + "db:setup": "docker-compose up -d", + "db:migrate": "prisma migrate dev --name init", + "prisma:reset": "rm -rf spec/prisma", + "test:setup:mongo": "yarn prisma:reset && cp -r spec/.mongo.prisma spec/prisma && prisma generate", + "test:setup:postgresql": "yarn prisma:reset && cp -r spec/.postgres.prisma spec/prisma && yarn db:migrate && prisma generate" }, "repository": { "type": "git", diff --git a/spec/.mongo.prisma/schema.prisma b/spec/.mongo.prisma/schema.prisma new file mode 100644 index 0000000..aaace63 --- /dev/null +++ b/spec/.mongo.prisma/schema.prisma @@ -0,0 +1,47 @@ +datasource db { + provider = "mongodb" + url = env("MONGO_DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +enum Status { + ACTIVE + REMOVED +} + +model Post { + id String @id @default(uuid()) @map("_id") + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + title String + content String? + someJson Json? @db.Json + status Status @default(ACTIVE) + published Boolean @default(false) + author User @relation(fields: [authorId], references: [id]) + authorId String +} + +model Profile { + id String @id @default(uuid()) @map("_id") + bio String? + user User @relation(fields: [userId], references: [id]) + userId String @unique +} + +model User { + id String @id @default(uuid()) @map("_id") + email String @unique + name String? + posts Post[] + profile Profile? + updatedAt DateTime @default(now()) @updatedAt +} + +model UuidExample { + id String @id @default(uuid()) @map("_id") + label String +} diff --git a/spec/prisma/migrations/20211122063611_uuid_ossp_extension/migration.sql b/spec/.postgres.prisma/migrations/20211122063611_uuid_ossp_extension/migration.sql similarity index 100% rename from spec/prisma/migrations/20211122063611_uuid_ossp_extension/migration.sql rename to spec/.postgres.prisma/migrations/20211122063611_uuid_ossp_extension/migration.sql diff --git a/spec/prisma/schema.prisma b/spec/.postgres.prisma/schema.prisma similarity index 69% rename from spec/prisma/schema.prisma rename to spec/.postgres.prisma/schema.prisma index 8827500..95d7702 100644 --- a/spec/prisma/schema.prisma +++ b/spec/.postgres.prisma/schema.prisma @@ -1,6 +1,6 @@ datasource db { provider = "postgresql" - url = env("DATABASE_URL") + url = env("POSTGRESQL_DATABASE_URL") } generator client { @@ -33,14 +33,15 @@ model Profile { } model User { - id Int @id @default(autoincrement()) - email String @unique - name String? - posts Post[] - profile Profile? + id Int @id @default(autoincrement()) + email String @unique + name String? + posts Post[] + profile Profile? + updatedAt DateTime @default(now()) @updatedAt } model UuidExample { - id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid - label String + id String @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid + label String } diff --git a/spec/Resource.spec.ts b/spec/Resource.spec.ts index ebb1146..a037d45 100644 --- a/spec/Resource.spec.ts +++ b/spec/Resource.spec.ts @@ -8,6 +8,7 @@ describe('Resource', () => { let resource: Resource; let prisma: PrismaClient; let dmmf: DMMFClass; + let provider: string; const data = { name: 'Someone', @@ -17,6 +18,7 @@ describe('Resource', () => { beforeAll(async () => { prisma = new PrismaClient(); dmmf = ((prisma as any)._baseDmmf as DMMFClass); + provider = ((prisma as any)._engineConfig.activeProvider as string); }); beforeEach(async () => { @@ -43,7 +45,7 @@ describe('Resource', () => { describe('#databaseType', () => { it('returns database dialect', () => { - expect(resource.databaseType()).toEqual('postgresql'); + expect(resource.databaseType()).toEqual(provider); }); }); @@ -55,13 +57,13 @@ describe('Resource', () => { describe('#properties', () => { it('returns all the properties', () => { - expect(resource.properties()).toHaveLength(3); + expect(resource.properties()).toHaveLength(4); }); it('returns all properties with the correct position', () => { expect( resource.properties().map((property) => property.position()), - ).toEqual([0, 1, 2]); + ).toEqual([0, 1, 2, 3]); }); }); @@ -95,14 +97,19 @@ describe('Resource', () => { record = await resource.findOne(params.id); const name = 'Michael'; + jest.useFakeTimers().advanceTimersByTime(10000); await resource.update((record && record.id()) as string, { + ...record?.params, name, }); + jest.useRealTimers() + const recordInDb = await resource.findOne( (record && record.id()) as string, ); expect(recordInDb && recordInDb.get('name')).toEqual(name); + expect(record?.get('updatedAt')).not.toEqual(recordInDb?.get('updatedAt')); }); }); @@ -119,7 +126,7 @@ describe('Resource', () => { const filter = new Filter(undefined, resource); filter.filters = { name: { path: 'name', value: params.name, property: resource.property('name') as BaseProperty }, - } + }; record = await resource.find(filter); expect(record[0] && record[0].get('name')).toEqual(data.name); @@ -135,7 +142,7 @@ describe('Resource', () => { const filter = new Filter(undefined, uuidResource); filter.filters = { id: { path: 'id', value: params.id, property: uuidResource.property('id') as BaseProperty }, - } + }; record = await uuidResource.find(filter); expect(record[0] && record[0].get('id')).toEqual(params.id); diff --git a/src/Property.ts b/src/Property.ts index 55a15f8..035d0e5 100644 --- a/src/Property.ts +++ b/src/Property.ts @@ -20,7 +20,7 @@ export class Property extends BaseProperty { } public isEditable(): boolean { - return !this.isId() && this.column.name !== 'createdAt' && this.column.name !== 'updatedAt'; + return !this.isId() && this.column.name !== 'createdAt' && !this.column.isUpdatedAt; } public isId(): boolean { diff --git a/src/Resource.ts b/src/Resource.ts index 3a4b334..b4925a8 100644 --- a/src/Resource.ts +++ b/src/Resource.ts @@ -169,7 +169,7 @@ export class Resource extends BaseResource { const key = property.path(); // eslint-disable-next-line no-continue - if (param === undefined) continue; + if (param === undefined || !property.isEditable()) continue; const type = property.type(); const foreignColumnName = property.foreignColumnName();