4.0.4 • Published 2 years ago

fireschema v4.0.4

Weekly downloads
57
License
MIT
Repository
github
Last release
2 years ago

Fireschema

Firestore のスキーマを定義してバリデーションを含むセキュリティルールを自動生成するツール

Requirements

  • TypeScript (>= 4.0)

Install

yarn add fireschema
yarn add -D ts-node
# or
npm i -S fireschema
npm i -D ts-node

Usage

スキーマ定義・セキュリティルール生成

  1. 以下のようにスキーマを定義する (schema として named export する)
  2. npx fireschema <スキーマのパス>

Case

  • /users/{uid}
    • ユーザー (IUser)
  • /users/{uid}/posts/{postId}
    • ユーザーの投稿 (IPostA または IPostB)
  • /users/{uid}/privatePosts/{postId}
    • ユーザーの非公開投稿 (IPostA)
import {
  $adapter,
  $allow,
  $docLabel,
  $functions,
  $or,
  $schema,
  adapter,
  createFireschema,
  dataSchema,
} from 'fireschema'

type IUser = {
  name: string
  displayName: string | null
  age: number
  tags: string[]
  timestamp: FTypes.Timestamp
}

type IPostA = {
  type: 'a'
  text: string
}
type IPostB = {
  type: 'b'
  texts: string[]
}

const UserSchema = dataSchema<IUser>({
  name: 'string',
  displayName: 'string | null',
  age: 'int',
  tags: 'list',
  timestamp: 'timestamp',
})
const UserAdapter = adapter<IUser>()({
  selectors: (q) => ({
    teen: () => q.where('age', '>=', 10).where('age', '<', 20),
  }),
})

const PostASchema = dataSchema<IPostA>({
  type: 'string',
  text: 'string',
})
const PostBSchema = dataSchema<IPostB>({
  type: 'string',
  texts: 'list',
})
const PostAdapter = adapter<IPostA | IPostB>()({})

// const isAdmin = () => `'isAdmin()'`
// const isUserScope = (arg: string) => `isUserScope(${arg})`

export const schema = createFireschema({
  [$functions]: {
    // /admins/<uid> が存在するかどうか
    ['isAdmin()']: `
      return exists(/databases/$(database)/documents/admins/$(request.auth.uid));
    `,

    // アクセスしようとするユーザーの uid が 一致するかどうか
    ['isUserScope(uid)']: `
      return request.auth.uid == uid;
    `,
  },

  /**
   * /users/{uid}
   * schema: UserSchema
   * rule:
   *   [read]: 誰でも可
   *   [write]: uid がユーザーと一致する場合のみ
   */
  users: {
    [$docLabel]: 'uid',
    [$schema]: UserSchema,
    [$adapter]: UserAdapter,
    [$allow]: {
      read: true,
      write: $or(['isUserScope(uid)']),
    },

    /**
     * /users/{uid}/posts/{postId}
     * schema: PostASchema または PostBSchema
     * rule:
     *   [read]: 誰でも可
     *   [write]: uid がユーザーと一致する場合のみ
     */
    posts: {
      [$docLabel]: 'postId',
      [$schema]: [PostASchema, PostBSchema],
      [$adapter]: PostAdapter,
      [$allow]: {
        read: true,
        write: $or(['isUserScope(uid)']),
      },
    },

    /**
     * /users/{uid}/privatePosts/{postId}
     * schema: PostASchema
     * rule:
     *   [read]: uid がユーザーと一致するか admin のみ
     *   [write]: uid がユーザーと一致する場合のみ
     */
    privatePosts: {
      [$docLabel]: 'postId',
      [$schema]: PostASchema,
      [$adapter]: PostAdapter,
      [$allow]: {
        read: $or(['isAdmin()', 'isUserScope(uid)']),
        write: $or(['isUserScope(uid)']),
      },
    },
  },
})

a

import firebase, { firestore, initializeApp } from 'firebase' // or firebase-admin

const app: firebase.app.App = initializeApp({
  // ...
})
const firestoreApp = app.firestore()

const store: FirestoreController<
  typeof firestoreApp,
  typeof schema
> = initFirestore(firestore, firestoreApp, schema)

const users = storeAdmin.collection('root', 'users')
const user = users.ref.doc('user')

const posts = storeAdmin.collection(user, 'posts')
const post = posts.ref.doc('post')

const usersGroup = storeAdmin.collectionGroup(['users'])

user.get().then((snap) => snap.data()) // => IUser
5.0.0

2 years ago

5.0.0-32

2 years ago

5.0.0-31

2 years ago

5.0.0-36

2 years ago

5.0.0-35

2 years ago

5.0.0-34

2 years ago

5.0.0-33

2 years ago

5.0.0-30

2 years ago

5.0.0-29

2 years ago

5.0.0-28

2 years ago

5.0.0-27

2 years ago

5.0.0-26

3 years ago

5.0.0-25

3 years ago

5.0.0-24

3 years ago

5.0.0-23

3 years ago

5.0.0-22

3 years ago

5.0.0-21

3 years ago

5.0.0-20

3 years ago

5.0.0-19

3 years ago

5.0.0-18

3 years ago

5.0.0-17

3 years ago

5.0.0-16

3 years ago

5.0.0-15

3 years ago

5.0.0-14

3 years ago

5.0.0-13

3 years ago

5.0.0-12

3 years ago

5.0.0-11

3 years ago

5.0.0-10

3 years ago

5.0.0-8

3 years ago

5.0.0-9

3 years ago

5.0.0-7

3 years ago

5.0.0-5

3 years ago

5.0.0-6

3 years ago

5.0.0-4

3 years ago

5.0.0-0

3 years ago

5.0.0-1

3 years ago

5.0.0-2

3 years ago

5.0.0-3

3 years ago

4.0.4

3 years ago

4.0.3

3 years ago

4.0.2

3 years ago

4.0.1

3 years ago

4.0.0

3 years ago

4.0.0-8

3 years ago

4.0.0-7

3 years ago

4.0.0-4

3 years ago

4.0.0-5

3 years ago

4.0.0-6

3 years ago

4.0.0-3

3 years ago

4.0.0-1

3 years ago

4.0.0-2

3 years ago

4.0.0-0

3 years ago

3.0.1

3 years ago

3.0.0

3 years ago

2.2.2

3 years ago

2.2.1

3 years ago

2.2.0

3 years ago

2.2.0-4

3 years ago

2.2.0-3

3 years ago

2.2.0-2

3 years ago

2.2.0-0

3 years ago

2.2.0-1

3 years ago

2.1.0

3 years ago

2.1.0-4

3 years ago

2.1.0-3

3 years ago

2.1.0-2

3 years ago

2.1.0-1

3 years ago

2.1.0-0

3 years ago

2.0.0-3

4 years ago

2.0.0-2

4 years ago

2.0.0-1

4 years ago

2.0.0-0

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago

0.10.3

4 years ago

0.10.2

4 years ago

0.10.1

4 years ago

0.9.5

4 years ago

0.10.0

4 years ago

0.9.4

4 years ago

0.9.3

4 years ago

0.9.2

4 years ago

0.9.1

4 years ago

0.9.0

4 years ago

0.9.0-4

4 years ago

0.9.0-3

4 years ago

0.9.0-2

4 years ago

0.9.0-1

4 years ago

0.9.0-0

4 years ago

0.8.1

4 years ago

0.8.2

4 years ago

0.8.0

4 years ago

0.7.0

4 years ago

0.6.0

4 years ago

0.5.0

4 years ago

0.4.1

4 years ago

0.4.2

4 years ago

0.4.0

4 years ago

0.3.1

4 years ago

0.3.0

4 years ago

0.2.5

4 years ago

0.2.3

4 years ago

0.2.2

4 years ago

0.2.4

4 years ago

0.2.1

4 years ago

0.2.0

4 years ago

0.1.0

4 years ago

0.0.1

4 years ago