├── .aegir.js
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ └── open_an_issue.md
├── config.yml
├── dependabot.yml
└── workflows
│ ├── automerge.yml
│ ├── js-test-and-release.yml
│ └── stale.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── LICENSE-APACHE
├── LICENSE-MIT
├── README.md
├── package.json
├── src
└── index.ts
├── test
├── browser.ts
├── fixtures
│ └── test-level-iterator-destroy.ts
├── index.spec.ts
└── node.ts
└── tsconfig.json
/.aegir.js:
--------------------------------------------------------------------------------
1 | /** @type {import('aegir').PartialOptions} */
2 | export default {
3 | build: {
4 | bundlesizeMax: '67KB'
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Getting Help on IPFS
4 | url: https://ipfs.io/help
5 | about: All information about how and where to get help on IPFS.
6 | - name: IPFS Official Forum
7 | url: https://discuss.ipfs.io
8 | about: Please post general questions, support requests, and discussions here.
9 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/open_an_issue.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Open an issue
3 | about: Only for actionable issues relevant to this repository.
4 | title: ''
5 | labels: need/triage
6 | assignees: ''
7 |
8 | ---
9 |
20 |
--------------------------------------------------------------------------------
/.github/config.yml:
--------------------------------------------------------------------------------
1 | # Configuration for welcome - https://github.com/behaviorbot/welcome
2 |
3 | # Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome
4 | # Comment to be posted to on first time issues
5 | newIssueWelcomeComment: >
6 | Thank you for submitting your first issue to this repository! A maintainer
7 | will be here shortly to triage and review.
8 |
9 | In the meantime, please double-check that you have provided all the
10 | necessary information to make this process easy! Any information that can
11 | help save additional round trips is useful! We currently aim to give
12 | initial feedback within **two business days**. If this does not happen, feel
13 | free to leave a comment.
14 |
15 | Please keep an eye on how this issue will be labeled, as labels give an
16 | overview of priorities, assignments and additional actions requested by the
17 | maintainers:
18 |
19 | - "Priority" labels will show how urgent this is for the team.
20 | - "Status" labels will show if this is ready to be worked on, blocked, or in progress.
21 | - "Need" labels will indicate if additional input or analysis is required.
22 |
23 | Finally, remember to use https://discuss.ipfs.io if you just need general
24 | support.
25 |
26 | # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome
27 | # Comment to be posted to on PRs from first time contributors in your repository
28 | newPRWelcomeComment: >
29 | Thank you for submitting this PR!
30 |
31 | A maintainer will be here shortly to review it.
32 |
33 | We are super grateful, but we are also overloaded! Help us by making sure
34 | that:
35 |
36 | * The context for this PR is clear, with relevant discussion, decisions
37 | and stakeholders linked/mentioned.
38 |
39 | * Your contribution itself is clear (code comments, self-review for the
40 | rest) and in its best form. Follow the [code contribution
41 | guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md#code-contribution-guidelines)
42 | if they apply.
43 |
44 | Getting other community members to do a review would be great help too on
45 | complex PRs (you can ask in the chats/forums). If you are unsure about
46 | something, just leave us a comment.
47 |
48 | Next steps:
49 |
50 | * A maintainer will triage and assign priority to this PR, commenting on
51 | any missing things and potentially assigning a reviewer for high
52 | priority items.
53 |
54 | * The PR gets reviews, discussed and approvals as needed.
55 |
56 | * The PR is merged by maintainers when it has been approved and comments addressed.
57 |
58 | We currently aim to provide initial feedback/triaging within **two business
59 | days**. Please keep an eye on any labelling actions, as these will indicate
60 | priorities and status of your contribution.
61 |
62 | We are very grateful for your contribution!
63 |
64 |
65 | # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
66 | # Comment to be posted to on pull requests merged by a first time user
67 | # Currently disabled
68 | #firstPRMergeComment: ""
69 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: daily
7 | time: "10:00"
8 | open-pull-requests-limit: 10
9 | commit-message:
10 | prefix: "deps"
11 | prefix-development: "deps(dev)"
12 |
--------------------------------------------------------------------------------
/.github/workflows/automerge.yml:
--------------------------------------------------------------------------------
1 | # File managed by web3-bot. DO NOT EDIT.
2 | # See https://github.com/protocol/.github/ for details.
3 |
4 | name: Automerge
5 | on: [ pull_request ]
6 |
7 | jobs:
8 | automerge:
9 | uses: protocol/.github/.github/workflows/automerge.yml@master
10 | with:
11 | job: 'automerge'
12 |
--------------------------------------------------------------------------------
/.github/workflows/js-test-and-release.yml:
--------------------------------------------------------------------------------
1 | # File managed by web3-bot. DO NOT EDIT.
2 | # See https://github.com/protocol/.github/ for details.
3 |
4 | name: test & maybe release
5 | on:
6 | push:
7 | branches:
8 | - master
9 | pull_request:
10 |
11 | jobs:
12 |
13 | check:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v3
17 | - uses: actions/setup-node@v3
18 | with:
19 | node-version: lts/*
20 | - uses: ipfs/aegir/actions/cache-node-modules@master
21 | - run: npm run --if-present lint
22 | - run: npm run --if-present dep-check
23 |
24 | test-node:
25 | needs: check
26 | runs-on: ${{ matrix.os }}
27 | strategy:
28 | matrix:
29 | os: [windows-latest, ubuntu-latest, macos-latest]
30 | node: [lts/*]
31 | fail-fast: true
32 | steps:
33 | - uses: actions/checkout@v3
34 | - uses: actions/setup-node@v3
35 | with:
36 | node-version: ${{ matrix.node }}
37 | - uses: ipfs/aegir/actions/cache-node-modules@master
38 | - run: npm run --if-present test:node
39 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
40 | with:
41 | flags: node
42 |
43 | test-chrome:
44 | needs: check
45 | runs-on: ubuntu-latest
46 | steps:
47 | - uses: actions/checkout@v3
48 | - uses: actions/setup-node@v3
49 | with:
50 | node-version: lts/*
51 | - uses: ipfs/aegir/actions/cache-node-modules@master
52 | - run: npm run --if-present test:chrome
53 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
54 | with:
55 | flags: chrome
56 |
57 | test-chrome-webworker:
58 | needs: check
59 | runs-on: ubuntu-latest
60 | steps:
61 | - uses: actions/checkout@v3
62 | - uses: actions/setup-node@v3
63 | with:
64 | node-version: lts/*
65 | - uses: ipfs/aegir/actions/cache-node-modules@master
66 | - run: npm run --if-present test:chrome-webworker
67 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
68 | with:
69 | flags: chrome-webworker
70 |
71 | test-firefox:
72 | needs: check
73 | runs-on: ubuntu-latest
74 | steps:
75 | - uses: actions/checkout@v3
76 | - uses: actions/setup-node@v3
77 | with:
78 | node-version: lts/*
79 | - uses: ipfs/aegir/actions/cache-node-modules@master
80 | - run: npm run --if-present test:firefox
81 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
82 | with:
83 | flags: firefox
84 |
85 | test-firefox-webworker:
86 | needs: check
87 | runs-on: ubuntu-latest
88 | steps:
89 | - uses: actions/checkout@v3
90 | - uses: actions/setup-node@v3
91 | with:
92 | node-version: lts/*
93 | - uses: ipfs/aegir/actions/cache-node-modules@master
94 | - run: npm run --if-present test:firefox-webworker
95 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
96 | with:
97 | flags: firefox-webworker
98 |
99 | test-webkit:
100 | needs: check
101 | runs-on: ${{ matrix.os }}
102 | strategy:
103 | matrix:
104 | os: [ubuntu-latest, macos-latest]
105 | node: [lts/*]
106 | fail-fast: true
107 | steps:
108 | - uses: actions/checkout@v3
109 | - uses: actions/setup-node@v3
110 | with:
111 | node-version: lts/*
112 | - uses: ipfs/aegir/actions/cache-node-modules@master
113 | - run: npm run --if-present test:webkit
114 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
115 | with:
116 | flags: webkit
117 |
118 | test-webkit-webworker:
119 | needs: check
120 | runs-on: ${{ matrix.os }}
121 | strategy:
122 | matrix:
123 | os: [ubuntu-latest, macos-latest]
124 | node: [lts/*]
125 | fail-fast: true
126 | steps:
127 | - uses: actions/checkout@v3
128 | - uses: actions/setup-node@v3
129 | with:
130 | node-version: lts/*
131 | - uses: ipfs/aegir/actions/cache-node-modules@master
132 | - run: npm run --if-present test:webkit-webworker
133 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
134 | with:
135 | flags: webkit-webworker
136 |
137 | test-electron-main:
138 | needs: check
139 | runs-on: ubuntu-latest
140 | steps:
141 | - uses: actions/checkout@v3
142 | - uses: actions/setup-node@v3
143 | with:
144 | node-version: lts/*
145 | - uses: ipfs/aegir/actions/cache-node-modules@master
146 | - run: npx xvfb-maybe npm run --if-present test:electron-main
147 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
148 | with:
149 | flags: electron-main
150 |
151 | test-electron-renderer:
152 | needs: check
153 | runs-on: ubuntu-latest
154 | steps:
155 | - uses: actions/checkout@v3
156 | - uses: actions/setup-node@v3
157 | with:
158 | node-version: lts/*
159 | - uses: ipfs/aegir/actions/cache-node-modules@master
160 | - run: npx xvfb-maybe npm run --if-present test:electron-renderer
161 | - uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1
162 | with:
163 | flags: electron-renderer
164 |
165 | release:
166 | needs: [test-node, test-chrome, test-chrome-webworker, test-firefox, test-firefox-webworker, test-webkit, test-webkit-webworker, test-electron-main, test-electron-renderer]
167 | runs-on: ubuntu-latest
168 | if: github.event_name == 'push' && github.ref == 'refs/heads/master'
169 | steps:
170 | - uses: actions/checkout@v3
171 | with:
172 | fetch-depth: 0
173 | - uses: actions/setup-node@v3
174 | with:
175 | node-version: lts/*
176 | - uses: ipfs/aegir/actions/cache-node-modules@master
177 | - uses: ipfs/aegir/actions/docker-login@master
178 | with:
179 | docker-token: ${{ secrets.DOCKER_TOKEN }}
180 | docker-username: ${{ secrets.DOCKER_USERNAME }}
181 | - run: npm run --if-present release
182 | env:
183 | GITHUB_TOKEN: ${{ secrets.UCI_GITHUB_TOKEN || github.token }}
184 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
185 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: Close and mark stale issue
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 |
7 | jobs:
8 | stale:
9 |
10 | runs-on: ubuntu-latest
11 | permissions:
12 | issues: write
13 | pull-requests: write
14 |
15 | steps:
16 | - uses: actions/stale@v3
17 | with:
18 | repo-token: ${{ secrets.GITHUB_TOKEN }}
19 | stale-issue-message: 'Oops, seems like we needed more information for this issue, please comment with more details or this issue will be closed in 7 days.'
20 | close-issue-message: 'This issue was closed because it is missing author input.'
21 | stale-issue-label: 'kind/stale'
22 | any-of-labels: 'need/author-input'
23 | exempt-issue-labels: 'need/triage,need/community-input,need/maintainer-input,need/maintainers-input,need/analysis,status/blocked,status/in-progress,status/ready,status/deferred,status/inactive'
24 | days-before-issue-stale: 6
25 | days-before-issue-close: 7
26 | enable-statistics: true
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | dist
4 | .docs
5 | .coverage
6 | node_modules
7 | package-lock.json
8 | yarn.lock
9 | .vscode
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## [10.0.2](https://github.com/ipfs/js-datastore-level/compare/v10.0.1...v10.0.2) (2023-03-23)
2 |
3 |
4 | ### Dependencies
5 |
6 | * update interface-store to 5.x.x ([#176](https://github.com/ipfs/js-datastore-level/issues/176)) ([2c89f37](https://github.com/ipfs/js-datastore-level/commit/2c89f371a03019d5e811bbd7893abb11fe0ea46f))
7 |
8 | ## [10.0.1](https://github.com/ipfs/js-datastore-level/compare/v10.0.0...v10.0.1) (2023-03-14)
9 |
10 |
11 | ### Bug Fixes
12 |
13 | * update project config ([#173](https://github.com/ipfs/js-datastore-level/issues/173)) ([57a69c7](https://github.com/ipfs/js-datastore-level/commit/57a69c79324cecd5966000e65b4734997c183c17))
14 |
15 | ## [10.0.0](https://github.com/ipfs/js-datastore-level/compare/v9.0.4...v10.0.0) (2023-03-13)
16 |
17 |
18 | ### ⚠ BREAKING CHANGES
19 |
20 | * this module now implements interface-datastore@8.x.x
21 |
22 | ### Dependencies
23 |
24 | * update to interface-datastore 8.x.x ([#172](https://github.com/ipfs/js-datastore-level/issues/172)) ([178d235](https://github.com/ipfs/js-datastore-level/commit/178d235254805f2abdd919e0860bd86af5b48582))
25 |
26 | ## [9.0.4](https://github.com/ipfs/js-datastore-level/compare/v9.0.3...v9.0.4) (2022-11-03)
27 |
28 |
29 | ### Dependencies
30 |
31 | * bump it-map from 1.0.6 to 2.0.0 ([#136](https://github.com/ipfs/js-datastore-level/issues/136)) ([049045a](https://github.com/ipfs/js-datastore-level/commit/049045a4aced05840ec7abce235f3e64c83d42bd))
32 |
33 | ## [9.0.3](https://github.com/ipfs/js-datastore-level/compare/v9.0.2...v9.0.3) (2022-11-03)
34 |
35 |
36 | ### Dependencies
37 |
38 | * bump it-sort from 1.0.1 to 2.0.0 ([#137](https://github.com/ipfs/js-datastore-level/issues/137)) ([4ab7b70](https://github.com/ipfs/js-datastore-level/commit/4ab7b700642ad09548c3580129de9bb53270c33d))
39 |
40 | ## [9.0.2](https://github.com/ipfs/js-datastore-level/compare/v9.0.1...v9.0.2) (2022-11-03)
41 |
42 |
43 | ### Dependencies
44 |
45 | * bump it-filter from 1.0.3 to 2.0.0 ([#138](https://github.com/ipfs/js-datastore-level/issues/138)) ([2b13ed0](https://github.com/ipfs/js-datastore-level/commit/2b13ed04723922093cd2a15fff0a04de15a59f69))
46 | * bump it-take from 1.0.2 to 2.0.0 ([#139](https://github.com/ipfs/js-datastore-level/issues/139)) ([1052cdd](https://github.com/ipfs/js-datastore-level/commit/1052cdd68dbee91d2adfab578b04f741448b22ef))
47 | * **dev:** bump @ipld/dag-cbor from 7.0.3 to 8.0.0 ([#142](https://github.com/ipfs/js-datastore-level/issues/142)) ([1180956](https://github.com/ipfs/js-datastore-level/commit/11809565db0b80ae307f8ce219402600f9ce5745))
48 | * **dev:** bump multiformats from 9.9.0 to 10.0.2 ([#141](https://github.com/ipfs/js-datastore-level/issues/141)) ([8db833b](https://github.com/ipfs/js-datastore-level/commit/8db833bc97122334bb21bd3de6b52018b4c3e816))
49 |
50 | ## [9.0.1](https://github.com/ipfs/js-datastore-level/compare/v9.0.0...v9.0.1) (2022-08-14)
51 |
52 |
53 | ### Bug Fixes
54 |
55 | * restore open options and support old level iterators ([#132](https://github.com/ipfs/js-datastore-level/issues/132)) ([78e4911](https://github.com/ipfs/js-datastore-level/commit/78e4911458371740f2c482c7b1907ec6c15d61d9))
56 |
57 | ## [9.0.0](https://github.com/ipfs/js-datastore-level/compare/v8.0.0...v9.0.0) (2022-08-12)
58 |
59 |
60 | ### ⚠ BREAKING CHANGES
61 |
62 | * this module used to be published as ESM/CJS now it is just ESM
63 |
64 | ### Features
65 |
66 | * publish as ESM only ([#131](https://github.com/ipfs/js-datastore-level/issues/131)) ([0d3b6ab](https://github.com/ipfs/js-datastore-level/commit/0d3b6ab61b23c20587059b01e5446d9638fb569b))
67 |
68 |
69 | ### Trivial Changes
70 |
71 | * Update .github/workflows/stale.yml [skip ci] ([f5b456e](https://github.com/ipfs/js-datastore-level/commit/f5b456e022d2b00edad0d913bbcc517ce0b90218))
72 |
73 | ## [8.0.0](https://github.com/ipfs/js-datastore-level/compare/v7.0.1...v8.0.0) (2022-01-19)
74 |
75 |
76 | ### ⚠ BREAKING CHANGES
77 |
78 | * updates project config to use unified ci
79 |
80 | ### Trivial Changes
81 |
82 | * switch to unified ci ([#99](https://github.com/ipfs/js-datastore-level/issues/99)) ([8344486](https://github.com/ipfs/js-datastore-level/commit/8344486d6971e0b2f49ceaa6dbc63f6469e8ed12))
83 |
84 | ## [7.0.1](https://github.com/ipfs/js-datastore-level/compare/v7.0.0...v7.0.1) (2021-09-09)
85 |
86 |
87 |
88 | # [7.0.0](https://github.com/ipfs/js-datastore-level/compare/v6.0.2...v7.0.0) (2021-09-08)
89 |
90 |
91 | ### chore
92 |
93 | * switch to ESM ([#87](https://github.com/ipfs/js-datastore-level/issues/87)) ([798e995](https://github.com/ipfs/js-datastore-level/commit/798e9958967c2fc279110eebe75e78523560f903))
94 |
95 |
96 | ### BREAKING CHANGES
97 |
98 | * deep imports/requires are no longer possible
99 |
100 |
101 |
102 | ## [6.0.2](https://github.com/ipfs/js-datastore-level/compare/v6.0.1...v6.0.2) (2021-07-30)
103 |
104 |
105 | ### Features
106 |
107 | * add level options ([#82](https://github.com/ipfs/js-datastore-level/issues/82)) ([1a3e060](https://github.com/ipfs/js-datastore-level/commit/1a3e060d12bcebc8b5bdc8123d03b23bbc13de59))
108 |
109 |
110 |
111 | ## [6.0.1](https://github.com/ipfs/js-datastore-level/compare/v6.0.0...v6.0.1) (2021-07-10)
112 |
113 |
114 |
115 | # [6.0.0](https://github.com/ipfs/js-datastore-level/compare/v5.0.1...v6.0.0) (2021-07-06)
116 |
117 |
118 | ### chore
119 |
120 | * update deps ([7e20056](https://github.com/ipfs/js-datastore-level/commit/7e20056b13db55e74c5fde986ec9afe186bba414))
121 |
122 |
123 | ### BREAKING CHANGES
124 |
125 | * uses new interface-datastore interfaces
126 |
127 |
128 |
129 | ## [5.0.1](https://github.com/ipfs/js-datastore-level/compare/v5.0.0...v5.0.1) (2021-04-19)
130 |
131 |
132 |
133 | # [5.0.0](https://github.com/ipfs/js-datastore-level/compare/v4.0.0...v5.0.0) (2021-04-15)
134 |
135 |
136 | ### Features
137 |
138 | * split .query into .query and .queryKeys ([#70](https://github.com/ipfs/js-datastore-level/issues/70)) ([39ba735](https://github.com/ipfs/js-datastore-level/commit/39ba735c591524270740b49bfaa09fa4bcbb11d0))
139 |
140 |
141 |
142 | # [4.0.0](https://github.com/ipfs/js-datastore-level/compare/v3.0.0...v4.0.0) (2021-01-29)
143 |
144 |
145 | ### chore
146 |
147 | * **deps:** bump level from 5.0.1 to 6.0.1 ([#31](https://github.com/ipfs/js-datastore-level/issues/31)) ([06853bd](https://github.com/ipfs/js-datastore-level/commit/06853bd389f1f0c8cd00d12219040a903ed48633))
148 |
149 |
150 | ### BREAKING CHANGES
151 |
152 | * **deps:** requires an upgrade to existing datastores created in the browser with level-js@4 or below
153 |
154 |
155 |
156 | # [3.0.0](https://github.com/ipfs/js-datastore-level/compare/v2.0.0...v3.0.0) (2021-01-22)
157 |
158 |
159 | ### Bug Fixes
160 |
161 | * fix constructor ([#58](https://github.com/ipfs/js-datastore-level/issues/58)) ([621e425](https://github.com/ipfs/js-datastore-level/commit/621e42569d8c31c3d2b7311a8abd2594fa6621bd))
162 |
163 |
164 | ### Features
165 |
166 | * types ([#53](https://github.com/ipfs/js-datastore-level/issues/53)) ([51cd55e](https://github.com/ipfs/js-datastore-level/commit/51cd55e34aa5139dd9dfdb8966df5283e3c5a324))
167 |
168 |
169 |
170 |
171 | # [2.0.0](https://github.com/ipfs/js-datastore-level/compare/v1.1.0...v2.0.0) (2020-07-29)
172 |
173 |
174 | ### Bug Fixes
175 |
176 | * remove node buffers ([#39](https://github.com/ipfs/js-datastore-level/issues/39)) ([19fe886](https://github.com/ipfs/js-datastore-level/commit/19fe886))
177 |
178 |
179 | ### BREAKING CHANGES
180 |
181 | * remove node buffers in favour of Uint8Arrays
182 |
183 |
184 |
185 |
186 | # [1.1.0](https://github.com/ipfs/js-datastore-level/compare/v1.0.0...v1.1.0) (2020-05-07)
187 |
188 |
189 | ### Bug Fixes
190 |
191 | * **ci:** add empty commit to fix lint checks on master ([60d14c0](https://github.com/ipfs/js-datastore-level/commit/60d14c0))
192 |
193 |
194 | ### Features
195 |
196 | * add streaming/cancellable API ([#34](https://github.com/ipfs/js-datastore-level/issues/34)) ([6bfb51a](https://github.com/ipfs/js-datastore-level/commit/6bfb51a))
197 |
198 |
199 |
200 |
201 | # [1.0.0](https://github.com/ipfs/js-datastore-level/compare/v0.14.1...v1.0.0) (2020-04-28)
202 |
203 |
204 |
205 |
206 | ## [0.14.1](https://github.com/ipfs/js-datastore-level/compare/v0.14.0...v0.14.1) (2020-01-14)
207 |
208 |
209 | ### Bug Fixes
210 |
211 | * leveldb iterator memory leak ([#26](https://github.com/ipfs/js-datastore-level/issues/26)) ([e503c1a](https://github.com/ipfs/js-datastore-level/commit/e503c1a)), closes [/github.com/Level/leveldown/blob/d3453fbde4d2a8aa04d9091101c25c999649069b/binding.cc#L545](https://github.com//github.com/Level/leveldown/blob/d3453fbde4d2a8aa04d9091101c25c999649069b/binding.cc/issues/L545)
212 |
213 |
214 | ### Performance Improvements
215 |
216 | * optimize prefix search ([#25](https://github.com/ipfs/js-datastore-level/issues/25)) ([8efa812](https://github.com/ipfs/js-datastore-level/commit/8efa812))
217 |
218 |
219 |
220 |
221 | # [0.14.0](https://github.com/ipfs/js-datastore-level/compare/v0.13.0...v0.14.0) (2019-11-29)
222 |
223 |
224 |
225 |
226 | # [0.13.0](https://github.com/ipfs/js-datastore-level/compare/v0.12.1...v0.13.0) (2019-11-29)
227 |
228 |
229 | ### Bug Fixes
230 |
231 | * init db in overridable method for easier extending ([#21](https://github.com/ipfs/js-datastore-level/issues/21)) ([b21428c](https://github.com/ipfs/js-datastore-level/commit/b21428c))
232 |
233 |
234 |
235 |
236 | ## [0.12.1](https://github.com/ipfs/js-datastore-level/compare/v0.12.0...v0.12.1) (2019-06-26)
237 |
238 |
239 | ### Bug Fixes
240 |
241 | * swap leveldown/level.js for level ([#20](https://github.com/ipfs/js-datastore-level/issues/20)) ([d16e212](https://github.com/ipfs/js-datastore-level/commit/d16e212))
242 |
243 |
244 |
245 |
246 | # [0.12.0](https://github.com/ipfs/js-datastore-level/compare/v0.11.0...v0.12.0) (2019-05-29)
247 |
248 |
249 | ### Bug Fixes
250 |
251 | * remove unused var ([74d4a36](https://github.com/ipfs/js-datastore-level/commit/74d4a36))
252 | * tests ([601599d](https://github.com/ipfs/js-datastore-level/commit/601599d))
253 |
254 |
255 |
256 |
257 | # [0.11.0](https://github.com/ipfs/js-datastore-level/compare/v0.10.0...v0.11.0) (2019-04-29)
258 |
259 |
260 |
261 |
262 | # [0.10.0](https://github.com/ipfs/js-datastore-level/compare/v0.9.0...v0.10.0) (2018-10-24)
263 |
264 |
265 |
266 |
267 | # [0.9.0](https://github.com/ipfs/js-datastore-level/compare/v0.8.0...v0.9.0) (2018-09-19)
268 |
269 |
270 | ### Features
271 |
272 | * add basic error codes ([02a5146](https://github.com/ipfs/js-datastore-level/commit/02a5146))
273 |
274 |
275 |
276 |
277 | # [0.8.0](https://github.com/ipfs/js-datastore-level/compare/v0.7.0...v0.8.0) (2018-05-29)
278 |
279 |
280 | ### Bug Fixes
281 |
282 | * add test and fix constructor ([396f657](https://github.com/ipfs/js-datastore-level/commit/396f657))
283 | * update binary encoding for levelup 2 ([a5d7378](https://github.com/ipfs/js-datastore-level/commit/a5d7378))
284 | * upgrade level libs to resolve node 10 failure ([a427eca](https://github.com/ipfs/js-datastore-level/commit/a427eca))
285 |
286 |
287 |
288 |
289 | # [0.7.0](https://github.com/ipfs/js-datastore-level/compare/v0.6.0...v0.7.0) (2017-11-06)
290 |
291 |
292 | ### Bug Fixes
293 |
294 | * Windows interop ([#4](https://github.com/ipfs/js-datastore-level/issues/4)) ([5d67042](https://github.com/ipfs/js-datastore-level/commit/5d67042))
295 |
296 |
297 |
298 |
299 | # [0.6.0](https://github.com/ipfs/js-datastore-level/compare/v0.5.0...v0.6.0) (2017-07-23)
300 |
301 |
302 |
303 |
304 | # [0.5.0](https://github.com/ipfs/js-datastore-level/compare/v0.4.2...v0.5.0) (2017-07-22)
305 |
306 |
307 |
308 |
309 | ## [0.4.2](https://github.com/ipfs/js-datastore-level/compare/v0.4.0...v0.4.2) (2017-05-24)
310 |
311 |
312 | ### Bug Fixes
313 |
314 | * Object.assign is now evil and no longer is behaving as spec says when Webpacked ([5e40f3b](https://github.com/ipfs/js-datastore-level/commit/5e40f3b))
315 | * Object.assign is now evil and no longer is behaving as spec says when Webpacked ([c3f50ec](https://github.com/ipfs/js-datastore-level/commit/c3f50ec))
316 |
317 |
318 |
319 |
320 | ## [0.4.1](https://github.com/ipfs/js-datastore-level/compare/v0.4.0...v0.4.1) (2017-05-24)
321 |
322 |
323 | ### Bug Fixes
324 |
325 | * Object.assign is now evil and no longer is behaving as spec says when Webpacked ([077bbc1](https://github.com/ipfs/js-datastore-level/commit/077bbc1))
326 |
327 |
328 |
329 |
330 | # [0.4.0](https://github.com/ipfs/js-datastore-level/compare/v0.3.0...v0.4.0) (2017-05-23)
331 |
332 |
333 |
334 |
335 | # [0.3.0](https://github.com/ipfs/js-datastore-level/compare/v0.2.0...v0.3.0) (2017-03-23)
336 |
337 |
338 |
339 |
340 | # [0.2.0](https://github.com/ipfs/js-datastore-level/compare/v0.1.0...v0.2.0) (2017-03-23)
341 |
342 |
343 | ### Features
344 |
345 | * add open method ([fd12c6b](https://github.com/ipfs/js-datastore-level/commit/fd12c6b))
346 |
347 |
348 |
349 |
350 | # 0.1.0 (2017-03-15)
351 |
352 |
353 | ### Bug Fixes
354 |
355 | * key handling ([682f8b3](https://github.com/ipfs/js-datastore-level/commit/682f8b3))
356 | * working interop with go ([f5e03c6](https://github.com/ipfs/js-datastore-level/commit/f5e03c6))
357 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This project is dual licensed under MIT and Apache-2.0.
2 |
3 | MIT: https://www.opensource.org/licenses/mit
4 | Apache-2.0: https://www.apache.org/licenses/license-2.0
5 |
--------------------------------------------------------------------------------
/LICENSE-APACHE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
6 |
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ⛔️ This module is now part of https://github.com/ipfs/js-stores
2 |
3 | # datastore-level
4 |
5 | [](https://ipfs.tech)
6 | [](https://discuss.ipfs.tech)
7 | [](https://codecov.io/gh/ipfs/js-datastore-level)
8 | [](https://github.com/ipfs/js-datastore-level/actions/workflows/js-test-and-release.yml?query=branch%3Amaster)
9 |
10 | > Datastore implementation with level(up|down) backend
11 |
12 | ## Table of contents
13 |
14 | - [Install](#install)
15 | - [Browser `
34 | ```
35 |
36 | ## Usage
37 |
38 | ```js
39 | import { LevelDatastore } from 'datastore-level'
40 |
41 | // Default using level as backend for node or the browser
42 | const store = new LevelDatastore('path/to/store')
43 |
44 | // another leveldown compliant backend like memory-level
45 | const memStore = new LevelDatastore(
46 | new MemoryLevel({
47 | keyEncoding: 'utf8',
48 | valueEncoding: 'view'
49 | })
50 | )
51 | ```
52 |
53 | ### Browser Shimming Leveldown
54 |
55 | `LevelStore` uses the `level` module to automatically use `level` if a modern bundler is used which can detect bundle targets based on the `pkg.browser` property in your `package.json`.
56 |
57 | If you are using a bundler that does not support `pkg.browser`, you will need to handle the shimming yourself, as was the case with versions of `LevelStore` 0.7.0 and earlier.
58 |
59 | ### Database names
60 |
61 | `level-js@3` changed the database prefix from `IDBWrapper-` to `level-js-`, so please specify the old prefix if you wish to continue using databases created using `datastore-level` prior to `v0.12.0`. E.g.
62 |
63 | ```javascript
64 | import leveljs from 'level-js'
65 | import browserStore = new LevelDatastore(
66 | new Level('my/db/name', {
67 | prefix: 'IDBWrapper-'
68 | })
69 | })
70 | ```
71 |
72 | More information: [https://github.com/Level/level-js/blob/master/UPGRADING.md#new-database-prefix](https://github.com/Level/level-js/blob/99831913e905d19e5f6dee56d512b7264fbed7bd/UPGRADING.md#new-database-prefix)
73 |
74 | ## License
75 |
76 | Licensed under either of
77 |
78 | - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / )
79 | - MIT ([LICENSE-MIT](LICENSE-MIT) / )
80 |
81 | ## Contribute
82 |
83 | Contributions welcome! Please check out [the issues](https://github.com/ipfs/js-datastore-level/issues).
84 |
85 | Also see our [contributing document](https://github.com/ipfs/community/blob/master/CONTRIBUTING_JS.md) for more information on how we work, and about contributing in general.
86 |
87 | Please be aware that all interactions related to this repo are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
88 |
89 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
90 |
91 | [](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md)
92 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "datastore-level",
3 | "version": "10.0.2",
4 | "description": "Datastore implementation with level(up|down) backend",
5 | "author": "Friedel Ziegelmayer",
6 | "license": "Apache-2.0 OR MIT",
7 | "homepage": "https://github.com/ipfs/js-datastore-level#readme",
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/ipfs/js-datastore-level.git"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/ipfs/js-datastore-level/issues"
14 | },
15 | "keywords": [
16 | "datastore",
17 | "interface",
18 | "ipfs",
19 | "key-value",
20 | "leveldb",
21 | "leveldown",
22 | "levelup"
23 | ],
24 | "engines": {
25 | "node": ">=16.0.0",
26 | "npm": ">=7.0.0"
27 | },
28 | "type": "module",
29 | "types": "./dist/src/index.d.ts",
30 | "files": [
31 | "src",
32 | "dist",
33 | "!dist/test",
34 | "!**/*.tsbuildinfo"
35 | ],
36 | "exports": {
37 | ".": {
38 | "types": "./dist/src/index.d.ts",
39 | "import": "./dist/src/index.js"
40 | }
41 | },
42 | "eslintConfig": {
43 | "extends": "ipfs",
44 | "parserOptions": {
45 | "sourceType": "module"
46 | }
47 | },
48 | "release": {
49 | "branches": [
50 | "master"
51 | ],
52 | "plugins": [
53 | [
54 | "@semantic-release/commit-analyzer",
55 | {
56 | "preset": "conventionalcommits",
57 | "releaseRules": [
58 | {
59 | "breaking": true,
60 | "release": "major"
61 | },
62 | {
63 | "revert": true,
64 | "release": "patch"
65 | },
66 | {
67 | "type": "feat",
68 | "release": "minor"
69 | },
70 | {
71 | "type": "fix",
72 | "release": "patch"
73 | },
74 | {
75 | "type": "docs",
76 | "release": "patch"
77 | },
78 | {
79 | "type": "test",
80 | "release": "patch"
81 | },
82 | {
83 | "type": "deps",
84 | "release": "patch"
85 | },
86 | {
87 | "scope": "no-release",
88 | "release": false
89 | }
90 | ]
91 | }
92 | ],
93 | [
94 | "@semantic-release/release-notes-generator",
95 | {
96 | "preset": "conventionalcommits",
97 | "presetConfig": {
98 | "types": [
99 | {
100 | "type": "feat",
101 | "section": "Features"
102 | },
103 | {
104 | "type": "fix",
105 | "section": "Bug Fixes"
106 | },
107 | {
108 | "type": "chore",
109 | "section": "Trivial Changes"
110 | },
111 | {
112 | "type": "docs",
113 | "section": "Documentation"
114 | },
115 | {
116 | "type": "deps",
117 | "section": "Dependencies"
118 | },
119 | {
120 | "type": "test",
121 | "section": "Tests"
122 | }
123 | ]
124 | }
125 | }
126 | ],
127 | "@semantic-release/changelog",
128 | "@semantic-release/npm",
129 | "@semantic-release/github",
130 | "@semantic-release/git"
131 | ]
132 | },
133 | "scripts": {
134 | "clean": "aegir clean",
135 | "lint": "aegir lint",
136 | "build": "aegir build",
137 | "release": "aegir release",
138 | "test": "aegir test",
139 | "test:node": "aegir test -t node --cov",
140 | "test:chrome": "aegir test -t browser --cov",
141 | "test:chrome-webworker": "aegir test -t webworker",
142 | "test:firefox": "aegir test -t browser -- --browser firefox",
143 | "test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
144 | "test:electron-main": "aegir test -t electron-main",
145 | "dep-check": "aegir dep-check"
146 | },
147 | "dependencies": {
148 | "datastore-core": "^9.0.4",
149 | "interface-datastore": "^8.1.2",
150 | "it-filter": "^2.0.0",
151 | "it-map": "^2.0.0",
152 | "it-sort": "^2.0.0",
153 | "it-take": "^2.0.0",
154 | "level": "^8.0.0"
155 | },
156 | "devDependencies": {
157 | "aegir": "^38.1.7",
158 | "interface-datastore-tests": "^5.0.0",
159 | "ipfs-utils": "^9.0.4",
160 | "memory-level": "^1.0.0"
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { Batch, Key, KeyQuery, Pair, Query } from 'interface-datastore'
2 | import { BaseDatastore, Errors } from 'datastore-core'
3 | import filter from 'it-filter'
4 | import map from 'it-map'
5 | import take from 'it-take'
6 | import sort from 'it-sort'
7 | import { Level } from 'level'
8 | import type { DatabaseOptions, OpenOptions, IteratorOptions } from 'level'
9 |
10 | interface BatchPut {
11 | type: 'put'
12 | key: string
13 | value: Uint8Array
14 | }
15 |
16 | interface BatchDel {
17 | type: 'del'
18 | key: string
19 | }
20 |
21 | type BatchOp = BatchPut | BatchDel
22 |
23 | /**
24 | * A datastore backed by leveldb
25 | */
26 | export class LevelDatastore extends BaseDatastore {
27 | public db: Level
28 | private readonly opts: OpenOptions
29 |
30 | constructor (path: string | Level, opts: DatabaseOptions & OpenOptions = {}) {
31 | super()
32 |
33 | this.db = typeof path === 'string'
34 | ? new Level(path, {
35 | ...opts,
36 | keyEncoding: 'utf8',
37 | valueEncoding: 'view'
38 | })
39 | : path
40 |
41 | this.opts = {
42 | createIfMissing: true,
43 | compression: false, // same default as go
44 | ...opts
45 | }
46 | }
47 |
48 | async open (): Promise {
49 | try {
50 | await this.db.open(this.opts)
51 | } catch (err: any) {
52 | throw Errors.dbOpenFailedError(err)
53 | }
54 | }
55 |
56 | async put (key: Key, value: Uint8Array): Promise {
57 | try {
58 | await this.db.put(key.toString(), value)
59 |
60 | return key
61 | } catch (err: any) {
62 | throw Errors.dbWriteFailedError(err)
63 | }
64 | }
65 |
66 | async get (key: Key): Promise {
67 | let data
68 | try {
69 | data = await this.db.get(key.toString())
70 | } catch (err: any) {
71 | if (err.notFound != null) {
72 | throw Errors.notFoundError(err)
73 | }
74 |
75 | throw Errors.dbWriteFailedError(err)
76 | }
77 | return data
78 | }
79 |
80 | async has (key: Key): Promise {
81 | try {
82 | await this.db.get(key.toString())
83 | } catch (err: any) {
84 | if (err.notFound != null) {
85 | return false
86 | }
87 |
88 | throw err
89 | }
90 | return true
91 | }
92 |
93 | async delete (key: Key): Promise {
94 | try {
95 | await this.db.del(key.toString())
96 | } catch (err: any) {
97 | throw Errors.dbDeleteFailedError(err)
98 | }
99 | }
100 |
101 | async close (): Promise {
102 | await this.db.close()
103 | }
104 |
105 | batch (): Batch {
106 | const ops: BatchOp[] = []
107 |
108 | return {
109 | put: (key, value) => {
110 | ops.push({
111 | type: 'put',
112 | key: key.toString(),
113 | value
114 | })
115 | },
116 | delete: (key) => {
117 | ops.push({
118 | type: 'del',
119 | key: key.toString()
120 | })
121 | },
122 | commit: async () => {
123 | if (this.db.batch == null) {
124 | throw new Error('Batch operations unsupported by underlying Level')
125 | }
126 |
127 | await this.db.batch(ops)
128 | }
129 | }
130 | }
131 |
132 | query (q: Query): AsyncIterable {
133 | let it = this._query({
134 | values: true,
135 | prefix: q.prefix
136 | })
137 |
138 | if (Array.isArray(q.filters)) {
139 | it = q.filters.reduce((it, f) => filter(it, f), it)
140 | }
141 |
142 | if (Array.isArray(q.orders)) {
143 | it = q.orders.reduce((it, f) => sort(it, f), it)
144 | }
145 |
146 | const { offset, limit } = q
147 | if (offset != null) {
148 | let i = 0
149 | it = filter(it, () => i++ >= offset)
150 | }
151 |
152 | if (limit != null) {
153 | it = take(it, limit)
154 | }
155 |
156 | return it
157 | }
158 |
159 | queryKeys (q: KeyQuery): AsyncIterable {
160 | let it = map(this._query({
161 | values: false,
162 | prefix: q.prefix
163 | }), ({ key }) => key)
164 |
165 | if (Array.isArray(q.filters)) {
166 | it = q.filters.reduce((it, f) => filter(it, f), it)
167 | }
168 |
169 | if (Array.isArray(q.orders)) {
170 | it = q.orders.reduce((it, f) => sort(it, f), it)
171 | }
172 |
173 | const { offset, limit } = q
174 | if (offset != null) {
175 | let i = 0
176 | it = filter(it, () => i++ >= offset)
177 | }
178 |
179 | if (limit != null) {
180 | it = take(it, limit)
181 | }
182 |
183 | return it
184 | }
185 |
186 | _query (opts: { values: boolean, prefix?: string }): AsyncIterable {
187 | const iteratorOpts: IteratorOptions = {
188 | keys: true,
189 | keyEncoding: 'buffer',
190 | values: opts.values
191 | }
192 |
193 | // Let the db do the prefix matching
194 | if (opts.prefix != null) {
195 | const prefix = opts.prefix.toString()
196 | // Match keys greater than or equal to `prefix` and
197 | iteratorOpts.gte = prefix
198 | // less than `prefix` + \xFF (hex escape sequence)
199 | iteratorOpts.lt = prefix + '\xFF'
200 | }
201 |
202 | const iterator = this.db.iterator(iteratorOpts)
203 |
204 | if (iterator[Symbol.asyncIterator] != null) {
205 | return levelIteratorToIterator(iterator)
206 | }
207 |
208 | // @ts-expect-error support older level
209 | if (iterator.next != null && iterator.end != null) {
210 | // @ts-expect-error support older level
211 | return oldLevelIteratorToIterator(iterator)
212 | }
213 |
214 | throw new Error('Level returned incompatible iterator')
215 | }
216 | }
217 |
218 | async function * levelIteratorToIterator (li: AsyncIterable<[string, Uint8Array]> & { close: () => Promise }): AsyncIterable {
219 | for await (const [key, value] of li) {
220 | yield { key: new Key(key, false), value }
221 | }
222 |
223 | await li.close()
224 | }
225 |
226 | interface OldLevelIterator {
227 | next: (cb: (err: Error, key: string | Uint8Array | null, value: any) => void) => void
228 | end: (cb: (err: Error) => void) => void
229 | }
230 |
231 | function oldLevelIteratorToIterator (li: OldLevelIterator): AsyncIterable {
232 | return {
233 | [Symbol.asyncIterator] () {
234 | return {
235 | next: async () => await new Promise((resolve, reject) => {
236 | li.next((err, key, value) => {
237 | if (err != null) {
238 | reject(err); return
239 | }
240 | if (key == null) {
241 | li.end(err => {
242 | if (err != null) {
243 | reject(err)
244 | return
245 | }
246 | resolve({ done: true, value: undefined })
247 | }); return
248 | }
249 | resolve({ done: false, value: { key: new Key(key, false), value } })
250 | })
251 | }),
252 | return: async () => await new Promise((resolve, reject) => {
253 | li.end(err => {
254 | if (err != null) {
255 | reject(err); return
256 | }
257 | resolve({ done: true, value: undefined })
258 | })
259 | })
260 | }
261 | }
262 | }
263 | }
264 |
--------------------------------------------------------------------------------
/test/browser.ts:
--------------------------------------------------------------------------------
1 | /* eslint-env mocha */
2 |
3 | import { MountDatastore } from 'datastore-core'
4 | import { Key } from 'interface-datastore/key'
5 | import { LevelDatastore } from '../src/index.js'
6 | import { interfaceDatastoreTests } from 'interface-datastore-tests'
7 |
8 | describe('LevelDatastore', () => {
9 | describe('interface-datastore (leveljs)', () => {
10 | interfaceDatastoreTests({
11 | setup: () => new LevelDatastore(`hello-${Math.random()}`),
12 | teardown: () => {}
13 | })
14 | })
15 |
16 | describe('interface-datastore (mount(leveljs, leveljs, leveljs))', () => {
17 | interfaceDatastoreTests({
18 | setup () {
19 | return new MountDatastore([{
20 | prefix: new Key('/a'),
21 | datastore: new LevelDatastore(`one-${Math.random()}`)
22 | }, {
23 | prefix: new Key('/q'),
24 | datastore: new LevelDatastore(`two-${Math.random()}`)
25 | }, {
26 | prefix: new Key('/z'),
27 | datastore: new LevelDatastore(`three-${Math.random()}`)
28 | }])
29 | },
30 | teardown () {}
31 | })
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/test/fixtures/test-level-iterator-destroy.ts:
--------------------------------------------------------------------------------
1 | import { Key } from 'interface-datastore/key'
2 | import { LevelDatastore } from '../../src/index.js'
3 | import tempdir from 'ipfs-utils/src/temp-dir.js'
4 |
5 | async function testLevelIteratorDestroy (): Promise {
6 | const store = new LevelDatastore(tempdir())
7 | await store.open()
8 | await store.put(new Key(`/test/key${Date.now()}`), new TextEncoder().encode(`TESTDATA${Date.now()}`))
9 | for await (const d of store.query({})) {
10 | console.log(d) // eslint-disable-line no-console
11 | }
12 | }
13 |
14 | // Will exit with:
15 | // > Assertion failed: (ended_), function ~Iterator, file ../binding.cc, line 546.
16 | // If iterator gets destroyed (in c++ land) and .end() was not called on it.
17 | void testLevelIteratorDestroy()
18 |
--------------------------------------------------------------------------------
/test/index.spec.ts:
--------------------------------------------------------------------------------
1 | /* eslint-env mocha */
2 |
3 | import { expect } from 'aegir/chai'
4 | import { MemoryLevel } from 'memory-level'
5 | import { Level } from 'level'
6 | import { LevelDatastore } from '../src/index.js'
7 | import tempdir from 'ipfs-utils/src/temp-dir.js'
8 | import { interfaceDatastoreTests } from 'interface-datastore-tests'
9 |
10 | describe('LevelDatastore', () => {
11 | describe('initialization', () => {
12 | it('should default to a leveldown database', async () => {
13 | const levelStore = new LevelDatastore(`${tempdir()}/init-default-${Date.now()}`)
14 | await levelStore.open()
15 |
16 | expect(levelStore.db).to.be.an.instanceOf(Level)
17 | })
18 |
19 | it('should be able to override the database', async () => {
20 | const levelStore = new LevelDatastore(
21 | // @ts-expect-error MemoryLevel does not implement the same interface as Level
22 | new MemoryLevel({
23 | keyEncoding: 'utf8',
24 | valueEncoding: 'view'
25 | })
26 | )
27 |
28 | await levelStore.open()
29 |
30 | expect(levelStore.db).to.be.an.instanceOf(MemoryLevel)
31 | })
32 | })
33 |
34 | describe('interface-datastore MemoryLevel', () => {
35 | interfaceDatastoreTests({
36 | async setup () {
37 | const store = new LevelDatastore(
38 | // @ts-expect-error MemoryLevel does not implement the same interface as Level
39 | new MemoryLevel({
40 | keyEncoding: 'utf8',
41 | valueEncoding: 'view'
42 | })
43 | )
44 | await store.open()
45 |
46 | return store
47 | },
48 | teardown () {}
49 | })
50 | })
51 |
52 | describe('interface-datastore Level', () => {
53 | interfaceDatastoreTests({
54 | async setup () {
55 | const store = new LevelDatastore(tempdir())
56 | await store.open()
57 |
58 | return store
59 | },
60 | teardown () {}
61 | })
62 | })
63 | })
64 |
--------------------------------------------------------------------------------
/test/node.ts:
--------------------------------------------------------------------------------
1 | /* eslint-env mocha */
2 |
3 | import { expect } from 'aegir/chai'
4 | import path from 'path'
5 | import { Key } from 'interface-datastore/key'
6 | import { MountDatastore } from 'datastore-core'
7 | import childProcess from 'child_process'
8 | import { interfaceDatastoreTests } from 'interface-datastore-tests'
9 | import { LevelDatastore } from '../src/index.js'
10 | import tempdir from 'ipfs-utils/src/temp-dir.js'
11 |
12 | describe('LevelDatastore', () => {
13 | describe('interface-datastore (leveldown)', () => {
14 | interfaceDatastoreTests({
15 | async setup () {
16 | const store = new LevelDatastore(tempdir())
17 | await store.open()
18 |
19 | return store
20 | },
21 | teardown () {}
22 | })
23 | })
24 |
25 | describe('interface-datastore (mount(leveldown, leveldown, leveldown))', () => {
26 | interfaceDatastoreTests({
27 | async setup () {
28 | return new MountDatastore(
29 | await Promise.all(
30 | ['/a', '/q', '/z'].map(async prefix => {
31 | const datastore = new LevelDatastore(tempdir())
32 | await datastore.open()
33 |
34 | return {
35 | prefix: new Key(prefix),
36 | datastore
37 | }
38 | })
39 | )
40 | )
41 | },
42 | async teardown () {
43 |
44 | }
45 | })
46 | })
47 |
48 | // The `.end()` method MUST be called on LevelDB iterators or they remain open,
49 | // leaking memory.
50 | //
51 | // This test exposes this problem by causing an error to be thrown on process
52 | // exit when an iterator is open AND leveldb is not closed.
53 | //
54 | // Normally when leveldb is closed it'll automatically clean up open iterators
55 | // but if you don't close the store this error will occur:
56 | //
57 | // > Assertion failed: (ended_), function ~Iterator, file ../binding.cc, line 546.
58 | //
59 | // This is thrown by a destructor function for iterator objects that asserts
60 | // the iterator has ended before cleanup.
61 | //
62 | // https://github.com/Level/leveldown/blob/d3453fbde4d2a8aa04d9091101c25c999649069b/binding.cc#L545
63 | it('should not leave iterators open and leak memory', (done) => {
64 | const cp = childProcess.fork(path.join(process.cwd(), '/dist/test/fixtures/test-level-iterator-destroy'), { stdio: 'pipe' })
65 |
66 | let out = ''
67 | const { stdout, stderr } = cp
68 | stdout?.on('data', d => { out = `${out}${d}` })
69 | stderr?.on('data', d => { out = `${out}${d}` })
70 |
71 | cp.on('exit', code => {
72 | expect(code).to.equal(0)
73 | expect(out).to.not.include('Assertion failed: (ended_)')
74 | done()
75 | })
76 | })
77 | })
78 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "aegir/src/config/tsconfig.aegir.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": [
7 | "test",
8 | "src"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------